1 | /*
|
2 | * Copyright DataStax, Inc.
|
3 | *
|
4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
5 | * you may not use this file except in compliance with the License.
|
6 | * You may obtain a copy of the License at
|
7 | *
|
8 | * http://www.apache.org/licenses/LICENSE-2.0
|
9 | *
|
10 | * Unless required by applicable law or agreed to in writing, software
|
11 | * distributed under the License is distributed on an "AS IS" BASIS,
|
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13 | * See the License for the specific language governing permissions and
|
14 | * limitations under the License.
|
15 | */
|
16 |
|
17 | ;
|
18 |
|
19 | const utils = require('./utils');
|
20 | const types = require('./types');
|
21 | const errors = require('./errors');
|
22 |
|
23 | const proxyExecuteKey = 'ProxyExecute';
|
24 |
|
25 | /**
|
26 | * A base class that represents a wrapper around the user provided query options with getter methods and proper
|
27 | * default values.
|
28 | * <p>
|
29 | * Note that getter methods might return <code>undefined</code> when not set on the query options or default
|
30 | * {@link Client} options.
|
31 | * </p>
|
32 | */
|
33 | class ExecutionOptions {
|
34 |
|
35 | /**
|
36 | * Creates a new instance of {@link ExecutionOptions}.
|
37 | */
|
38 | constructor() {
|
39 | }
|
40 |
|
41 | /**
|
42 | * Creates an empty instance, where all methods return undefined, used internally.
|
43 | * @ignore
|
44 | * @return {ExecutionOptions}
|
45 | */
|
46 | static empty() {
|
47 | return new ExecutionOptions();
|
48 | }
|
49 |
|
50 | /**
|
51 | * Determines if the stack trace before the query execution should be maintained.
|
52 | * @abstract
|
53 | * @returns {Boolean}
|
54 | */
|
55 | getCaptureStackTrace() {
|
56 |
|
57 | }
|
58 |
|
59 | /**
|
60 | * Gets the [Consistency level]{@link module:types~consistencies} to be used for the execution.
|
61 | * @abstract
|
62 | * @returns {Number}
|
63 | */
|
64 | getConsistency() {
|
65 |
|
66 | }
|
67 |
|
68 | /**
|
69 | * Key-value payload to be passed to the server. On the server side, implementations of QueryHandler can use
|
70 | * this data.
|
71 | * @abstract
|
72 | * @returns {Object}
|
73 | */
|
74 | getCustomPayload() {
|
75 |
|
76 | }
|
77 |
|
78 | /**
|
79 | * Gets the amount of rows to retrieve per page.
|
80 | * @abstract
|
81 | * @returns {Number}
|
82 | */
|
83 | getFetchSize() {
|
84 |
|
85 | }
|
86 |
|
87 | /**
|
88 | * When a fixed host is set on the query options and the query plan for the load-balancing policy is not used, it
|
89 | * gets the host that should handle the query.
|
90 | * @returns {Host}
|
91 | */
|
92 | getFixedHost() {
|
93 |
|
94 | }
|
95 |
|
96 | /**
|
97 | * Gets the type hints for parameters given in the query, ordered as for the parameters.
|
98 | * @abstract
|
99 | * @returns {Array|Array<Array>}
|
100 | */
|
101 | getHints() {
|
102 |
|
103 | }
|
104 |
|
105 | /**
|
106 | * Determines whether the driver must retrieve the following result pages automatically.
|
107 | * <p>
|
108 | * This setting is only considered by the [Client#eachRow()]{@link Client#eachRow} method.
|
109 | * </p>
|
110 | * @abstract
|
111 | * @returns {Boolean}
|
112 | */
|
113 | isAutoPage() {
|
114 |
|
115 | }
|
116 |
|
117 | /**
|
118 | * Determines whether its a counter batch. Only valid for [Client#batch()]{@link Client#batch}, it will be ignored by
|
119 | * other methods.
|
120 | * @abstract
|
121 | * @returns {Boolean} A <code>Boolean</code> value, it can't be <code>undefined</code>.
|
122 | */
|
123 | isBatchCounter() {
|
124 |
|
125 | }
|
126 |
|
127 | /**
|
128 | * Determines whether the batch should be written to the batchlog. Only valid for
|
129 | * [Client#batch()]{@link Client#batch}, it will be ignored by other methods.
|
130 | * @abstract
|
131 | * @returns {Boolean} A <code>Boolean</code> value, it can't be <code>undefined</code>.
|
132 | */
|
133 | isBatchLogged() {
|
134 |
|
135 | }
|
136 |
|
137 | /**
|
138 | * Determines whether the query can be applied multiple times without changing the result beyond the initial
|
139 | * application.
|
140 | * @abstract
|
141 | * @returns {Boolean}
|
142 | */
|
143 | isIdempotent() {
|
144 |
|
145 | }
|
146 |
|
147 | /**
|
148 | * Determines whether the query must be prepared beforehand.
|
149 | * @abstract
|
150 | * @returns {Boolean} A <code>Boolean</code> value, it can't be <code>undefined</code>.
|
151 | */
|
152 | isPrepared() {
|
153 |
|
154 | }
|
155 |
|
156 | /**
|
157 | * Determines whether query tracing is enabled for the execution.
|
158 | * @abstract
|
159 | * @returns {Boolean}
|
160 | */
|
161 | isQueryTracing() {
|
162 |
|
163 | }
|
164 |
|
165 | /**
|
166 | * Gets the keyspace for the query when set at query options level.
|
167 | * <p>
|
168 | * Note that this method will return <code>undefined</code> when the keyspace is not set at query options level.
|
169 | * It will only return the keyspace name when the user provided a different keyspace than the current
|
170 | * {@link Client} keyspace.
|
171 | * </p>
|
172 | * @abstract
|
173 | * @returns {String}
|
174 | */
|
175 | getKeyspace() {
|
176 |
|
177 | }
|
178 |
|
179 | /**
|
180 | * Gets the load balancing policy used for this execution.
|
181 | * @returns {LoadBalancingPolicy} A <code>LoadBalancingPolicy</code> instance, it can't be <code>undefined</code>.
|
182 | */
|
183 | getLoadBalancingPolicy() {
|
184 |
|
185 | }
|
186 |
|
187 | /**
|
188 | * Gets the Buffer representing the paging state.
|
189 | * @abstract
|
190 | * @returns {Buffer}
|
191 | */
|
192 | getPageState() {
|
193 |
|
194 | }
|
195 |
|
196 | /**
|
197 | * Internal method that gets the preferred host.
|
198 | * @abstract
|
199 | * @ignore
|
200 | */
|
201 | getPreferredHost() {
|
202 |
|
203 | }
|
204 |
|
205 | /**
|
206 | * Gets the query options as provided to the execution method without setting the default values.
|
207 | * @returns {QueryOptions}
|
208 | */
|
209 | getRawQueryOptions() {
|
210 |
|
211 | }
|
212 |
|
213 | /**
|
214 | * Gets the timeout in milliseconds to be used for the execution per coordinator.
|
215 | * <p>
|
216 | * A value of <code>0</code> disables client side read timeout for the execution. Default: <code>undefined</code>.
|
217 | * </p>
|
218 | * @abstract
|
219 | * @returns {Number}
|
220 | */
|
221 | getReadTimeout() {
|
222 |
|
223 | }
|
224 |
|
225 | /**
|
226 | * Gets the [retry policy]{@link module:policies/retry} to be used.
|
227 | * @abstract
|
228 | * @returns {RetryPolicy} A <code>RetryPolicy</code> instance, it can't be <code>undefined</code>.
|
229 | */
|
230 | getRetryPolicy() {
|
231 |
|
232 | }
|
233 |
|
234 | /**
|
235 | * Internal method to obtain the row callback, for "by row" results.
|
236 | * @abstract
|
237 | * @ignore
|
238 | */
|
239 | getRowCallback() {
|
240 |
|
241 | }
|
242 |
|
243 | /**
|
244 | * Internal method to get or generate a timestamp for the request execution.
|
245 | * @ignore
|
246 | * @returns {Long|null}
|
247 | */
|
248 | getOrGenerateTimestamp() {
|
249 |
|
250 | }
|
251 |
|
252 | /**
|
253 | * Gets the index of the parameters that are part of the partition key to determine the routing.
|
254 | * @abstract
|
255 | * @ignore
|
256 | * @returns {Array}
|
257 | */
|
258 | getRoutingIndexes() {
|
259 |
|
260 | }
|
261 |
|
262 | /**
|
263 | * Gets the partition key(s) to determine which coordinator should be used for the query.
|
264 | * @abstract
|
265 | * @returns {Buffer|Array<Buffer>}
|
266 | */
|
267 | getRoutingKey() {
|
268 |
|
269 | }
|
270 |
|
271 | /**
|
272 | * Gets the array of the parameters names that are part of the partition key to determine the
|
273 | * routing. Only valid for non-prepared requests.
|
274 | * @abstract
|
275 | * @ignore
|
276 | */
|
277 | getRoutingNames() {
|
278 |
|
279 | }
|
280 |
|
281 | /**
|
282 | * Gets the the consistency level to be used for the serial phase of conditional updates.
|
283 | * @abstract
|
284 | * @returns {Number}
|
285 | */
|
286 | getSerialConsistency() {
|
287 |
|
288 | }
|
289 |
|
290 | /**
|
291 | * Gets the provided timestamp for the execution in microseconds from the unix epoch (00:00:00, January 1st, 1970).
|
292 | * <p>When a timestamp generator is used, this method returns <code>undefined</code>.</p>
|
293 | * @abstract
|
294 | * @returns {Number|Long|undefined|null}
|
295 | */
|
296 | getTimestamp() {
|
297 |
|
298 | }
|
299 |
|
300 | /**
|
301 | * @param {Array} hints
|
302 | * @abstract
|
303 | * @ignore
|
304 | */
|
305 | setHints(hints) {
|
306 |
|
307 | }
|
308 |
|
309 | /**
|
310 | * Sets the keyspace for the execution.
|
311 | * @ignore
|
312 | * @abstract
|
313 | * @param {String} keyspace
|
314 | */
|
315 | setKeyspace(keyspace) {
|
316 |
|
317 | }
|
318 |
|
319 | /**
|
320 | * @abstract
|
321 | * @ignore
|
322 | */
|
323 | setPageState() {
|
324 |
|
325 | }
|
326 |
|
327 | /**
|
328 | * Internal method that sets the preferred host.
|
329 | * @abstract
|
330 | * @ignore
|
331 | */
|
332 | setPreferredHost() {
|
333 |
|
334 | }
|
335 |
|
336 | /**
|
337 | * Sets the index of the parameters that are part of the partition key to determine the routing.
|
338 | * @param {Array} routingIndexes
|
339 | * @abstract
|
340 | * @ignore
|
341 | */
|
342 | setRoutingIndexes(routingIndexes) {
|
343 |
|
344 | }
|
345 |
|
346 | /**
|
347 | * Sets the routing key.
|
348 | * @abstract
|
349 | * @ignore
|
350 | */
|
351 | setRoutingKey(value) {
|
352 |
|
353 | }
|
354 | }
|
355 |
|
356 | /**
|
357 | * Internal implementation of {@link ExecutionOptions} that uses the value from the client options and execution
|
358 | * profile into account.
|
359 | * @ignore
|
360 | */
|
361 | class DefaultExecutionOptions extends ExecutionOptions {
|
362 | /**
|
363 | * Creates a new instance of {@link ExecutionOptions}.
|
364 | * @param {QueryOptions} queryOptions
|
365 | * @param {Client} client
|
366 | * @param {Function|null} rowCallback
|
367 | */
|
368 | constructor(queryOptions, client, rowCallback) {
|
369 | super();
|
370 |
|
371 | this._queryOptions = queryOptions;
|
372 | this._rowCallback = rowCallback;
|
373 | this._routingKey = this._queryOptions.routingKey;
|
374 | this._hints = this._queryOptions.hints;
|
375 | this._keyspace = this._queryOptions.keyspace;
|
376 | this._routingIndexes = this._queryOptions.routingIndexes;
|
377 | this._pageState = typeof this._queryOptions.pageState === 'string' ?
|
378 | utils.allocBufferFromString(this._queryOptions.pageState, 'hex') : this._queryOptions.pageState;
|
379 | this._preferredHost = null;
|
380 |
|
381 | this._client = client;
|
382 | this._defaultQueryOptions = client.options.queryOptions;
|
383 | this._profile = client.profileManager.getProfile(this._queryOptions.executionProfile);
|
384 |
|
385 | // Build a custom payload object designed for DSE-specific functionality
|
386 | this._customPayload = DefaultExecutionOptions.createCustomPayload(this._queryOptions, this._defaultQueryOptions);
|
387 |
|
388 | if (!this._profile) {
|
389 | throw new errors.ArgumentError(`Execution profile "${this._queryOptions.executionProfile}" not found`);
|
390 | }
|
391 | }
|
392 |
|
393 | /**
|
394 | * Creates a payload for given user.
|
395 | * @param {QueryOptions} userOptions
|
396 | * @param {QueryOptions} defaultQueryOptions
|
397 | * @private
|
398 | */
|
399 | static createCustomPayload(userOptions, defaultQueryOptions) {
|
400 | let customPayload = userOptions.customPayload || defaultQueryOptions.customPayload;
|
401 | const executeAs = userOptions.executeAs || defaultQueryOptions.executeAs;
|
402 |
|
403 | if (executeAs) {
|
404 | if (!customPayload) {
|
405 | customPayload = {};
|
406 | customPayload[proxyExecuteKey] = utils.allocBufferFromString(executeAs);
|
407 | } else if (!customPayload[proxyExecuteKey]) {
|
408 | // Avoid appending to the existing payload object
|
409 | customPayload = utils.extend({}, customPayload);
|
410 | customPayload[proxyExecuteKey] = utils.allocBufferFromString(executeAs);
|
411 | }
|
412 | }
|
413 |
|
414 | return customPayload;
|
415 | }
|
416 |
|
417 | /**
|
418 | * Creates a new instance {@link ExecutionOptions}, based on the query options.
|
419 | * @param {QueryOptions|null} queryOptions
|
420 | * @param {Client} client
|
421 | * @param {Function|null} [rowCallback]
|
422 | * @ignore
|
423 | * @return {ExecutionOptions}
|
424 | */
|
425 | static create(queryOptions, client, rowCallback) {
|
426 | if (!queryOptions || typeof queryOptions === 'function') {
|
427 | // queryOptions can be null/undefined and could be of type function when is an optional parameter
|
428 | queryOptions = utils.emptyObject;
|
429 | }
|
430 | return new DefaultExecutionOptions(queryOptions, client, rowCallback);
|
431 | }
|
432 |
|
433 | getCaptureStackTrace() {
|
434 | return ifUndefined(this._queryOptions.captureStackTrace, this._defaultQueryOptions.captureStackTrace);
|
435 | }
|
436 |
|
437 | getConsistency() {
|
438 | return ifUndefined3(this._queryOptions.consistency, this._profile.consistency,
|
439 | this._defaultQueryOptions.consistency);
|
440 | }
|
441 |
|
442 | getCustomPayload() {
|
443 | return this._customPayload;
|
444 | }
|
445 |
|
446 | getFetchSize() {
|
447 | return ifUndefined(this._queryOptions.fetchSize, this._defaultQueryOptions.fetchSize);
|
448 | }
|
449 |
|
450 | getFixedHost() {
|
451 | return this._queryOptions.host;
|
452 | }
|
453 |
|
454 | getHints() {
|
455 | return this._hints;
|
456 | }
|
457 |
|
458 | isAutoPage() {
|
459 | return ifUndefined(this._queryOptions.autoPage, this._defaultQueryOptions.autoPage);
|
460 | }
|
461 |
|
462 | isBatchCounter() {
|
463 | return ifUndefined(this._queryOptions.counter, false);
|
464 | }
|
465 |
|
466 | isBatchLogged() {
|
467 | return ifUndefined3(this._queryOptions.logged, this._defaultQueryOptions.logged, true);
|
468 | }
|
469 |
|
470 | isIdempotent() {
|
471 | return ifUndefined(this._queryOptions.isIdempotent, this._defaultQueryOptions.isIdempotent);
|
472 | }
|
473 |
|
474 | /**
|
475 | * Determines if the query execution must be prepared beforehand.
|
476 | * @return {Boolean}
|
477 | */
|
478 | isPrepared() {
|
479 | return ifUndefined(this._queryOptions.prepare, this._defaultQueryOptions.prepare);
|
480 | }
|
481 |
|
482 | isQueryTracing() {
|
483 | return ifUndefined(this._queryOptions.traceQuery, this._defaultQueryOptions.traceQuery);
|
484 | }
|
485 |
|
486 | getKeyspace() {
|
487 | return this._keyspace;
|
488 | }
|
489 |
|
490 | getLoadBalancingPolicy() {
|
491 | return this._profile.loadBalancing;
|
492 | }
|
493 |
|
494 | getOrGenerateTimestamp() {
|
495 | let result = this.getTimestamp();
|
496 |
|
497 | if (result === undefined) {
|
498 | const generator = this._client.options.policies.timestampGeneration;
|
499 |
|
500 | if ( types.protocolVersion.supportsTimestamp(this._client.controlConnection.protocolVersion) && generator) {
|
501 | result = generator.next(this._client);
|
502 | } else {
|
503 | result = null;
|
504 | }
|
505 | }
|
506 |
|
507 | return typeof result === 'number' ? types.Long.fromNumber(result) : result;
|
508 | }
|
509 |
|
510 | getPageState() {
|
511 | return this._pageState;
|
512 | }
|
513 |
|
514 | /**
|
515 | * Gets the profile defined by the user or the default profile
|
516 | * @internal
|
517 | * @ignore
|
518 | */
|
519 | getProfile() {
|
520 | return this._profile;
|
521 | }
|
522 |
|
523 | getRawQueryOptions() {
|
524 | return this._queryOptions;
|
525 | }
|
526 |
|
527 | getReadTimeout() {
|
528 | return ifUndefined3(this._queryOptions.readTimeout, this._profile.readTimeout,
|
529 | this._client.options.socketOptions.readTimeout);
|
530 | }
|
531 |
|
532 | getRetryPolicy() {
|
533 | return ifUndefined3(this._queryOptions.retry, this._profile.retry, this._client.options.policies.retry);
|
534 | }
|
535 |
|
536 | getRoutingIndexes() {
|
537 | return this._routingIndexes;
|
538 | }
|
539 |
|
540 | getRoutingKey() {
|
541 | return this._routingKey;
|
542 | }
|
543 |
|
544 | getRoutingNames() {
|
545 | return this._queryOptions.routingNames;
|
546 | }
|
547 |
|
548 | /**
|
549 | * Internal method to obtain the row callback, for "by row" results.
|
550 | * @ignore
|
551 | */
|
552 | getRowCallback() {
|
553 | return this._rowCallback;
|
554 | }
|
555 |
|
556 | getSerialConsistency() {
|
557 | return ifUndefined3(
|
558 | this._queryOptions.serialConsistency, this._profile.serialConsistency, this._defaultQueryOptions.serialConsistency);
|
559 | }
|
560 |
|
561 | getTimestamp() {
|
562 | return this._queryOptions.timestamp;
|
563 | }
|
564 |
|
565 | /**
|
566 | * Internal property to set the custom payload.
|
567 | * @ignore
|
568 | * @internal
|
569 | * @param {Object} payload
|
570 | */
|
571 | setCustomPayload(payload) {
|
572 | this._customPayload = payload;
|
573 | }
|
574 |
|
575 | /**
|
576 | * @param {Array} hints
|
577 | */
|
578 | setHints(hints) {
|
579 | this._hints = hints;
|
580 | }
|
581 |
|
582 | /**
|
583 | * @param {String} keyspace
|
584 | */
|
585 | setKeyspace(keyspace) {
|
586 | this._keyspace = keyspace;
|
587 | }
|
588 |
|
589 | /**
|
590 | * @param {Buffer} pageState
|
591 | */
|
592 | setPageState(pageState) {
|
593 | this._pageState = pageState;
|
594 | }
|
595 |
|
596 | /**
|
597 | * @param {Array} routingIndexes
|
598 | */
|
599 | setRoutingIndexes(routingIndexes) {
|
600 | this._routingIndexes = routingIndexes;
|
601 | }
|
602 |
|
603 | setRoutingKey(value) {
|
604 | this._routingKey = value;
|
605 | }
|
606 | }
|
607 |
|
608 | function ifUndefined(v1, v2) {
|
609 | return v1 !== undefined ? v1 : v2;
|
610 | }
|
611 |
|
612 | function ifUndefined3(v1, v2, v3) {
|
613 | if (v1 !== undefined) {
|
614 | return v1;
|
615 | }
|
616 | return v2 !== undefined ? v2 : v3;
|
617 | }
|
618 |
|
619 | module.exports = { ExecutionOptions, DefaultExecutionOptions, proxyExecuteKey }; |
\ | No newline at end of file |