@ragestudio/scylla-odm 0.22.2 → 0.22.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/batch/index.d.ts +3 -3
- package/batch/index.d.ts.map +1 -1
- package/client.d.ts +6 -5
- package/client.d.ts.map +1 -1
- package/client.js +7 -7
- package/client.js.map +1 -1
- package/cql_gen/create_table.d.ts +1 -1
- package/cql_gen/create_table.d.ts.map +1 -1
- package/document/index.d.ts +3 -3
- package/document/index.d.ts.map +1 -1
- package/driver/LICENSE.txt +177 -0
- package/driver/NOTICE.txt +67 -0
- package/driver/auth/index.d.ts +37 -0
- package/driver/auth/index.js +37 -0
- package/driver/auth/no-auth-provider.js +73 -0
- package/driver/auth/plain-text-auth-provider.js +81 -0
- package/driver/auth/provider.js +77 -0
- package/driver/client-options.js +442 -0
- package/driver/client.js +1267 -0
- package/driver/concurrent/index.d.ts +49 -0
- package/driver/concurrent/index.js +366 -0
- package/driver/connection.js +1034 -0
- package/driver/control-connection.js +1282 -0
- package/driver/encoder.js +2316 -0
- package/driver/errors.js +223 -0
- package/driver/execution-options.js +612 -0
- package/driver/execution-profile.js +274 -0
- package/driver/host-connection-pool.js +587 -0
- package/driver/host.js +699 -0
- package/driver/index.d.ts +387 -0
- package/driver/index.js +81 -0
- package/driver/mapping/cache.js +214 -0
- package/driver/mapping/doc-info-adapter.js +171 -0
- package/driver/mapping/index.d.ts +219 -0
- package/driver/mapping/index.js +57 -0
- package/driver/mapping/mapper.js +225 -0
- package/driver/mapping/mapping-handler.js +641 -0
- package/driver/mapping/model-batch-item.js +215 -0
- package/driver/mapping/model-batch-mapper.js +141 -0
- package/driver/mapping/model-mapper.js +315 -0
- package/driver/mapping/model-mapping-info.js +225 -0
- package/driver/mapping/object-selector.js +417 -0
- package/driver/mapping/q.js +156 -0
- package/driver/mapping/query-generator.js +556 -0
- package/driver/mapping/result-mapper.js +123 -0
- package/driver/mapping/result.js +139 -0
- package/driver/mapping/table-mappings.js +133 -0
- package/driver/mapping/tree.js +160 -0
- package/driver/metadata/aggregate.js +79 -0
- package/driver/metadata/client-state.js +119 -0
- package/driver/metadata/data-collection.js +182 -0
- package/driver/metadata/event-debouncer.js +174 -0
- package/driver/metadata/index.d.ts +276 -0
- package/driver/metadata/index.js +1156 -0
- package/driver/metadata/materialized-view.js +49 -0
- package/driver/metadata/schema-function.js +98 -0
- package/driver/metadata/schema-index.js +166 -0
- package/driver/metadata/schema-parser.js +1399 -0
- package/driver/metadata/table-metadata.js +77 -0
- package/driver/operation-state.js +206 -0
- package/driver/policies/address-resolution.js +145 -0
- package/driver/policies/index.d.ts +241 -0
- package/driver/policies/index.js +110 -0
- package/driver/policies/load-balancing.js +970 -0
- package/driver/policies/reconnection.js +166 -0
- package/driver/policies/retry.js +326 -0
- package/driver/policies/speculative-execution.js +150 -0
- package/driver/policies/timestamp-generation.js +176 -0
- package/driver/prepare-handler.js +347 -0
- package/driver/promise-utils.js +191 -0
- package/driver/readers.js +624 -0
- package/driver/request-execution.js +644 -0
- package/driver/request-handler.js +332 -0
- package/driver/requests.js +618 -0
- package/driver/stream-id-stack.js +209 -0
- package/driver/streams.js +745 -0
- package/driver/token.js +325 -0
- package/driver/tokenizer.js +631 -0
- package/driver/types/big-decimal.js +282 -0
- package/driver/types/duration.js +576 -0
- package/driver/types/index.d.ts +486 -0
- package/driver/types/index.js +733 -0
- package/driver/types/inet-address.js +262 -0
- package/driver/types/integer.js +818 -0
- package/driver/types/local-date.js +280 -0
- package/driver/types/local-time.js +299 -0
- package/driver/types/mutable-long.js +385 -0
- package/driver/types/protocol-version.js +391 -0
- package/driver/types/result-set.js +287 -0
- package/driver/types/result-stream.js +164 -0
- package/driver/types/row.js +85 -0
- package/driver/types/time-uuid.js +414 -0
- package/driver/types/tuple.js +103 -0
- package/driver/types/uuid.js +160 -0
- package/driver/types/vector.js +130 -0
- package/driver/types/version-number.js +153 -0
- package/driver/utils.js +1485 -0
- package/driver/writers.js +350 -0
- package/global.d.ts +1 -1
- package/global.d.ts.map +1 -1
- package/index.d.ts +6 -6
- package/index.d.ts.map +1 -1
- package/index.js +6 -6
- package/index.js.map +1 -1
- package/migrate/index.d.ts +1 -1
- package/migrate/index.d.ts.map +1 -1
- package/migrate/index.js +1 -1
- package/migrate/index.js.map +1 -1
- package/model/index.d.ts +6 -6
- package/model/index.d.ts.map +1 -1
- package/model/index.js +10 -10
- package/model/index.js.map +1 -1
- package/operations/countAll.d.ts +1 -1
- package/operations/countAll.d.ts.map +1 -1
- package/operations/delete.d.ts +3 -4
- package/operations/delete.d.ts.map +1 -1
- package/operations/delete.js +1 -1
- package/operations/delete.js.map +1 -1
- package/operations/find.d.ts +2 -2
- package/operations/find.d.ts.map +1 -1
- package/operations/find.js +1 -1
- package/operations/find.js.map +1 -1
- package/operations/findOne.d.ts +2 -2
- package/operations/findOne.d.ts.map +1 -1
- package/operations/findOne.js +1 -1
- package/operations/findOne.js.map +1 -1
- package/operations/insert.d.ts +3 -3
- package/operations/insert.d.ts.map +1 -1
- package/operations/insert.js +2 -2
- package/operations/insert.js.map +1 -1
- package/operations/sync.d.ts +1 -1
- package/operations/sync.d.ts.map +1 -1
- package/operations/sync.js +1 -1
- package/operations/sync.js.map +1 -1
- package/operations/tableExists.d.ts +1 -1
- package/operations/tableExists.d.ts.map +1 -1
- package/operations/update.d.ts +3 -3
- package/operations/update.d.ts.map +1 -1
- package/operations/update.js +2 -2
- package/operations/update.js.map +1 -1
- package/package.json +4 -12
- package/schema/index.d.ts +1 -1
- package/schema/index.d.ts.map +1 -1
- package/types.d.ts +4 -4
- package/types.d.ts.map +1 -1
- package/utils/queryParser.d.ts +1 -1
- package/utils/queryParser.d.ts.map +1 -1
- package/utils/queryParser.js +1 -1
- package/utils/queryParser.js.map +1 -1
- package/utils/typeChecker.d.ts +1 -1
- package/utils/typeChecker.d.ts.map +1 -1
- package/utils/typeChecker.js +1 -1
- package/utils/typeChecker.js.map +1 -1
package/driver/client.js
ADDED
|
@@ -0,0 +1,1267 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Licensed to the Apache Software Foundation (ASF) under one
|
|
3
|
+
* or more contributor license agreements. See the NOTICE file
|
|
4
|
+
* distributed with this work for additional information
|
|
5
|
+
* regarding copyright ownership. The ASF licenses this file
|
|
6
|
+
* to you under the Apache License, Version 2.0 (the
|
|
7
|
+
* "License"); you may not use this file except in compliance
|
|
8
|
+
* with the License. You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/
|
|
18
|
+
import events from "events"
|
|
19
|
+
import util from "util"
|
|
20
|
+
|
|
21
|
+
import utils from "./utils.js"
|
|
22
|
+
import errors from "./errors.js"
|
|
23
|
+
import types from "./types/index.js"
|
|
24
|
+
import { ProfileManager } from "./execution-profile.js"
|
|
25
|
+
import requests from "./requests.js"
|
|
26
|
+
import clientOptions from "./client-options.js"
|
|
27
|
+
import ClientState from "./metadata/client-state.js"
|
|
28
|
+
import { DefaultExecutionOptions } from "./execution-options.js"
|
|
29
|
+
import ControlConnection from "./control-connection.js"
|
|
30
|
+
import RequestHandler from "./request-handler.js"
|
|
31
|
+
import PrepareHandler from "./prepare-handler.js"
|
|
32
|
+
import promiseUtils from "./promise-utils.js"
|
|
33
|
+
import { description, version } from "../../package.json" with { type: "json" }
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Max amount of pools being warmup in parallel, when warmup is enabled
|
|
37
|
+
* @private
|
|
38
|
+
*/
|
|
39
|
+
const warmupLimit = 32
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Client options.
|
|
43
|
+
* <p>While the driver provides lots of extensibility points and configurability, few client options are required.</p>
|
|
44
|
+
* <p>Default values for all settings are designed to be suitable for the majority of use cases, you should avoid
|
|
45
|
+
* fine tuning it when not needed.</p>
|
|
46
|
+
* <p>See [Client constructor]{@link Client} documentation for recommended options.</p>
|
|
47
|
+
* @typedef {Object} ClientOptions
|
|
48
|
+
* @property {Array.<string>} contactPoints
|
|
49
|
+
* Array of addresses or host names of the nodes to add as contact points.
|
|
50
|
+
* <p>
|
|
51
|
+
* Contact points are addresses of Cassandra nodes that the driver uses to discover the cluster topology.
|
|
52
|
+
* </p>
|
|
53
|
+
* <p>
|
|
54
|
+
* Only one contact point is required (the driver will retrieve the address of the other nodes automatically),
|
|
55
|
+
* but it is usually a good idea to provide more than one contact point, because if that single contact point is
|
|
56
|
+
* unavailable, the driver will not be able to initialize correctly.
|
|
57
|
+
* </p>
|
|
58
|
+
* @property {String} [localDataCenter] The local data center to use.
|
|
59
|
+
* <p>
|
|
60
|
+
* If using DCAwareRoundRobinPolicy (default), this option is required and only hosts from this data center are
|
|
61
|
+
* connected to and used in query plans.
|
|
62
|
+
* </p>
|
|
63
|
+
* @property {String} [keyspace] The logged keyspace for all the connections created within the {@link Client} instance.
|
|
64
|
+
* @property {Object} [credentials] An object containing the username and password for plain-text authentication.
|
|
65
|
+
* It configures the authentication provider to be used against Apache Cassandra's PasswordAuthenticator or DSE's
|
|
66
|
+
* DseAuthenticator, when default auth scheme is plain-text.
|
|
67
|
+
* <p>
|
|
68
|
+
* Note that you should configure either <code>credentials</code> or <code>authProvider</code> to connect to an
|
|
69
|
+
* auth-enabled cluster, but not both.
|
|
70
|
+
* </p>
|
|
71
|
+
* @property {String} [credentials.username] The username to use for plain-text authentication.
|
|
72
|
+
* @property {String} [credentials.password] The password to use for plain-text authentication.
|
|
73
|
+
* @property {Uuid} [id] A unique identifier assigned to a {@link Client} object, that will be communicated to the
|
|
74
|
+
* server (DSE 6.0+) to identify the client instance created with this options. When not defined, the driver will
|
|
75
|
+
* generate a random identifier.
|
|
76
|
+
* @property {String} [applicationName] An optional setting identifying the name of the application using
|
|
77
|
+
* the {@link Client} instance.
|
|
78
|
+
* <p>This value is passed to DSE and is useful as metadata for describing a client connection on the server side.</p>
|
|
79
|
+
* @property {String} [applicationVersion] An optional setting identifying the version of the application using
|
|
80
|
+
* the {@link Client} instance.
|
|
81
|
+
* <p>This value is passed to DSE and is useful as metadata for describing a client connection on the server side.</p>
|
|
82
|
+
* @property {Object} [monitorReporting] Options for reporting mechanism from the client to the DSE server, for
|
|
83
|
+
* versions that support it.
|
|
84
|
+
* @property {Boolean} [monitorReporting.enabled=true] Determines whether the reporting mechanism is enabled.
|
|
85
|
+
* Defaults to <code>true</code>.
|
|
86
|
+
* @property {Number} [refreshSchemaDelay] The default window size in milliseconds used to debounce node list and schema
|
|
87
|
+
* refresh metadata requests. Default: 1000.
|
|
88
|
+
* @property {Boolean} [isMetadataSyncEnabled] Determines whether client-side schema metadata retrieval and update is
|
|
89
|
+
* enabled.
|
|
90
|
+
* <p>Setting this value to <code>false</code> will cause keyspace information not to be automatically loaded, affecting
|
|
91
|
+
* replica calculation per token in the different keyspaces. When disabling metadata synchronization, use
|
|
92
|
+
* [Metadata.refreshKeyspaces()]{@link module:metadata~Metadata#refreshKeyspaces} to keep keyspace information up to
|
|
93
|
+
* date or token-awareness will not work correctly.</p>
|
|
94
|
+
* Default: <code>true</code>.
|
|
95
|
+
* @property {Boolean} [prepareOnAllHosts] Determines if the driver should prepare queries on all hosts in the cluster.
|
|
96
|
+
* Default: <code>true</code>.
|
|
97
|
+
* @property {Boolean} [rePrepareOnUp] Determines if the driver should re-prepare all cached prepared queries on a
|
|
98
|
+
* host when it marks it back up.
|
|
99
|
+
* Default: <code>true</code>.
|
|
100
|
+
* @property {Number} [maxPrepared] Determines the maximum amount of different prepared queries before evicting items
|
|
101
|
+
* from the internal cache. Reaching a high threshold hints that the queries are not being reused, like when
|
|
102
|
+
* hard-coding parameter values inside the queries.
|
|
103
|
+
* Default: <code>500</code>.
|
|
104
|
+
* @property {Object} [policies]
|
|
105
|
+
* @property {LoadBalancingPolicy} [policies.loadBalancing] The load balancing policy instance to be used to determine
|
|
106
|
+
* the coordinator per query.
|
|
107
|
+
* @property {RetryPolicy} [policies.retry] The retry policy.
|
|
108
|
+
* @property {ReconnectionPolicy} [policies.reconnection] The reconnection policy to be used.
|
|
109
|
+
* @property {AddressTranslator} [policies.addressResolution] The address resolution policy.
|
|
110
|
+
* @property {SpeculativeExecutionPolicy} [policies.speculativeExecution] The <code>SpeculativeExecutionPolicy</code>
|
|
111
|
+
* instance to be used to determine if the client should send speculative queries when the selected host takes more
|
|
112
|
+
* time than expected.
|
|
113
|
+
* <p>
|
|
114
|
+
* Default: <code>[NoSpeculativeExecutionPolicy]{@link
|
|
115
|
+
* module:policies/speculativeExecution~NoSpeculativeExecutionPolicy}</code>
|
|
116
|
+
* </p>
|
|
117
|
+
* @property {TimestampGenerator} [policies.timestampGeneration] The client-side
|
|
118
|
+
* [query timestamp generator]{@link module:policies/timestampGeneration~TimestampGenerator}.
|
|
119
|
+
* <p>
|
|
120
|
+
* Default: <code>[MonotonicTimestampGenerator]{@link module:policies/timestampGeneration~MonotonicTimestampGenerator}
|
|
121
|
+
* </code>
|
|
122
|
+
* </p>
|
|
123
|
+
* <p>Use <code>null</code> to disable client-side timestamp generation.</p>
|
|
124
|
+
* @property {QueryOptions} [queryOptions] Default options for all queries.
|
|
125
|
+
* @property {Object} [pooling] Pooling options.
|
|
126
|
+
* @property {Number} [pooling.heartBeatInterval] The amount of idle time in milliseconds that has to pass before the
|
|
127
|
+
* driver issues a request on an active connection to avoid idle time disconnections. Default: 30000.
|
|
128
|
+
* @property {Object} [pooling.coreConnectionsPerHost] Associative array containing amount of connections per host
|
|
129
|
+
* distance.
|
|
130
|
+
* @property {Number} [pooling.maxRequestsPerConnection] The maximum number of requests per connection. The default
|
|
131
|
+
* value is:
|
|
132
|
+
* <ul>
|
|
133
|
+
* <li>For modern protocol versions (v3 and above): 2048</li>
|
|
134
|
+
* <li>For older protocol versions (v1 and v2): 128</li>
|
|
135
|
+
* </ul>
|
|
136
|
+
* @property {Boolean} [pooling.warmup] Determines if all connections to hosts in the local datacenter must be opened on
|
|
137
|
+
* connect. Default: true.
|
|
138
|
+
* @property {Object} [protocolOptions]
|
|
139
|
+
* @property {Number} [protocolOptions.port] The port to use to connect to the Cassandra host. If not set through this
|
|
140
|
+
* method, the default port (9042) will be used instead.
|
|
141
|
+
* @property {Number} [protocolOptions.maxSchemaAgreementWaitSeconds] The maximum time in seconds to wait for schema
|
|
142
|
+
* agreement between nodes before returning from a DDL query. Default: 10.
|
|
143
|
+
* @property {Number} [protocolOptions.maxVersion] When set, it limits the maximum protocol version used to connect to
|
|
144
|
+
* the nodes.
|
|
145
|
+
* Useful for using the driver against a cluster that contains nodes with different major/minor versions of Cassandra.
|
|
146
|
+
* @property {Boolean} [protocolOptions.noCompact] When set to true, enables the NO_COMPACT startup option.
|
|
147
|
+
* <p>
|
|
148
|
+
* When this option is supplied <code>SELECT</code>, <code>UPDATE</code>, <code>DELETE</code>, and <code>BATCH</code>
|
|
149
|
+
* statements on <code>COMPACT STORAGE</code> tables function in "compatibility" mode which allows seeing these tables
|
|
150
|
+
* as if they were "regular" CQL tables.
|
|
151
|
+
* </p>
|
|
152
|
+
* <p>
|
|
153
|
+
* This option only effects interactions with interactions with tables using <code>COMPACT STORAGE</code> and is only
|
|
154
|
+
* supported by C* 3.0.16+, 3.11.2+, 4.0+ and DSE 6.0+.
|
|
155
|
+
* </p>
|
|
156
|
+
* @property {Object} [socketOptions]
|
|
157
|
+
* @property {Number} [socketOptions.connectTimeout] Connection timeout in milliseconds. Default: 5000.
|
|
158
|
+
* @property {Number} [socketOptions.defunctReadTimeoutThreshold] Determines the amount of requests that simultaneously
|
|
159
|
+
* have to timeout before closing the connection. Default: 64.
|
|
160
|
+
* @property {Boolean} [socketOptions.keepAlive] Whether to enable TCP keep-alive on the socket. Default: true.
|
|
161
|
+
* @property {Number} [socketOptions.keepAliveDelay] TCP keep-alive delay in milliseconds. Default: 0.
|
|
162
|
+
* @property {Number} [socketOptions.readTimeout] Per-host read timeout in milliseconds.
|
|
163
|
+
* <p>
|
|
164
|
+
* Please note that this is not the maximum time a call to {@link Client#execute} may have to wait;
|
|
165
|
+
* this is the maximum time that call will wait for one particular Cassandra host, but other hosts will be tried if
|
|
166
|
+
* one of them timeout. In other words, a {@link Client#execute} call may theoretically wait up to
|
|
167
|
+
* <code>readTimeout * number_of_cassandra_hosts</code> (though the total number of hosts tried for a given query also
|
|
168
|
+
* depends on the LoadBalancingPolicy in use).
|
|
169
|
+
* <p>When setting this value, keep in mind the following:</p>
|
|
170
|
+
* <ul>
|
|
171
|
+
* <li>the timeout settings used on the Cassandra side (*_request_timeout_in_ms in cassandra.yaml) should be taken
|
|
172
|
+
* into account when picking a value for this read timeout. You should pick a value a couple of seconds greater than
|
|
173
|
+
* the Cassandra timeout settings.
|
|
174
|
+
* </li>
|
|
175
|
+
* <li>
|
|
176
|
+
* the read timeout is only approximate and only control the timeout to one Cassandra host, not the full query.
|
|
177
|
+
* </li>
|
|
178
|
+
* </ul>
|
|
179
|
+
* Setting a value of 0 disables read timeouts. Default: <code>12000</code>.
|
|
180
|
+
* @property {Boolean} [socketOptions.tcpNoDelay] When set to true, it disables the Nagle algorithm. Default: true.
|
|
181
|
+
* @property {Number} [socketOptions.coalescingThreshold] Buffer length in bytes use by the write queue before flushing
|
|
182
|
+
* the frames. Default: 8000.
|
|
183
|
+
* @property {AuthProvider} [authProvider] Provider to be used to authenticate to an auth-enabled cluster.
|
|
184
|
+
* @property {RequestTracker} [requestTracker] The instance of RequestTracker used to monitor or log requests executed
|
|
185
|
+
* with this instance.
|
|
186
|
+
* @property {Object} [sslOptions] Client-to-node ssl options. When set the driver will use the secure layer.
|
|
187
|
+
* You can specify cert, ca, ... options named after the Node <code>tls.connect()</code> options.
|
|
188
|
+
* <p>
|
|
189
|
+
* It uses the same default values as Node <code>tls.connect()</code> except for <code>rejectUnauthorized</code>
|
|
190
|
+
* which is set to <code>false</code> by default (for historical reasons). This setting is likely to change
|
|
191
|
+
* in upcoming versions to enable validation by default.
|
|
192
|
+
* </p>
|
|
193
|
+
* @property {Object} [encoding] Encoding options.
|
|
194
|
+
* @property {Function} [encoding.map] Map constructor to use for Cassandra map<k,v> type encoding and decoding.
|
|
195
|
+
* If not set, it will default to Javascript Object with map keys as property names.
|
|
196
|
+
* @property {Function} [encoding.set] Set constructor to use for Cassandra set<k> type encoding and decoding.
|
|
197
|
+
* If not set, it will default to Javascript Array.
|
|
198
|
+
* @property {Boolean} [encoding.copyBuffer] Determines if the network buffer should be copied for buffer based data
|
|
199
|
+
* types (blob, uuid, timeuuid and inet).
|
|
200
|
+
* <p>
|
|
201
|
+
* Setting it to true will cause that the network buffer is copied for each row value of those types,
|
|
202
|
+
* causing additional allocations but freeing the network buffer to be reused.
|
|
203
|
+
* Setting it to true is a good choice for cases where the Row and ResultSet returned by the queries are long-lived
|
|
204
|
+
* objects.
|
|
205
|
+
* </p>
|
|
206
|
+
* <p>
|
|
207
|
+
* Setting it to false will cause less overhead and the reference of the network buffer to be maintained until the row
|
|
208
|
+
* / result set are de-referenced.
|
|
209
|
+
* Default: true.
|
|
210
|
+
* </p>
|
|
211
|
+
* @property {Boolean} [encoding.useUndefinedAsUnset] Valid for Cassandra 2.2 and above. Determines that, if a parameter
|
|
212
|
+
* is set to
|
|
213
|
+
* <code>undefined</code> it should be encoded as <code>unset</code>.
|
|
214
|
+
* <p>
|
|
215
|
+
* By default, ECMAScript <code>undefined</code> is encoded as <code>null</code> in the driver. Cassandra 2.2
|
|
216
|
+
* introduced the concept of unset.
|
|
217
|
+
* At driver level, you can set a parameter to unset using the field <code>types.unset</code>. Setting this flag to
|
|
218
|
+
* true allows you to use ECMAScript undefined as Cassandra <code>unset</code>.
|
|
219
|
+
* </p>
|
|
220
|
+
* <p>
|
|
221
|
+
* Default: true.
|
|
222
|
+
* </p>
|
|
223
|
+
* @property {Boolean} [encoding.useBigIntAsLong] Use [BigInt ECMAScript type](https://tc39.github.io/proposal-bigint/)
|
|
224
|
+
* to represent CQL bigint and counter data types.
|
|
225
|
+
* @property {Boolean} [encoding.useBigIntAsVarint] Use [BigInt ECMAScript
|
|
226
|
+
* type](https://tc39.github.io/proposal-bigint/) to represent CQL varint data type.
|
|
227
|
+
* @property {Array.<ExecutionProfile>} [profiles] The array of [execution profiles]{@link ExecutionProfile}.
|
|
228
|
+
* @property {Function} [promiseFactory] Function to be used to create a <code>Promise</code> from a
|
|
229
|
+
* callback-style function.
|
|
230
|
+
* <p>
|
|
231
|
+
* Promise libraries often provide different methods to create a promise. For example, you can use Bluebird's
|
|
232
|
+
* <code>Promise.fromCallback()</code> method.
|
|
233
|
+
* </p>
|
|
234
|
+
* <p>
|
|
235
|
+
* By default, the driver will use the
|
|
236
|
+
* [Promise constructor]{@link https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise}.
|
|
237
|
+
* </p>
|
|
238
|
+
*/
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Query options
|
|
242
|
+
* @typedef {Object} QueryOptions
|
|
243
|
+
* @property {Boolean} [autoPage] Determines if the driver must retrieve the following result pages automatically.
|
|
244
|
+
* <p>
|
|
245
|
+
* This setting is only considered by the [Client#eachRow()]{@link Client#eachRow} method. For more information,
|
|
246
|
+
* check the
|
|
247
|
+
* [paging results documentation]{@link https://docs.datastax.com/en/developer/nodejs-driver/latest/features/paging/}.
|
|
248
|
+
* </p>
|
|
249
|
+
* @property {Boolean} [captureStackTrace] Determines if the stack trace before the query execution should be
|
|
250
|
+
* maintained.
|
|
251
|
+
* <p>
|
|
252
|
+
* Useful for debugging purposes, it should be set to <code>false</code> under production environment as it adds an
|
|
253
|
+
* unnecessary overhead to each execution.
|
|
254
|
+
* </p>
|
|
255
|
+
* Default: false.
|
|
256
|
+
* @property {Number} [consistency] [Consistency level]{@link module:types~consistencies}.
|
|
257
|
+
* <p>
|
|
258
|
+
* Defaults to <code>localOne</code> for Apache Cassandra and DSE deployments.
|
|
259
|
+
* For DataStax Astra, it defaults to <code>localQuorum</code>.
|
|
260
|
+
* </p>
|
|
261
|
+
* @property {Object} [customPayload] Key-value payload to be passed to the server. On the Cassandra side,
|
|
262
|
+
* implementations of QueryHandler can use this data.
|
|
263
|
+
* @property {String} [executeAs] The user or role name to act as when executing this statement.
|
|
264
|
+
* <p>When set, it executes as a different user/role than the one currently authenticated (a.k.a. proxy execution).</p>
|
|
265
|
+
* <p>This feature is only available in DSE 5.1+.</p>
|
|
266
|
+
* @property {String|ExecutionProfile} [executionProfile] Name or instance of the [profile]{@link ExecutionProfile} to
|
|
267
|
+
* be used for this execution. If not set, it will the use "default" execution profile.
|
|
268
|
+
* @property {Number} [fetchSize] Amount of rows to retrieve per page.
|
|
269
|
+
* @property {Array|Array<Array>} [hints] Type hints for parameters given in the query, ordered as for the parameters.
|
|
270
|
+
* <p>For batch queries, an array of such arrays, ordered as with the queries in the batch.</p>
|
|
271
|
+
* @property {Host} [host] The host that should handle the query.
|
|
272
|
+
* <p>
|
|
273
|
+
* Use of this option is <em>heavily discouraged</em> and should only be used in the following cases:
|
|
274
|
+
* </p>
|
|
275
|
+
* <ol>
|
|
276
|
+
* <li>
|
|
277
|
+
* Querying node-local tables, such as tables in the <code>system</code> and <code>system_views</code>
|
|
278
|
+
* keyspaces.
|
|
279
|
+
* </li>
|
|
280
|
+
* <li>
|
|
281
|
+
* Applying a series of schema changes, where it may be advantageous to execute schema changes in sequence on the
|
|
282
|
+
* same node.
|
|
283
|
+
* </li>
|
|
284
|
+
* </ol>
|
|
285
|
+
* <p>
|
|
286
|
+
* Configuring a specific host causes the configured
|
|
287
|
+
* [LoadBalancingPolicy]{@link module:policies/loadBalancing~LoadBalancingPolicy} to be completely bypassed.
|
|
288
|
+
* However, if the load balancing policy dictates that the host is at a
|
|
289
|
+
* [distance of ignored]{@link module:types~distance} or there is no active connectivity to the host, the request will
|
|
290
|
+
* fail with a [NoHostAvailableError]{@link module:errors~NoHostAvailableError}.
|
|
291
|
+
* </p>
|
|
292
|
+
* @property {Boolean} [isIdempotent] Defines whether the query can be applied multiple times without changing the result
|
|
293
|
+
* beyond the initial application.
|
|
294
|
+
* <p>
|
|
295
|
+
* The query execution idempotence can be used at [RetryPolicy]{@link module:policies/retry~RetryPolicy} level to
|
|
296
|
+
* determine if an statement can be retried in case of request error or write timeout.
|
|
297
|
+
* </p>
|
|
298
|
+
* <p>Default: <code>false</code>.</p>
|
|
299
|
+
* @property {String} [keyspace] Specifies the keyspace for the query. It is used for the following:
|
|
300
|
+
* <ol>
|
|
301
|
+
* <li>To indicate what keyspace the statement is applicable to (protocol V5+ only). This is useful when the
|
|
302
|
+
* query does not provide an explicit keyspace and you want to override the current {@link Client#keyspace}.</li>
|
|
303
|
+
* <li>For query routing when the query operates on a different keyspace than the current {@link Client#keyspace}.</li>
|
|
304
|
+
* </ol>
|
|
305
|
+
* @property {Boolean} [logged] Determines if the batch should be written to the batchlog. Only valid for
|
|
306
|
+
* [Client#batch()]{@link Client#batch}, it will be ignored by other methods. Default: true.
|
|
307
|
+
* @property {Boolean} [counter] Determines if its a counter batch. Only valid for
|
|
308
|
+
* [Client#batch()]{@link Client#batch}, it will be ignored by other methods. Default: false.
|
|
309
|
+
* @property {Buffer|String} [pageState] Buffer or string token representing the paging state.
|
|
310
|
+
* <p>Useful for manual paging, if provided, the query will be executed starting from a given paging state.</p>
|
|
311
|
+
* @property {Boolean} [prepare] Determines if the query must be executed as a prepared statement.
|
|
312
|
+
* @property {Number} [readTimeout] When defined, it overrides the default read timeout
|
|
313
|
+
* (<code>socketOptions.readTimeout</code>) in milliseconds for this execution per coordinator.
|
|
314
|
+
* <p>
|
|
315
|
+
* Suitable for statements for which the coordinator may allow a longer server-side timeout, for example aggregation
|
|
316
|
+
* queries.
|
|
317
|
+
* </p>
|
|
318
|
+
* <p>
|
|
319
|
+
* A value of <code>0</code> disables client side read timeout for the execution. Default: <code>undefined</code>.
|
|
320
|
+
* </p>
|
|
321
|
+
* @property {RetryPolicy} [retry] Retry policy for the query.
|
|
322
|
+
* <p>
|
|
323
|
+
* This property can be used to specify a different [retry policy]{@link module:policies/retry} to the one specified
|
|
324
|
+
* in the {@link ClientOptions}.policies.
|
|
325
|
+
* </p>
|
|
326
|
+
* @property {Array} [routingIndexes] Index of the parameters that are part of the partition key to determine
|
|
327
|
+
* the routing.
|
|
328
|
+
* @property {Buffer|Array} [routingKey] Partition key(s) to determine which coordinator should be used for the query.
|
|
329
|
+
* @property {Array} [routingNames] Array of the parameters names that are part of the partition key to determine the
|
|
330
|
+
* routing. Only valid for non-prepared requests, it's recommended that you use the prepare flag instead.
|
|
331
|
+
* @property {Number} [serialConsistency] Serial consistency is the consistency level for the serial phase of
|
|
332
|
+
* conditional updates.
|
|
333
|
+
* This option will be ignored for anything else that a conditional update/insert.
|
|
334
|
+
* @property {Number|Long} [timestamp] The default timestamp for the query in microseconds from the unix epoch
|
|
335
|
+
* (00:00:00, January 1st, 1970).
|
|
336
|
+
* <p>If provided, this will replace the server side assigned timestamp as default timestamp.</p>
|
|
337
|
+
* <p>Use [generateTimestamp()]{@link module:types~generateTimestamp} utility method to generate a valid timestamp
|
|
338
|
+
* based on a Date and microseconds parts.</p>
|
|
339
|
+
* @property {Boolean} [traceQuery] Enable query tracing for the execution. Use query tracing to diagnose performance
|
|
340
|
+
* problems related to query executions. Default: false.
|
|
341
|
+
* <p>To retrieve trace, you can call [Metadata.getTrace()]{@link module:metadata~Metadata#getTrace} method.</p>
|
|
342
|
+
* @property {Object} [graphOptions] Default options for graph query executions.
|
|
343
|
+
* <p>
|
|
344
|
+
* These options are meant to provide defaults for all graph query executions. Consider using
|
|
345
|
+
* [execution profiles]{@link ExecutionProfile} if you plan to reuse different set of options across different
|
|
346
|
+
* query executions.
|
|
347
|
+
* </p>
|
|
348
|
+
* @property {String} [graphOptions.language] The graph language to use in graph queries. Default:
|
|
349
|
+
* <code>'gremlin-groovy'</code>.
|
|
350
|
+
* @property {String} [graphOptions.name] The graph name to be used in all graph queries.
|
|
351
|
+
* <p>
|
|
352
|
+
* This property is required but there is no default value for it. This value can be overridden at query level.
|
|
353
|
+
* </p>
|
|
354
|
+
* @property {Number} [graphOptions.readConsistency] Overrides the
|
|
355
|
+
* [consistency level]{@link module:types~consistencies}
|
|
356
|
+
* defined in the query options for graph read queries.
|
|
357
|
+
* @property {Number} [graphOptions.readTimeout] Overrides the default per-host read timeout (in milliseconds) for all
|
|
358
|
+
* graph queries. Default: <code>0</code>.
|
|
359
|
+
* <p>
|
|
360
|
+
* Use <code>null</code> to reset the value and use the default on <code>socketOptions.readTimeout</code> .
|
|
361
|
+
* </p>
|
|
362
|
+
* @property {String} [graphOptions.source] The graph traversal source name to use in graph queries. Default:
|
|
363
|
+
* <code>'g'</code>.
|
|
364
|
+
* @property {Number} [graphOptions.writeConsistency] Overrides the [consistency
|
|
365
|
+
* level]{@link module:types~consistencies} defined in the query options for graph write queries.
|
|
366
|
+
*/
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Creates a new instance of {@link Client}.
|
|
370
|
+
* @classdesc
|
|
371
|
+
* Represents a database client that maintains multiple connections to the cluster nodes, providing methods to
|
|
372
|
+
* execute CQL statements.
|
|
373
|
+
* <p>
|
|
374
|
+
* The <code>Client</code> uses [policies]{@link module:policies} to decide which nodes to connect to, which node
|
|
375
|
+
* to use per each query execution, when it should retry failed or timed-out executions and how reconnection to down
|
|
376
|
+
* nodes should be made.
|
|
377
|
+
* </p>
|
|
378
|
+
* @extends EventEmitter
|
|
379
|
+
* @param {ClientOptions} options The options for this instance.
|
|
380
|
+
* @example <caption>Creating a new client instance</caption>
|
|
381
|
+
* const client = new Client({
|
|
382
|
+
* contactPoints: ['10.0.1.101', '10.0.1.102'],
|
|
383
|
+
* localDataCenter: 'datacenter1'
|
|
384
|
+
* });
|
|
385
|
+
* @example <caption>Executing a query</caption>
|
|
386
|
+
* const result = await client.connect();
|
|
387
|
+
* console.log(`Connected to ${client.hosts.length} nodes in the cluster: ${client.hosts.keys().join(', ')}`);
|
|
388
|
+
* @example <caption>Executing a query</caption>
|
|
389
|
+
* const result = await client.execute('SELECT key FROM system.local');
|
|
390
|
+
* const row = result.first();
|
|
391
|
+
* console.log(row['key']);
|
|
392
|
+
* @constructor
|
|
393
|
+
*/
|
|
394
|
+
function Client(options) {
|
|
395
|
+
events.EventEmitter.call(this)
|
|
396
|
+
this.options = clientOptions.extend(
|
|
397
|
+
{ logEmitter: this.emit.bind(this), id: types.Uuid.random() },
|
|
398
|
+
options,
|
|
399
|
+
)
|
|
400
|
+
Object.defineProperty(this, "profileManager", {
|
|
401
|
+
value: new ProfileManager(this.options),
|
|
402
|
+
})
|
|
403
|
+
Object.defineProperty(this, "controlConnection", {
|
|
404
|
+
value: new ControlConnection(this.options, this.profileManager),
|
|
405
|
+
writable: true,
|
|
406
|
+
})
|
|
407
|
+
//Unlimited amount of listeners for internal event queues by default
|
|
408
|
+
this.setMaxListeners(0)
|
|
409
|
+
this.connected = false
|
|
410
|
+
this.isShuttingDown = false
|
|
411
|
+
/**
|
|
412
|
+
* Gets the name of the active keyspace.
|
|
413
|
+
* @type {String}
|
|
414
|
+
*/
|
|
415
|
+
this.keyspace = options.keyspace
|
|
416
|
+
/**
|
|
417
|
+
* Gets the schema and cluster metadata information.
|
|
418
|
+
* @type {Metadata}
|
|
419
|
+
*/
|
|
420
|
+
this.metadata = this.controlConnection.metadata
|
|
421
|
+
/**
|
|
422
|
+
* Gets an associative array of cluster hosts.
|
|
423
|
+
* @type {HostMap}
|
|
424
|
+
*/
|
|
425
|
+
this.hosts = this.controlConnection.hosts
|
|
426
|
+
|
|
427
|
+
// metrics are not available in this build (noop stub from client-options)
|
|
428
|
+
this.metrics = this.options.metrics
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
util.inherits(Client, events.EventEmitter)
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Emitted when a new host is added to the cluster.
|
|
435
|
+
* <ul>
|
|
436
|
+
* <li>{@link Host} The host being added.</li>
|
|
437
|
+
* </ul>
|
|
438
|
+
* @event Client#hostAdd
|
|
439
|
+
*/
|
|
440
|
+
/**
|
|
441
|
+
* Emitted when a host is removed from the cluster
|
|
442
|
+
* <ul>
|
|
443
|
+
* <li>{@link Host} The host being removed.</li>
|
|
444
|
+
* </ul>
|
|
445
|
+
* @event Client#hostRemove
|
|
446
|
+
*/
|
|
447
|
+
/**
|
|
448
|
+
* Emitted when a host in the cluster changed status from down to up.
|
|
449
|
+
* <ul>
|
|
450
|
+
* <li>{@link Host host} The host that changed the status.</li>
|
|
451
|
+
* </ul>
|
|
452
|
+
* @event Client#hostUp
|
|
453
|
+
*/
|
|
454
|
+
/**
|
|
455
|
+
* Emitted when a host in the cluster changed status from up to down.
|
|
456
|
+
* <ul>
|
|
457
|
+
* <li>{@link Host host} The host that changed the status.</li>
|
|
458
|
+
* </ul>
|
|
459
|
+
* @event Client#hostDown
|
|
460
|
+
*/
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Attempts to connect to one of the [contactPoints]{@link ClientOptions} and discovers the rest the nodes of the
|
|
464
|
+
* cluster.
|
|
465
|
+
* <p>When the {@link Client} is already connected, it resolves immediately.</p>
|
|
466
|
+
* <p>It returns a <code>Promise</code> when a <code>callback</code> is not provided.</p>
|
|
467
|
+
* @param {function} [callback] The optional callback that is invoked when the pool is connected or it failed to
|
|
468
|
+
* connect.
|
|
469
|
+
* @example <caption>Usage example</caption>
|
|
470
|
+
* await client.connect();
|
|
471
|
+
*/
|
|
472
|
+
Client.prototype.connect = function (callback) {
|
|
473
|
+
if (this.connected && callback) {
|
|
474
|
+
// Avoid creating Promise to immediately resolve them
|
|
475
|
+
return callback()
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
return promiseUtils.optionalCallback(this._connect(), callback)
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Async-only version of {@link Client#connect()}.
|
|
483
|
+
* @private
|
|
484
|
+
*/
|
|
485
|
+
Client.prototype._connect = async function () {
|
|
486
|
+
if (this.connected) {
|
|
487
|
+
return
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
if (this.isShuttingDown) {
|
|
491
|
+
//it is being shutdown, don't allow further calls to connect()
|
|
492
|
+
throw new errors.NoHostAvailableError(
|
|
493
|
+
null,
|
|
494
|
+
"Connecting after shutdown is not supported",
|
|
495
|
+
)
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (this.connecting) {
|
|
499
|
+
return promiseUtils.fromEvent(this, "connected")
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
this.connecting = true
|
|
503
|
+
this.log(
|
|
504
|
+
"info",
|
|
505
|
+
util.format(
|
|
506
|
+
"Connecting to cluster using '%s' version %s",
|
|
507
|
+
description,
|
|
508
|
+
version,
|
|
509
|
+
),
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
try {
|
|
513
|
+
await this.controlConnection.init()
|
|
514
|
+
this.hosts = this.controlConnection.hosts
|
|
515
|
+
await this.profileManager.init(this, this.hosts)
|
|
516
|
+
|
|
517
|
+
if (this.keyspace) {
|
|
518
|
+
await RequestHandler.setKeyspace(this)
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
clientOptions.setMetadataDependent(this)
|
|
522
|
+
|
|
523
|
+
await this._warmup()
|
|
524
|
+
} catch (err) {
|
|
525
|
+
// We should close the pools (if any) and reset the state to allow successive calls to connect()
|
|
526
|
+
await this.controlConnection.reset()
|
|
527
|
+
this.connected = false
|
|
528
|
+
this.connecting = false
|
|
529
|
+
this.emit("connected", err)
|
|
530
|
+
throw err
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
this._setHostListeners()
|
|
534
|
+
|
|
535
|
+
// Set the distance of the control connection host relatively to this instance
|
|
536
|
+
this.profileManager.getDistance(this.controlConnection.host)
|
|
537
|
+
this.connected = true
|
|
538
|
+
this.connecting = false
|
|
539
|
+
this.emit("connected")
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Executes a query on an available connection.
|
|
544
|
+
* <p>The query can be prepared (recommended) or not depending on the [prepare]{@linkcode QueryOptions} flag.</p>
|
|
545
|
+
* <p>
|
|
546
|
+
* Some execution failures can be handled transparently by the driver, according to the
|
|
547
|
+
* [RetryPolicy]{@linkcode module:policies/retry~RetryPolicy} or the
|
|
548
|
+
* [SpeculativeExecutionPolicy]{@linkcode module:policies/speculativeExecution} used.
|
|
549
|
+
* </p>
|
|
550
|
+
* <p>It returns a <code>Promise</code> when a <code>callback</code> is not provided.</p>
|
|
551
|
+
* @param {String} query The query to execute.
|
|
552
|
+
* @param {Array|Object} [params] Array of parameter values or an associative array (object) containing parameter names
|
|
553
|
+
* as keys and its value.
|
|
554
|
+
* @param {QueryOptions} [options] The query options for the execution.
|
|
555
|
+
* @param {ResultCallback} [callback] Executes callback(err, result) when execution completed. When not defined, the
|
|
556
|
+
* method will return a promise.
|
|
557
|
+
* @example <caption>Promise-based API, using async/await</caption>
|
|
558
|
+
* const query = 'SELECT name, email FROM users WHERE id = ?';
|
|
559
|
+
* const result = await client.execute(query, [ id ], { prepare: true });
|
|
560
|
+
* const row = result.first();
|
|
561
|
+
* console.log('%s: %s', row['name'], row['email']);
|
|
562
|
+
* @example <caption>Callback-based API</caption>
|
|
563
|
+
* const query = 'SELECT name, email FROM users WHERE id = ?';
|
|
564
|
+
* client.execute(query, [ id ], { prepare: true }, function (err, result) {
|
|
565
|
+
* assert.ifError(err);
|
|
566
|
+
* const row = result.first();
|
|
567
|
+
* console.log('%s: %s', row['name'], row['email']);
|
|
568
|
+
* });
|
|
569
|
+
* @see {@link ExecutionProfile} to reuse a set of options across different query executions.
|
|
570
|
+
*/
|
|
571
|
+
Client.prototype.execute = function (query, params, options, callback) {
|
|
572
|
+
// This method acts as a wrapper for the async method _execute()
|
|
573
|
+
|
|
574
|
+
if (!callback) {
|
|
575
|
+
// Set default argument values for optional parameters
|
|
576
|
+
if (typeof options === "function") {
|
|
577
|
+
callback = options
|
|
578
|
+
options = null
|
|
579
|
+
} else if (typeof params === "function") {
|
|
580
|
+
callback = params
|
|
581
|
+
params = null
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
try {
|
|
586
|
+
const execOptions = DefaultExecutionOptions.create(options, this)
|
|
587
|
+
return promiseUtils.optionalCallback(
|
|
588
|
+
this._execute(query, params, execOptions),
|
|
589
|
+
callback,
|
|
590
|
+
)
|
|
591
|
+
} catch (err) {
|
|
592
|
+
// There was an error when parsing the user options
|
|
593
|
+
if (callback) {
|
|
594
|
+
return callback(err)
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
return Promise.reject(err)
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* Executes a graph query.
|
|
603
|
+
* <p>It returns a <code>Promise</code> when a <code>callback</code> is not provided.</p>
|
|
604
|
+
* @param {String} query The gremlin query.
|
|
605
|
+
* @param {Object|null} [parameters] An associative array containing the key and values of the parameters.
|
|
606
|
+
* @param {GraphQueryOptions|null} [options] The graph query options.
|
|
607
|
+
* @param {Function} [callback] Function to execute when the response is retrieved, taking two arguments:
|
|
608
|
+
* <code>err</code> and <code>result</code>. When not defined, the method will return a promise.
|
|
609
|
+
* @example <caption>Promise-based API, using async/await</caption>
|
|
610
|
+
* const result = await client.executeGraph('g.V()');
|
|
611
|
+
* // Get the first item (vertex, edge, scalar value, ...)
|
|
612
|
+
* const vertex = result.first();
|
|
613
|
+
* console.log(vertex.label);
|
|
614
|
+
* @example <caption>Callback-based API</caption>
|
|
615
|
+
* client.executeGraph('g.V()', (err, result) => {
|
|
616
|
+
* const vertex = result.first();
|
|
617
|
+
* console.log(vertex.label);
|
|
618
|
+
* });
|
|
619
|
+
* @example <caption>Iterating through the results</caption>
|
|
620
|
+
* const result = await client.executeGraph('g.E()');
|
|
621
|
+
* for (let edge of result) {
|
|
622
|
+
* console.log(edge.label); // created
|
|
623
|
+
* });
|
|
624
|
+
* @example <caption>Using result.forEach()</caption>
|
|
625
|
+
* const result = await client.executeGraph('g.V().hasLabel("person")');
|
|
626
|
+
* result.forEach(function(vertex) {
|
|
627
|
+
* console.log(vertex.type); // vertex
|
|
628
|
+
* console.log(vertex.label); // person
|
|
629
|
+
* });
|
|
630
|
+
* @see {@link ExecutionProfile} to reuse a set of options across different query executions.
|
|
631
|
+
*/
|
|
632
|
+
Client.prototype.executeGraph = function () {
|
|
633
|
+
throw new Error("Graph queries are not supported in this build")
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Executes the query and calls <code>rowCallback</code> for each row as soon as they are received. Calls the final
|
|
638
|
+
* <code>callback</code> after all rows have been sent, or when there is an error.
|
|
639
|
+
* <p>
|
|
640
|
+
* The query can be prepared (recommended) or not depending on the [prepare]{@linkcode QueryOptions} flag.
|
|
641
|
+
* </p>
|
|
642
|
+
* @param {String} query The query to execute
|
|
643
|
+
* @param {Array|Object} [params] Array of parameter values or an associative array (object) containing parameter names
|
|
644
|
+
* as keys and its value.
|
|
645
|
+
* @param {QueryOptions} [options] The query options.
|
|
646
|
+
* @param {function} rowCallback Executes <code>rowCallback(n, row)</code> per each row received, where n is the row
|
|
647
|
+
* index and row is the current Row.
|
|
648
|
+
* @param {function} [callback] Executes <code>callback(err, result)</code> after all rows have been received.
|
|
649
|
+
* <p>
|
|
650
|
+
* When dealing with paged results, [ResultSet#nextPage()]{@link module:types~ResultSet#nextPage} method can be used
|
|
651
|
+
* to retrieve the following page. In that case, <code>rowCallback()</code> will be again called for each row and
|
|
652
|
+
* the final callback will be invoked when all rows in the following page has been retrieved.
|
|
653
|
+
* </p>
|
|
654
|
+
* @example <caption>Using per-row callback and arrow functions</caption>
|
|
655
|
+
* client.eachRow(query, params, { prepare: true }, (n, row) => console.log(n, row), err => console.error(err));
|
|
656
|
+
* @example <caption>Overloads</caption>
|
|
657
|
+
* client.eachRow(query, rowCallback);
|
|
658
|
+
* client.eachRow(query, params, rowCallback);
|
|
659
|
+
* client.eachRow(query, params, options, rowCallback);
|
|
660
|
+
* client.eachRow(query, params, rowCallback, callback);
|
|
661
|
+
* client.eachRow(query, params, options, rowCallback, callback);
|
|
662
|
+
*/
|
|
663
|
+
Client.prototype.eachRow = function (
|
|
664
|
+
query,
|
|
665
|
+
params,
|
|
666
|
+
options,
|
|
667
|
+
rowCallback,
|
|
668
|
+
callback,
|
|
669
|
+
) {
|
|
670
|
+
if (!callback && rowCallback && typeof options === "function") {
|
|
671
|
+
callback = utils.validateFn(rowCallback, "rowCallback")
|
|
672
|
+
rowCallback = options
|
|
673
|
+
} else {
|
|
674
|
+
callback = callback || utils.noop
|
|
675
|
+
rowCallback = utils.validateFn(
|
|
676
|
+
rowCallback || options || params,
|
|
677
|
+
"rowCallback",
|
|
678
|
+
)
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
params = typeof params !== "function" ? params : null
|
|
682
|
+
|
|
683
|
+
let execOptions
|
|
684
|
+
try {
|
|
685
|
+
execOptions = DefaultExecutionOptions.create(options, this, rowCallback)
|
|
686
|
+
} catch (e) {
|
|
687
|
+
return callback(e)
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
let rowLength = 0
|
|
691
|
+
|
|
692
|
+
const nextPage = () =>
|
|
693
|
+
promiseUtils.toCallback(
|
|
694
|
+
this._execute(query, params, execOptions),
|
|
695
|
+
pageCallback,
|
|
696
|
+
)
|
|
697
|
+
|
|
698
|
+
function pageCallback(err, result) {
|
|
699
|
+
if (err) {
|
|
700
|
+
return callback(err)
|
|
701
|
+
}
|
|
702
|
+
// Next requests in case paging (auto or explicit) is used
|
|
703
|
+
rowLength += result.rowLength
|
|
704
|
+
|
|
705
|
+
if (result.rawPageState !== undefined) {
|
|
706
|
+
// Use new page state as next request page state
|
|
707
|
+
execOptions.setPageState(result.rawPageState)
|
|
708
|
+
if (execOptions.isAutoPage()) {
|
|
709
|
+
// Issue next request for the next page
|
|
710
|
+
return nextPage()
|
|
711
|
+
}
|
|
712
|
+
// Allows for explicit (manual) paging, in case the caller needs it
|
|
713
|
+
result.nextPage = nextPage
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// Finished auto-paging
|
|
717
|
+
result.rowLength = rowLength
|
|
718
|
+
callback(null, result)
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
promiseUtils.toCallback(
|
|
722
|
+
this._execute(query, params, execOptions),
|
|
723
|
+
pageCallback,
|
|
724
|
+
)
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* Executes the query and pushes the rows to the result stream as soon as they received.
|
|
729
|
+
* <p>
|
|
730
|
+
* The stream is a [ReadableStream]{@linkcode https://nodejs.org/api/stream.html#stream_class_stream_readable} object
|
|
731
|
+
* that emits rows.
|
|
732
|
+
* It can be piped downstream and provides automatic pause/resume logic (it buffers when not read).
|
|
733
|
+
* </p>
|
|
734
|
+
* <p>
|
|
735
|
+
* The query can be prepared (recommended) or not depending on {@link QueryOptions}.prepare flag. Retries on multiple
|
|
736
|
+
* hosts if needed.
|
|
737
|
+
* </p>
|
|
738
|
+
* @param {String} query The query to prepare and execute.
|
|
739
|
+
* @param {Array|Object} [params] Array of parameter values or an associative array (object) containing parameter names
|
|
740
|
+
* as keys and its value
|
|
741
|
+
* @param {QueryOptions} [options] The query options.
|
|
742
|
+
* @param {function} [callback] executes callback(err) after all rows have been received or if there is an error
|
|
743
|
+
* @returns {ResultStream}
|
|
744
|
+
*/
|
|
745
|
+
Client.prototype.stream = function (query, params, options, callback) {
|
|
746
|
+
callback = callback || utils.noop
|
|
747
|
+
// NOTE: the nodejs stream maintains yet another internal buffer
|
|
748
|
+
// we rely on the default stream implementation to keep memory
|
|
749
|
+
// usage reasonable.
|
|
750
|
+
const resultStream = new types.ResultStream({ objectMode: 1 })
|
|
751
|
+
function onFinish(err, result) {
|
|
752
|
+
if (err) {
|
|
753
|
+
resultStream.emit("error", err)
|
|
754
|
+
}
|
|
755
|
+
if (result && result.nextPage) {
|
|
756
|
+
// allows for throttling as per the
|
|
757
|
+
// default nodejs stream implementation
|
|
758
|
+
resultStream._valve(function pageValve() {
|
|
759
|
+
try {
|
|
760
|
+
result.nextPage()
|
|
761
|
+
} catch (ex) {
|
|
762
|
+
resultStream.emit("error", ex)
|
|
763
|
+
}
|
|
764
|
+
})
|
|
765
|
+
return
|
|
766
|
+
}
|
|
767
|
+
// Explicitly dropping the valve (closure)
|
|
768
|
+
resultStream._valve(null)
|
|
769
|
+
resultStream.add(null)
|
|
770
|
+
callback(err)
|
|
771
|
+
}
|
|
772
|
+
let sync = true
|
|
773
|
+
this.eachRow(
|
|
774
|
+
query,
|
|
775
|
+
params,
|
|
776
|
+
options,
|
|
777
|
+
function rowCallback(n, row) {
|
|
778
|
+
resultStream.add(row)
|
|
779
|
+
},
|
|
780
|
+
function eachRowFinished(err, result) {
|
|
781
|
+
if (sync) {
|
|
782
|
+
// Prevent sync callback
|
|
783
|
+
return setImmediate(function eachRowFinishedImmediate() {
|
|
784
|
+
onFinish(err, result)
|
|
785
|
+
})
|
|
786
|
+
}
|
|
787
|
+
onFinish(err, result)
|
|
788
|
+
},
|
|
789
|
+
)
|
|
790
|
+
sync = false
|
|
791
|
+
return resultStream
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
/**
|
|
795
|
+
* Executes batch of queries on an available connection to a host.
|
|
796
|
+
* <p>It returns a <code>Promise</code> when a <code>callback</code> is not provided.</p>
|
|
797
|
+
* @param {Array.<string>|Array.<{query, params}>} queries The queries to execute as an Array of strings or as an array
|
|
798
|
+
* of object containing the query and params
|
|
799
|
+
* @param {QueryOptions} [options] The query options.
|
|
800
|
+
* @param {ResultCallback} [callback] Executes callback(err, result) when the batch was executed
|
|
801
|
+
*/
|
|
802
|
+
Client.prototype.batch = function (queries, options, callback) {
|
|
803
|
+
if (!callback && typeof options === "function") {
|
|
804
|
+
callback = options
|
|
805
|
+
options = null
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
return promiseUtils.optionalCallback(
|
|
809
|
+
this._batch(queries, options),
|
|
810
|
+
callback,
|
|
811
|
+
)
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* Async-only version of {@link Client#batch()} .
|
|
816
|
+
* @param {Array.<string>|Array.<{query, params}>}queries
|
|
817
|
+
* @param {QueryOptions} options
|
|
818
|
+
* @returns {Promise<ResultSet>}
|
|
819
|
+
* @private
|
|
820
|
+
*/
|
|
821
|
+
Client.prototype._batch = async function (queries, options) {
|
|
822
|
+
if (!Array.isArray(queries)) {
|
|
823
|
+
throw new errors.ArgumentError("Queries should be an Array")
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
if (queries.length === 0) {
|
|
827
|
+
throw new errors.ArgumentError("Queries array should not be empty")
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
await this._connect()
|
|
831
|
+
|
|
832
|
+
const execOptions = DefaultExecutionOptions.create(options, this)
|
|
833
|
+
let queryItems
|
|
834
|
+
|
|
835
|
+
if (execOptions.isPrepared()) {
|
|
836
|
+
// use keyspace from query options if protocol supports per-query keyspace, otherwise use connection keyspace.
|
|
837
|
+
const version = this.controlConnection.protocolVersion
|
|
838
|
+
const queryKeyspace =
|
|
839
|
+
(types.protocolVersion.supportsKeyspaceInRequest(version) &&
|
|
840
|
+
options.keyspace) ||
|
|
841
|
+
this.keyspace
|
|
842
|
+
queryItems = await PrepareHandler.getPreparedMultiple(
|
|
843
|
+
this,
|
|
844
|
+
execOptions.getLoadBalancingPolicy(),
|
|
845
|
+
queries,
|
|
846
|
+
queryKeyspace,
|
|
847
|
+
)
|
|
848
|
+
} else {
|
|
849
|
+
queryItems = new Array(queries.length)
|
|
850
|
+
|
|
851
|
+
for (let i = 0; i < queries.length; i++) {
|
|
852
|
+
const item = queries[i]
|
|
853
|
+
if (!item) {
|
|
854
|
+
throw new errors.ArgumentError(`Invalid query at index ${i}`)
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
const query = typeof item === "string" ? item : item.query
|
|
858
|
+
if (!query) {
|
|
859
|
+
throw new errors.ArgumentError(`Invalid query at index ${i}`)
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
queryItems[i] = { query, params: item.params }
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
const request = await this._createBatchRequest(queryItems, execOptions)
|
|
867
|
+
return await RequestHandler.send(request, execOptions, this)
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
/**
|
|
871
|
+
* Gets the host that are replicas of a given token.
|
|
872
|
+
* @param {String} keyspace
|
|
873
|
+
* @param {Buffer} token
|
|
874
|
+
* @returns {Array<Host>}
|
|
875
|
+
*/
|
|
876
|
+
Client.prototype.getReplicas = function (keyspace, token) {
|
|
877
|
+
return this.metadata.getReplicas(keyspace, token)
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
/**
|
|
881
|
+
* Gets a snapshot containing information on the connections pools held by this Client at the current time.
|
|
882
|
+
* <p>
|
|
883
|
+
* The information provided in the returned object only represents the state at the moment this method was called and
|
|
884
|
+
* it's not maintained in sync with the driver metadata.
|
|
885
|
+
* </p>
|
|
886
|
+
* @returns {ClientState} A [ClientState]{@linkcode module:metadata~ClientState} instance.
|
|
887
|
+
*/
|
|
888
|
+
Client.prototype.getState = function () {
|
|
889
|
+
return ClientState.from(this)
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
Client.prototype.log = utils.log
|
|
893
|
+
|
|
894
|
+
/**
|
|
895
|
+
* Closes all connections to all hosts.
|
|
896
|
+
* <p>It returns a <code>Promise</code> when a <code>callback</code> is not provided.</p>
|
|
897
|
+
* @param {Function} [callback] Optional callback to be invoked when finished closing all connections.
|
|
898
|
+
*/
|
|
899
|
+
Client.prototype.shutdown = function (callback) {
|
|
900
|
+
return promiseUtils.optionalCallback(this._shutdown(), callback)
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
/** @private */
|
|
904
|
+
Client.prototype._shutdown = async function () {
|
|
905
|
+
this.log("info", "Shutting down")
|
|
906
|
+
|
|
907
|
+
if (!this.hosts || !this.connected) {
|
|
908
|
+
// not initialized
|
|
909
|
+
this.connected = false
|
|
910
|
+
return
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
if (this.connecting) {
|
|
914
|
+
this.log("warning", "Shutting down while connecting")
|
|
915
|
+
// wait until finish connecting for easier troubleshooting
|
|
916
|
+
await promiseUtils.fromEvent(this, "connected")
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
this.connected = false
|
|
920
|
+
this.isShuttingDown = true
|
|
921
|
+
const hosts = this.hosts.values()
|
|
922
|
+
|
|
923
|
+
// Shutdown the ControlConnection before shutting down the pools
|
|
924
|
+
this.controlConnection.shutdown()
|
|
925
|
+
this.options.policies.speculativeExecution.shutdown()
|
|
926
|
+
|
|
927
|
+
if (this.options.requestTracker) {
|
|
928
|
+
this.options.requestTracker.shutdown()
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
// go through all the host and shut down their pools
|
|
932
|
+
await Promise.all(hosts.map((h) => h.shutdown(false)))
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
/**
|
|
936
|
+
* Waits until that the schema version in all nodes is the same or the waiting time passed.
|
|
937
|
+
* @param {Connection} connection
|
|
938
|
+
* @returns {Promise<boolean>}
|
|
939
|
+
* @ignore
|
|
940
|
+
*/
|
|
941
|
+
Client.prototype._waitForSchemaAgreement = async function (connection) {
|
|
942
|
+
if (this.hosts.length === 1) {
|
|
943
|
+
return true
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
const start = process.hrtime()
|
|
947
|
+
const maxWaitSeconds =
|
|
948
|
+
this.options.protocolOptions.maxSchemaAgreementWaitSeconds
|
|
949
|
+
|
|
950
|
+
this.log("info", "Waiting for schema agreement")
|
|
951
|
+
|
|
952
|
+
let versionsMatch
|
|
953
|
+
|
|
954
|
+
while (!versionsMatch && process.hrtime(start)[0] < maxWaitSeconds) {
|
|
955
|
+
versionsMatch = await this.metadata.compareSchemaVersions(connection)
|
|
956
|
+
|
|
957
|
+
if (versionsMatch) {
|
|
958
|
+
this.log("info", "Schema versions match")
|
|
959
|
+
break
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
// Let some time pass before the next check
|
|
963
|
+
await promiseUtils.delay(500)
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
return versionsMatch
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
/**
|
|
970
|
+
* Waits for schema agreements and schedules schema metadata refresh.
|
|
971
|
+
* @param {Connection} connection
|
|
972
|
+
* @param event
|
|
973
|
+
* @returns {Promise<boolean>}
|
|
974
|
+
* @ignore
|
|
975
|
+
* @internal
|
|
976
|
+
*/
|
|
977
|
+
Client.prototype.handleSchemaAgreementAndRefresh = async function (
|
|
978
|
+
connection,
|
|
979
|
+
event,
|
|
980
|
+
) {
|
|
981
|
+
let agreement = false
|
|
982
|
+
|
|
983
|
+
try {
|
|
984
|
+
agreement = await this._waitForSchemaAgreement(connection)
|
|
985
|
+
} catch (err) {
|
|
986
|
+
//we issue a warning but we continue with the normal flow
|
|
987
|
+
this.log(
|
|
988
|
+
"warning",
|
|
989
|
+
"There was an error while waiting for the schema agreement between nodes",
|
|
990
|
+
err,
|
|
991
|
+
)
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
if (!this.options.isMetadataSyncEnabled) {
|
|
995
|
+
return agreement
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
// Refresh metadata immediately
|
|
999
|
+
try {
|
|
1000
|
+
await this.controlConnection.handleSchemaChange(event, true)
|
|
1001
|
+
} catch (err) {
|
|
1002
|
+
this.log(
|
|
1003
|
+
"warning",
|
|
1004
|
+
"There was an error while handling schema change",
|
|
1005
|
+
err,
|
|
1006
|
+
)
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
return agreement
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
/**
|
|
1013
|
+
* Connects and handles the execution of prepared and simple statements.
|
|
1014
|
+
* @param {string} query
|
|
1015
|
+
* @param {Array} params
|
|
1016
|
+
* @param {ExecutionOptions} execOptions
|
|
1017
|
+
* @returns {Promise<ResultSet>}
|
|
1018
|
+
* @private
|
|
1019
|
+
*/
|
|
1020
|
+
Client.prototype._execute = async function (query, params, execOptions) {
|
|
1021
|
+
const version = this.controlConnection.protocolVersion
|
|
1022
|
+
|
|
1023
|
+
if (
|
|
1024
|
+
!execOptions.isPrepared() &&
|
|
1025
|
+
params &&
|
|
1026
|
+
!Array.isArray(params) &&
|
|
1027
|
+
!types.protocolVersion.supportsNamedParameters(version)
|
|
1028
|
+
) {
|
|
1029
|
+
// Only Cassandra 2.1 and above supports named parameters
|
|
1030
|
+
throw new errors.ArgumentError(
|
|
1031
|
+
"Named parameters for simple statements are not supported, use prepare flag",
|
|
1032
|
+
)
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
let request
|
|
1036
|
+
|
|
1037
|
+
if (!this.connected) {
|
|
1038
|
+
// Micro optimization to avoid an async execution for a simple check
|
|
1039
|
+
await this._connect()
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
if (!execOptions.isPrepared()) {
|
|
1043
|
+
request = await this._createQueryRequest(query, execOptions, params)
|
|
1044
|
+
} else {
|
|
1045
|
+
const lbp = execOptions.getLoadBalancingPolicy()
|
|
1046
|
+
|
|
1047
|
+
// Use keyspace from query options if protocol supports per-query keyspace, otherwise use connection keyspace.
|
|
1048
|
+
const queryKeyspace =
|
|
1049
|
+
(types.protocolVersion.supportsKeyspaceInRequest(version) &&
|
|
1050
|
+
execOptions.getKeyspace()) ||
|
|
1051
|
+
this.keyspace
|
|
1052
|
+
|
|
1053
|
+
const { queryId, meta } = await PrepareHandler.getPrepared(
|
|
1054
|
+
this,
|
|
1055
|
+
lbp,
|
|
1056
|
+
query,
|
|
1057
|
+
queryKeyspace,
|
|
1058
|
+
)
|
|
1059
|
+
request = await this._createExecuteRequest(
|
|
1060
|
+
query,
|
|
1061
|
+
queryId,
|
|
1062
|
+
execOptions,
|
|
1063
|
+
params,
|
|
1064
|
+
meta,
|
|
1065
|
+
)
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
return await RequestHandler.send(request, execOptions, this)
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
/**
|
|
1072
|
+
* Sets the listeners for the nodes.
|
|
1073
|
+
* @private
|
|
1074
|
+
*/
|
|
1075
|
+
Client.prototype._setHostListeners = function () {
|
|
1076
|
+
function getHostUpListener(emitter, h) {
|
|
1077
|
+
return () => emitter.emit("hostUp", h)
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
function getHostDownListener(emitter, h) {
|
|
1081
|
+
return () => emitter.emit("hostDown", h)
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
const self = this
|
|
1085
|
+
|
|
1086
|
+
// Add status listeners when new nodes are added and emit hostAdd
|
|
1087
|
+
this.hosts.on("add", function hostAddedListener(h) {
|
|
1088
|
+
h.on("up", getHostUpListener(self, h))
|
|
1089
|
+
h.on("down", getHostDownListener(self, h))
|
|
1090
|
+
self.emit("hostAdd", h)
|
|
1091
|
+
})
|
|
1092
|
+
|
|
1093
|
+
// Remove all listeners and emit hostRemove
|
|
1094
|
+
this.hosts.on("remove", function hostRemovedListener(h) {
|
|
1095
|
+
h.removeAllListeners()
|
|
1096
|
+
self.emit("hostRemove", h)
|
|
1097
|
+
})
|
|
1098
|
+
|
|
1099
|
+
// Add status listeners for existing hosts
|
|
1100
|
+
this.hosts.forEach(function (h) {
|
|
1101
|
+
h.on("up", getHostUpListener(self, h))
|
|
1102
|
+
h.on("down", getHostDownListener(self, h))
|
|
1103
|
+
})
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
/**
|
|
1107
|
+
* Sets the distance to each host and when warmup is true, creates all connections to local hosts.
|
|
1108
|
+
* @returns {Promise}
|
|
1109
|
+
* @private
|
|
1110
|
+
*/
|
|
1111
|
+
Client.prototype._warmup = function () {
|
|
1112
|
+
const hosts = this.hosts.values()
|
|
1113
|
+
|
|
1114
|
+
return promiseUtils.times(hosts.length, warmupLimit, async (index) => {
|
|
1115
|
+
const h = hosts[index]
|
|
1116
|
+
const distance = this.profileManager.getDistance(h)
|
|
1117
|
+
|
|
1118
|
+
if (distance === types.distance.ignored) {
|
|
1119
|
+
return
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
if (this.options.pooling.warmup && distance === types.distance.local) {
|
|
1123
|
+
try {
|
|
1124
|
+
await h.warmupPool(this.keyspace)
|
|
1125
|
+
} catch (err) {
|
|
1126
|
+
// An error while trying to create a connection to one of the hosts.
|
|
1127
|
+
// Warn the user and move on.
|
|
1128
|
+
this.log(
|
|
1129
|
+
"warning",
|
|
1130
|
+
`Connection pool to host ${h.address} could not be created: ${err}`,
|
|
1131
|
+
err,
|
|
1132
|
+
)
|
|
1133
|
+
}
|
|
1134
|
+
} else {
|
|
1135
|
+
h.initializePool()
|
|
1136
|
+
}
|
|
1137
|
+
})
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
/**
|
|
1141
|
+
* @returns {Encoder}
|
|
1142
|
+
* @private
|
|
1143
|
+
*/
|
|
1144
|
+
Client.prototype._getEncoder = function () {
|
|
1145
|
+
const encoder = this.controlConnection.getEncoder()
|
|
1146
|
+
if (!encoder) {
|
|
1147
|
+
throw new errors.DriverInternalError("Encoder is not defined")
|
|
1148
|
+
}
|
|
1149
|
+
return encoder
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
/**
|
|
1153
|
+
* Returns a BatchRequest instance and fills the routing key information in the provided options.
|
|
1154
|
+
* @private
|
|
1155
|
+
*/
|
|
1156
|
+
Client.prototype._createBatchRequest = async function (queryItems, info) {
|
|
1157
|
+
const firstQuery = queryItems[0]
|
|
1158
|
+
if (!firstQuery.meta) {
|
|
1159
|
+
return new requests.BatchRequest(queryItems, info)
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
await this._setRoutingInfo(info, firstQuery.params, firstQuery.meta)
|
|
1163
|
+
return new requests.BatchRequest(queryItems, info)
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
/**
|
|
1167
|
+
* Returns an ExecuteRequest instance and fills the routing key information in the provided options.
|
|
1168
|
+
* @private
|
|
1169
|
+
*/
|
|
1170
|
+
Client.prototype._createExecuteRequest = async function (
|
|
1171
|
+
query,
|
|
1172
|
+
queryId,
|
|
1173
|
+
info,
|
|
1174
|
+
params,
|
|
1175
|
+
meta,
|
|
1176
|
+
) {
|
|
1177
|
+
params = utils.adaptNamedParamsPrepared(params, meta.columns)
|
|
1178
|
+
await this._setRoutingInfo(info, params, meta)
|
|
1179
|
+
return new requests.ExecuteRequest(query, queryId, params, info, meta)
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
/**
|
|
1183
|
+
* Returns a QueryRequest instance and fills the routing key information in the provided options.
|
|
1184
|
+
* @private
|
|
1185
|
+
*/
|
|
1186
|
+
Client.prototype._createQueryRequest = async function (
|
|
1187
|
+
query,
|
|
1188
|
+
execOptions,
|
|
1189
|
+
params,
|
|
1190
|
+
) {
|
|
1191
|
+
await this.metadata.adaptUserHints(this.keyspace, execOptions.getHints())
|
|
1192
|
+
const paramsInfo = utils.adaptNamedParamsWithHints(params, execOptions)
|
|
1193
|
+
this._getEncoder().setRoutingKeyFromUser(
|
|
1194
|
+
paramsInfo.params,
|
|
1195
|
+
execOptions,
|
|
1196
|
+
paramsInfo.keyIndexes,
|
|
1197
|
+
)
|
|
1198
|
+
|
|
1199
|
+
return new requests.QueryRequest(
|
|
1200
|
+
query,
|
|
1201
|
+
paramsInfo.params,
|
|
1202
|
+
execOptions,
|
|
1203
|
+
paramsInfo.namedParameters,
|
|
1204
|
+
)
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
/**
|
|
1208
|
+
* Sets the routing key based on the parameter values or the provided routing key components.
|
|
1209
|
+
* @param {ExecutionOptions} execOptions
|
|
1210
|
+
* @param {Array} params
|
|
1211
|
+
* @param meta
|
|
1212
|
+
* @private
|
|
1213
|
+
*/
|
|
1214
|
+
Client.prototype._setRoutingInfo = async function (execOptions, params, meta) {
|
|
1215
|
+
const encoder = this._getEncoder()
|
|
1216
|
+
|
|
1217
|
+
if (!execOptions.getKeyspace() && meta.keyspace) {
|
|
1218
|
+
execOptions.setKeyspace(meta.keyspace)
|
|
1219
|
+
}
|
|
1220
|
+
if (execOptions.getRoutingKey()) {
|
|
1221
|
+
// Routing information provided by the user
|
|
1222
|
+
return encoder.setRoutingKeyFromUser(params, execOptions)
|
|
1223
|
+
}
|
|
1224
|
+
if (Array.isArray(meta.partitionKeys)) {
|
|
1225
|
+
// The partition keys are provided as part of the metadata for modern protocol versions
|
|
1226
|
+
execOptions.setRoutingIndexes(meta.partitionKeys)
|
|
1227
|
+
return encoder.setRoutingKeyFromMeta(meta, params, execOptions)
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
// Older versions of the protocol (v3 and below) don't provide routing information
|
|
1231
|
+
try {
|
|
1232
|
+
const tableInfo = await this.metadata.getTable(
|
|
1233
|
+
meta.keyspace,
|
|
1234
|
+
meta.table,
|
|
1235
|
+
)
|
|
1236
|
+
|
|
1237
|
+
if (!tableInfo) {
|
|
1238
|
+
// The schema data is not there, maybe it is being recreated, avoid setting the routing information
|
|
1239
|
+
return
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
execOptions.setRoutingIndexes(
|
|
1243
|
+
tableInfo.partitionKeys.map((c) => meta.columnsByName[c.name]),
|
|
1244
|
+
)
|
|
1245
|
+
// Skip parsing metadata next time
|
|
1246
|
+
meta.partitionKeys = execOptions.getRoutingIndexes()
|
|
1247
|
+
encoder.setRoutingKeyFromMeta(meta, params, execOptions)
|
|
1248
|
+
} catch (err) {
|
|
1249
|
+
this.log(
|
|
1250
|
+
"warning",
|
|
1251
|
+
util.format(
|
|
1252
|
+
"Table %s.%s metadata could not be retrieved",
|
|
1253
|
+
meta.keyspace,
|
|
1254
|
+
meta.table,
|
|
1255
|
+
),
|
|
1256
|
+
)
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
/**
|
|
1261
|
+
* Callback used by execution methods.
|
|
1262
|
+
* @callback ResultCallback
|
|
1263
|
+
* @param {Error} err Error occurred in the execution of the query.
|
|
1264
|
+
* @param {ResultSet} [result] Result of the execution of the query.
|
|
1265
|
+
*/
|
|
1266
|
+
|
|
1267
|
+
export default Client
|