| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| 'use strict'; |
| |
| const utils = require('./utils'); |
| const types = require('./types'); |
| const errors = require('./errors'); |
| |
| const proxyExecuteKey = 'ProxyExecute'; |
| |
| /** |
| * A base class that represents a wrapper around the user provided query options with getter methods and proper |
| * default values. |
| * <p> |
| * Note that getter methods might return <code>undefined</code> when not set on the query options or default |
| * {@link Client} options. |
| * </p> |
| */ |
| class ExecutionOptions { |
| |
| /** |
| * Creates a new instance of {@link ExecutionOptions}. |
| */ |
| constructor() { |
| } |
| |
| /** |
| * Creates an empty instance, where all methods return undefined, used internally. |
| * @ignore |
| * @return {ExecutionOptions} |
| */ |
| static empty() { |
| return new ExecutionOptions(); |
| } |
| |
| /** |
| * Determines if the stack trace before the query execution should be maintained. |
| * @abstract |
| * @returns {Boolean} |
| */ |
| getCaptureStackTrace() { |
| |
| } |
| |
| /** |
| * Gets the [Consistency level]{@link module:types~consistencies} to be used for the execution. |
| * @abstract |
| * @returns {Number} |
| */ |
| getConsistency() { |
| |
| } |
| |
| /** |
| * Key-value payload to be passed to the server. On the server side, implementations of QueryHandler can use |
| * this data. |
| * @abstract |
| * @returns {Object} |
| */ |
| getCustomPayload() { |
| |
| } |
| |
| /** |
| * Gets the amount of rows to retrieve per page. |
| * @abstract |
| * @returns {Number} |
| */ |
| getFetchSize() { |
| |
| } |
| |
| /** |
| * When a fixed host is set on the query options and the query plan for the load-balancing policy is not used, it |
| * gets the host that should handle the query. |
| * @returns {Host} |
| */ |
| getFixedHost() { |
| |
| } |
| |
| /** |
| * Gets the type hints for parameters given in the query, ordered as for the parameters. |
| * @abstract |
| * @returns {Array|Array<Array>} |
| */ |
| getHints() { |
| |
| } |
| |
| /** |
| * Determines whether the driver must retrieve the following result pages automatically. |
| * <p> |
| * This setting is only considered by the [Client#eachRow()]{@link Client#eachRow} method. |
| * </p> |
| * @abstract |
| * @returns {Boolean} |
| */ |
| isAutoPage() { |
| |
| } |
| |
| /** |
| * Determines whether its a counter batch. Only valid for [Client#batch()]{@link Client#batch}, it will be ignored by |
| * other methods. |
| * @abstract |
| * @returns {Boolean} A <code>Boolean</code> value, it can't be <code>undefined</code>. |
| */ |
| isBatchCounter() { |
| |
| } |
| |
| /** |
| * Determines whether the batch should be written to the batchlog. Only valid for |
| * [Client#batch()]{@link Client#batch}, it will be ignored by other methods. |
| * @abstract |
| * @returns {Boolean} A <code>Boolean</code> value, it can't be <code>undefined</code>. |
| */ |
| isBatchLogged() { |
| |
| } |
| |
| /** |
| * Determines whether the query can be applied multiple times without changing the result beyond the initial |
| * application. |
| * @abstract |
| * @returns {Boolean} |
| */ |
| isIdempotent() { |
| |
| } |
| |
| /** |
| * Determines whether the query must be prepared beforehand. |
| * @abstract |
| * @returns {Boolean} A <code>Boolean</code> value, it can't be <code>undefined</code>. |
| */ |
| isPrepared() { |
| |
| } |
| |
| /** |
| * Determines whether query tracing is enabled for the execution. |
| * @abstract |
| * @returns {Boolean} |
| */ |
| isQueryTracing() { |
| |
| } |
| |
| /** |
| * Gets the keyspace for the query when set at query options level. |
| * <p> |
| * Note that this method will return <code>undefined</code> when the keyspace is not set at query options level. |
| * It will only return the keyspace name when the user provided a different keyspace than the current |
| * {@link Client} keyspace. |
| * </p> |
| * @abstract |
| * @returns {String} |
| */ |
| getKeyspace() { |
| |
| } |
| |
| /** |
| * Gets the load balancing policy used for this execution. |
| * @returns {LoadBalancingPolicy} A <code>LoadBalancingPolicy</code> instance, it can't be <code>undefined</code>. |
| */ |
| getLoadBalancingPolicy() { |
| |
| } |
| |
| /** |
| * Gets the Buffer representing the paging state. |
| * @abstract |
| * @returns {Buffer} |
| */ |
| getPageState() { |
| |
| } |
| |
| /** |
| * Internal method that gets the preferred host. |
| * @abstract |
| * @ignore |
| */ |
| getPreferredHost() { |
| |
| } |
| |
| /** |
| * Gets the query options as provided to the execution method without setting the default values. |
| * @returns {QueryOptions} |
| */ |
| getRawQueryOptions() { |
| |
| } |
| |
| /** |
| * Gets the timeout in milliseconds to be used for the execution per coordinator. |
| * <p> |
| * A value of <code>0</code> disables client side read timeout for the execution. Default: <code>undefined</code>. |
| * </p> |
| * @abstract |
| * @returns {Number} |
| */ |
| getReadTimeout() { |
| |
| } |
| |
| /** |
| * Gets the [retry policy]{@link module:policies/retry} to be used. |
| * @abstract |
| * @returns {RetryPolicy} A <code>RetryPolicy</code> instance, it can't be <code>undefined</code>. |
| */ |
| getRetryPolicy() { |
| |
| } |
| |
| /** |
| * Internal method to obtain the row callback, for "by row" results. |
| * @abstract |
| * @ignore |
| */ |
| getRowCallback() { |
| |
| } |
| |
| /** |
| * Internal method to get or generate a timestamp for the request execution. |
| * @ignore |
| * @returns {Long|null} |
| */ |
| getOrGenerateTimestamp() { |
| |
| } |
| |
| /** |
| * Gets the index of the parameters that are part of the partition key to determine the routing. |
| * @abstract |
| * @ignore |
| * @returns {Array} |
| */ |
| getRoutingIndexes() { |
| |
| } |
| |
| /** |
| * Gets the partition key(s) to determine which coordinator should be used for the query. |
| * @abstract |
| * @returns {Buffer|Array<Buffer>} |
| */ |
| getRoutingKey() { |
| |
| } |
| |
| /** |
| * Gets the array of the parameters names that are part of the partition key to determine the |
| * routing. Only valid for non-prepared requests. |
| * @abstract |
| * @ignore |
| */ |
| getRoutingNames() { |
| |
| } |
| |
| /** |
| * Gets the the consistency level to be used for the serial phase of conditional updates. |
| * @abstract |
| * @returns {Number} |
| */ |
| getSerialConsistency() { |
| |
| } |
| |
| /** |
| * Gets the provided timestamp for the execution in microseconds from the unix epoch (00:00:00, January 1st, 1970). |
| * <p>When a timestamp generator is used, this method returns <code>undefined</code>.</p> |
| * @abstract |
| * @returns {Number|Long|undefined|null} |
| */ |
| getTimestamp() { |
| |
| } |
| |
| /** |
| * @param {Array} hints |
| * @abstract |
| * @ignore |
| */ |
| setHints(hints) { |
| |
| } |
| |
| /** |
| * Sets the keyspace for the execution. |
| * @ignore |
| * @abstract |
| * @param {String} keyspace |
| */ |
| setKeyspace(keyspace) { |
| |
| } |
| |
| /** |
| * @abstract |
| * @ignore |
| */ |
| setPageState() { |
| |
| } |
| |
| /** |
| * Internal method that sets the preferred host. |
| * @abstract |
| * @ignore |
| */ |
| setPreferredHost() { |
| |
| } |
| |
| /** |
| * Sets the index of the parameters that are part of the partition key to determine the routing. |
| * @param {Array} routingIndexes |
| * @abstract |
| * @ignore |
| */ |
| setRoutingIndexes(routingIndexes) { |
| |
| } |
| |
| /** |
| * Sets the routing key. |
| * @abstract |
| * @ignore |
| */ |
| setRoutingKey(value) { |
| |
| } |
| } |
| |
| /** |
| * Internal implementation of {@link ExecutionOptions} that uses the value from the client options and execution |
| * profile into account. |
| * @ignore |
| */ |
| class DefaultExecutionOptions extends ExecutionOptions { |
| /** |
| * Creates a new instance of {@link ExecutionOptions}. |
| * @param {QueryOptions} queryOptions |
| * @param {Client} client |
| * @param {Function|null} rowCallback |
| */ |
| constructor(queryOptions, client, rowCallback) { |
| super(); |
| |
| this._queryOptions = queryOptions; |
| this._rowCallback = rowCallback; |
| this._routingKey = this._queryOptions.routingKey; |
| this._hints = this._queryOptions.hints; |
| this._keyspace = this._queryOptions.keyspace; |
| this._routingIndexes = this._queryOptions.routingIndexes; |
| this._pageState = typeof this._queryOptions.pageState === 'string' ? |
| utils.allocBufferFromString(this._queryOptions.pageState, 'hex') : this._queryOptions.pageState; |
| this._preferredHost = null; |
| |
| this._client = client; |
| this._defaultQueryOptions = client.options.queryOptions; |
| this._profile = client.profileManager.getProfile(this._queryOptions.executionProfile); |
| |
| // Build a custom payload object designed for DSE-specific functionality |
| this._customPayload = DefaultExecutionOptions.createCustomPayload(this._queryOptions, this._defaultQueryOptions); |
| |
| if (!this._profile) { |
| throw new errors.ArgumentError(`Execution profile "${this._queryOptions.executionProfile}" not found`); |
| } |
| } |
| |
| /** |
| * Creates a payload for given user. |
| * @param {QueryOptions} userOptions |
| * @param {QueryOptions} defaultQueryOptions |
| * @private |
| */ |
| static createCustomPayload(userOptions, defaultQueryOptions) { |
| let customPayload = userOptions.customPayload || defaultQueryOptions.customPayload; |
| const executeAs = userOptions.executeAs || defaultQueryOptions.executeAs; |
| |
| if (executeAs) { |
| if (!customPayload) { |
| customPayload = {}; |
| customPayload[proxyExecuteKey] = utils.allocBufferFromString(executeAs); |
| } else if (!customPayload[proxyExecuteKey]) { |
| // Avoid appending to the existing payload object |
| customPayload = utils.extend({}, customPayload); |
| customPayload[proxyExecuteKey] = utils.allocBufferFromString(executeAs); |
| } |
| } |
| |
| return customPayload; |
| } |
| |
| /** |
| * Creates a new instance {@link ExecutionOptions}, based on the query options. |
| * @param {QueryOptions|null} queryOptions |
| * @param {Client} client |
| * @param {Function|null} [rowCallback] |
| * @ignore |
| * @return {ExecutionOptions} |
| */ |
| static create(queryOptions, client, rowCallback) { |
| if (!queryOptions || typeof queryOptions === 'function') { |
| // queryOptions can be null/undefined and could be of type function when is an optional parameter |
| queryOptions = utils.emptyObject; |
| } |
| return new DefaultExecutionOptions(queryOptions, client, rowCallback); |
| } |
| |
| getCaptureStackTrace() { |
| return ifUndefined(this._queryOptions.captureStackTrace, this._defaultQueryOptions.captureStackTrace); |
| } |
| |
| getConsistency() { |
| return ifUndefined3(this._queryOptions.consistency, this._profile.consistency, |
| this._defaultQueryOptions.consistency); |
| } |
| |
| getCustomPayload() { |
| return this._customPayload; |
| } |
| |
| getFetchSize() { |
| return ifUndefined(this._queryOptions.fetchSize, this._defaultQueryOptions.fetchSize); |
| } |
| |
| getFixedHost() { |
| return this._queryOptions.host; |
| } |
| |
| getHints() { |
| return this._hints; |
| } |
| |
| isAutoPage() { |
| return ifUndefined(this._queryOptions.autoPage, this._defaultQueryOptions.autoPage); |
| } |
| |
| isBatchCounter() { |
| return ifUndefined(this._queryOptions.counter, false); |
| } |
| |
| isBatchLogged() { |
| return ifUndefined3(this._queryOptions.logged, this._defaultQueryOptions.logged, true); |
| } |
| |
| isIdempotent() { |
| return ifUndefined(this._queryOptions.isIdempotent, this._defaultQueryOptions.isIdempotent); |
| } |
| |
| /** |
| * Determines if the query execution must be prepared beforehand. |
| * @return {Boolean} |
| */ |
| isPrepared() { |
| return ifUndefined(this._queryOptions.prepare, this._defaultQueryOptions.prepare); |
| } |
| |
| isQueryTracing() { |
| return ifUndefined(this._queryOptions.traceQuery, this._defaultQueryOptions.traceQuery); |
| } |
| |
| getKeyspace() { |
| return this._keyspace; |
| } |
| |
| getLoadBalancingPolicy() { |
| return this._profile.loadBalancing; |
| } |
| |
| getOrGenerateTimestamp() { |
| let result = this.getTimestamp(); |
| |
| if (result === undefined) { |
| const generator = this._client.options.policies.timestampGeneration; |
| |
| if ( types.protocolVersion.supportsTimestamp(this._client.controlConnection.protocolVersion) && generator) { |
| result = generator.next(this._client); |
| } else { |
| result = null; |
| } |
| } |
| |
| return typeof result === 'number' ? types.Long.fromNumber(result) : result; |
| } |
| |
| getPageState() { |
| return this._pageState; |
| } |
| |
| /** |
| * Gets the profile defined by the user or the default profile |
| * @internal |
| * @ignore |
| */ |
| getProfile() { |
| return this._profile; |
| } |
| |
| getRawQueryOptions() { |
| return this._queryOptions; |
| } |
| |
| getReadTimeout() { |
| return ifUndefined3(this._queryOptions.readTimeout, this._profile.readTimeout, |
| this._client.options.socketOptions.readTimeout); |
| } |
| |
| getRetryPolicy() { |
| return ifUndefined3(this._queryOptions.retry, this._profile.retry, this._client.options.policies.retry); |
| } |
| |
| getRoutingIndexes() { |
| return this._routingIndexes; |
| } |
| |
| getRoutingKey() { |
| return this._routingKey; |
| } |
| |
| getRoutingNames() { |
| return this._queryOptions.routingNames; |
| } |
| |
| /** |
| * Internal method to obtain the row callback, for "by row" results. |
| * @ignore |
| */ |
| getRowCallback() { |
| return this._rowCallback; |
| } |
| |
| getSerialConsistency() { |
| return ifUndefined3( |
| this._queryOptions.serialConsistency, this._profile.serialConsistency, this._defaultQueryOptions.serialConsistency); |
| } |
| |
| getTimestamp() { |
| return this._queryOptions.timestamp; |
| } |
| |
| /** |
| * Internal property to set the custom payload. |
| * @ignore |
| * @internal |
| * @param {Object} payload |
| */ |
| setCustomPayload(payload) { |
| this._customPayload = payload; |
| } |
| |
| /** |
| * @param {Array} hints |
| */ |
| setHints(hints) { |
| this._hints = hints; |
| } |
| |
| /** |
| * @param {String} keyspace |
| */ |
| setKeyspace(keyspace) { |
| this._keyspace = keyspace; |
| } |
| |
| /** |
| * @param {Buffer} pageState |
| */ |
| setPageState(pageState) { |
| this._pageState = pageState; |
| } |
| |
| /** |
| * @param {Array} routingIndexes |
| */ |
| setRoutingIndexes(routingIndexes) { |
| this._routingIndexes = routingIndexes; |
| } |
| |
| setRoutingKey(value) { |
| this._routingKey = value; |
| } |
| } |
| |
| function ifUndefined(v1, v2) { |
| return v1 !== undefined ? v1 : v2; |
| } |
| |
| function ifUndefined3(v1, v2, v3) { |
| if (v1 !== undefined) { |
| return v1; |
| } |
| return v2 !== undefined ? v2 : v3; |
| } |
| |
| module.exports = { ExecutionOptions, DefaultExecutionOptions, proxyExecuteKey }; |