@ragestudio/scylla-odm 0.22.2 → 0.22.4

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.
Files changed (153) hide show
  1. package/batch/index.d.ts +3 -3
  2. package/batch/index.d.ts.map +1 -1
  3. package/client.d.ts +6 -5
  4. package/client.d.ts.map +1 -1
  5. package/client.js +11 -12
  6. package/client.js.map +1 -1
  7. package/cql_gen/create_table.d.ts +1 -1
  8. package/cql_gen/create_table.d.ts.map +1 -1
  9. package/document/index.d.ts +3 -3
  10. package/document/index.d.ts.map +1 -1
  11. package/driver/LICENSE.txt +177 -0
  12. package/driver/NOTICE.txt +67 -0
  13. package/driver/auth/index.d.ts +37 -0
  14. package/driver/auth/index.js +37 -0
  15. package/driver/auth/no-auth-provider.js +73 -0
  16. package/driver/auth/plain-text-auth-provider.js +81 -0
  17. package/driver/auth/provider.js +77 -0
  18. package/driver/client-options.js +442 -0
  19. package/driver/client.js +1267 -0
  20. package/driver/concurrent/index.d.ts +49 -0
  21. package/driver/concurrent/index.js +366 -0
  22. package/driver/connection.js +1034 -0
  23. package/driver/control-connection.js +1282 -0
  24. package/driver/encoder.js +2316 -0
  25. package/driver/errors.js +223 -0
  26. package/driver/execution-options.js +612 -0
  27. package/driver/execution-profile.js +274 -0
  28. package/driver/host-connection-pool.js +587 -0
  29. package/driver/host.js +699 -0
  30. package/driver/index.d.ts +387 -0
  31. package/driver/index.js +81 -0
  32. package/driver/mapping/cache.js +214 -0
  33. package/driver/mapping/doc-info-adapter.js +171 -0
  34. package/driver/mapping/index.d.ts +219 -0
  35. package/driver/mapping/index.js +57 -0
  36. package/driver/mapping/mapper.js +225 -0
  37. package/driver/mapping/mapping-handler.js +641 -0
  38. package/driver/mapping/model-batch-item.js +215 -0
  39. package/driver/mapping/model-batch-mapper.js +141 -0
  40. package/driver/mapping/model-mapper.js +315 -0
  41. package/driver/mapping/model-mapping-info.js +225 -0
  42. package/driver/mapping/object-selector.js +417 -0
  43. package/driver/mapping/q.js +156 -0
  44. package/driver/mapping/query-generator.js +556 -0
  45. package/driver/mapping/result-mapper.js +123 -0
  46. package/driver/mapping/result.js +139 -0
  47. package/driver/mapping/table-mappings.js +133 -0
  48. package/driver/mapping/tree.js +160 -0
  49. package/driver/metadata/aggregate.js +79 -0
  50. package/driver/metadata/client-state.js +119 -0
  51. package/driver/metadata/data-collection.js +182 -0
  52. package/driver/metadata/event-debouncer.js +174 -0
  53. package/driver/metadata/index.d.ts +276 -0
  54. package/driver/metadata/index.js +1156 -0
  55. package/driver/metadata/materialized-view.js +49 -0
  56. package/driver/metadata/schema-function.js +98 -0
  57. package/driver/metadata/schema-index.js +166 -0
  58. package/driver/metadata/schema-parser.js +1399 -0
  59. package/driver/metadata/table-metadata.js +77 -0
  60. package/driver/operation-state.js +206 -0
  61. package/driver/policies/address-resolution.js +145 -0
  62. package/driver/policies/index.d.ts +241 -0
  63. package/driver/policies/index.js +110 -0
  64. package/driver/policies/load-balancing.js +970 -0
  65. package/driver/policies/reconnection.js +166 -0
  66. package/driver/policies/retry.js +326 -0
  67. package/driver/policies/speculative-execution.js +150 -0
  68. package/driver/policies/timestamp-generation.js +176 -0
  69. package/driver/prepare-handler.js +347 -0
  70. package/driver/promise-utils.js +191 -0
  71. package/driver/readers.js +624 -0
  72. package/driver/request-execution.js +644 -0
  73. package/driver/request-handler.js +332 -0
  74. package/driver/requests.js +618 -0
  75. package/driver/stream-id-stack.js +209 -0
  76. package/driver/streams.js +745 -0
  77. package/driver/token.js +325 -0
  78. package/driver/tokenizer.js +631 -0
  79. package/driver/types/big-decimal.js +282 -0
  80. package/driver/types/duration.js +576 -0
  81. package/driver/types/index.d.ts +486 -0
  82. package/driver/types/index.js +733 -0
  83. package/driver/types/inet-address.js +262 -0
  84. package/driver/types/integer.js +818 -0
  85. package/driver/types/local-date.js +280 -0
  86. package/driver/types/local-time.js +299 -0
  87. package/driver/types/mutable-long.js +385 -0
  88. package/driver/types/protocol-version.js +391 -0
  89. package/driver/types/result-set.js +287 -0
  90. package/driver/types/result-stream.js +164 -0
  91. package/driver/types/row.js +85 -0
  92. package/driver/types/time-uuid.js +414 -0
  93. package/driver/types/tuple.js +103 -0
  94. package/driver/types/uuid.js +160 -0
  95. package/driver/types/vector.js +130 -0
  96. package/driver/types/version-number.js +153 -0
  97. package/driver/utils.js +1485 -0
  98. package/driver/writers.js +350 -0
  99. package/global.d.ts +1 -1
  100. package/global.d.ts.map +1 -1
  101. package/index.d.ts +6 -6
  102. package/index.d.ts.map +1 -1
  103. package/index.js +6 -6
  104. package/index.js.map +1 -1
  105. package/migrate/index.d.ts +1 -1
  106. package/migrate/index.d.ts.map +1 -1
  107. package/migrate/index.js +1 -1
  108. package/migrate/index.js.map +1 -1
  109. package/model/index.d.ts +6 -6
  110. package/model/index.d.ts.map +1 -1
  111. package/model/index.js +10 -10
  112. package/model/index.js.map +1 -1
  113. package/operations/countAll.d.ts +1 -1
  114. package/operations/countAll.d.ts.map +1 -1
  115. package/operations/delete.d.ts +3 -4
  116. package/operations/delete.d.ts.map +1 -1
  117. package/operations/delete.js +1 -1
  118. package/operations/delete.js.map +1 -1
  119. package/operations/find.d.ts +2 -2
  120. package/operations/find.d.ts.map +1 -1
  121. package/operations/find.js +1 -1
  122. package/operations/find.js.map +1 -1
  123. package/operations/findOne.d.ts +2 -2
  124. package/operations/findOne.d.ts.map +1 -1
  125. package/operations/findOne.js +1 -1
  126. package/operations/findOne.js.map +1 -1
  127. package/operations/insert.d.ts +3 -3
  128. package/operations/insert.d.ts.map +1 -1
  129. package/operations/insert.js +2 -2
  130. package/operations/insert.js.map +1 -1
  131. package/operations/sync.d.ts +1 -1
  132. package/operations/sync.d.ts.map +1 -1
  133. package/operations/sync.js +1 -1
  134. package/operations/sync.js.map +1 -1
  135. package/operations/tableExists.d.ts +1 -1
  136. package/operations/tableExists.d.ts.map +1 -1
  137. package/operations/update.d.ts +3 -3
  138. package/operations/update.d.ts.map +1 -1
  139. package/operations/update.js +2 -2
  140. package/operations/update.js.map +1 -1
  141. package/package.json +4 -12
  142. package/schema/index.d.ts +1 -1
  143. package/schema/index.d.ts.map +1 -1
  144. package/types.d.ts +4 -4
  145. package/types.d.ts.map +1 -1
  146. package/utils/queryParser.d.ts +1 -1
  147. package/utils/queryParser.d.ts.map +1 -1
  148. package/utils/queryParser.js +1 -1
  149. package/utils/queryParser.js.map +1 -1
  150. package/utils/typeChecker.d.ts +1 -1
  151. package/utils/typeChecker.d.ts.map +1 -1
  152. package/utils/typeChecker.js +1 -1
  153. package/utils/typeChecker.js.map +1 -1
@@ -0,0 +1,176 @@
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 util from "util"
19
+ import { Long } from "../types/index.js"
20
+ import errors from "../errors.js"
21
+
22
+ /** @module policies/timestampGeneration */
23
+
24
+ /**
25
+ * Defines the maximum date in milliseconds that can be represented in microseconds using Number ((2 ^ 53) / 1000)
26
+ * @const
27
+ * @private
28
+ */
29
+ const _maxSafeNumberDate = 9007199254740
30
+
31
+ /**
32
+ * A long representing the value 1000
33
+ * @const
34
+ * @private
35
+ */
36
+ const _longOneThousand = Long.fromInt(1000)
37
+
38
+ /**
39
+ * Creates a new instance of {@link TimestampGenerator}.
40
+ * @classdesc
41
+ * Generates client-side, microsecond-precision query timestamps.
42
+ * <p>
43
+ * Given that Cassandra uses those timestamps to resolve conflicts, implementations should generate
44
+ * monotonically increasing timestamps for successive invocations of {@link TimestampGenerator.next()}.
45
+ * </p>
46
+ * @constructor
47
+ */
48
+ function TimestampGenerator() {}
49
+
50
+ /**
51
+ * Returns the next timestamp.
52
+ * <p>
53
+ * Implementors should enforce increasing monotonicity of timestamps, that is,
54
+ * a timestamp returned should always be strictly greater that any previously returned
55
+ * timestamp.
56
+ * <p/>
57
+ * <p>
58
+ * Implementors should strive to achieve microsecond precision in the best possible way,
59
+ * which is usually largely dependent on the underlying operating system's capabilities.
60
+ * </p>
61
+ * @param {Client} client The {@link Client} instance to generate timestamps to.
62
+ * @returns {Long|Number|null} the next timestamp (in microseconds). If it's equals to <code>null</code>, it won't be
63
+ * sent by the driver, letting the server to generate the timestamp.
64
+ * @abstract
65
+ */
66
+ TimestampGenerator.prototype.next = function (client) {
67
+ throw new Error("next() must be implemented")
68
+ }
69
+
70
+ /**
71
+ * A timestamp generator that guarantees monotonically increasing timestamps and logs warnings when timestamps
72
+ * drift in the future.
73
+ * <p>
74
+ * {@link Date} has millisecond precision and client timestamps require microsecond precision. This generator
75
+ * keeps track of the last generated timestamp, and if the current time is within the same millisecond as the last,
76
+ * it fills the microsecond portion of the new timestamp with the value of an incrementing counter.
77
+ * </p>
78
+ * @param {Number} [warningThreshold] Determines how far in the future timestamps are allowed to drift before a
79
+ * warning is logged, expressed in milliseconds. Default: <code>1000</code>.
80
+ * @param {Number} [minLogInterval] In case of multiple log events, it determines the time separation between log
81
+ * events, expressed in milliseconds. Use 0 to disable. Default: <code>1000</code>.
82
+ * @extends {TimestampGenerator}
83
+ * @constructor
84
+ */
85
+ function MonotonicTimestampGenerator(warningThreshold, minLogInterval) {
86
+ if (warningThreshold < 0) {
87
+ throw new errors.ArgumentError(
88
+ "warningThreshold can not be lower than 0",
89
+ )
90
+ }
91
+ this._warningThreshold = warningThreshold || 1000
92
+ this._minLogInterval = 1000
93
+ if (typeof minLogInterval === "number") {
94
+ // A value under 1 will disable logging
95
+ this._minLogInterval = minLogInterval
96
+ }
97
+ this._micros = -1
98
+ this._lastDate = 0
99
+ this._lastLogDate = 0
100
+ }
101
+
102
+ util.inherits(MonotonicTimestampGenerator, TimestampGenerator)
103
+
104
+ /**
105
+ * Returns the current time in milliseconds since UNIX epoch
106
+ * @returns {Number}
107
+ */
108
+ MonotonicTimestampGenerator.prototype.getDate = function () {
109
+ return Date.now()
110
+ }
111
+
112
+ MonotonicTimestampGenerator.prototype.next = function (client) {
113
+ let date = this.getDate()
114
+ let drifted = 0
115
+ if (date > this._lastDate) {
116
+ this._micros = 0
117
+ this._lastDate = date
118
+ return this._generateMicroseconds()
119
+ }
120
+
121
+ if (date < this._lastDate) {
122
+ drifted = this._lastDate - date
123
+ date = this._lastDate
124
+ }
125
+ if (++this._micros === 1000) {
126
+ this._micros = 0
127
+ if (date === this._lastDate) {
128
+ // Move date 1 millisecond into the future
129
+ date++
130
+ drifted++
131
+ }
132
+ }
133
+ const lastDate = this._lastDate
134
+ this._lastDate = date
135
+ const result = this._generateMicroseconds()
136
+ if (drifted >= this._warningThreshold) {
137
+ // Avoid logging an unbounded amount of times within a clock-skew event or during an interval when more than 1
138
+ // query is being issued by microsecond
139
+ const currentLogDate = Date.now()
140
+ if (
141
+ this._minLogInterval > 0 &&
142
+ this._lastLogDate + this._minLogInterval <= currentLogDate
143
+ ) {
144
+ const message = util.format(
145
+ "Timestamp generated using current date was %d milliseconds behind the last generated timestamp (which " +
146
+ "millisecond portion was %d), the returned value (%s) is being artificially incremented to guarantee " +
147
+ "monotonicity.",
148
+ drifted,
149
+ lastDate,
150
+ result,
151
+ )
152
+ this._lastLogDate = currentLogDate
153
+ client.log("warning", message)
154
+ }
155
+ }
156
+ return result
157
+ }
158
+
159
+ /**
160
+ * @private
161
+ * @returns {Number|Long}
162
+ */
163
+ MonotonicTimestampGenerator.prototype._generateMicroseconds = function () {
164
+ if (this._lastDate < _maxSafeNumberDate) {
165
+ // We are safe until Jun 06 2255, its faster to perform this operations on Number than on Long
166
+ // We hope to have native int64 by then :)
167
+ return this._lastDate * 1000 + this._micros
168
+ }
169
+ return Long.fromNumber(this._lastDate)
170
+ .multiply(_longOneThousand)
171
+ .add(Long.fromInt(this._micros))
172
+ }
173
+
174
+ export { TimestampGenerator, MonotonicTimestampGenerator }
175
+
176
+ export default { TimestampGenerator, MonotonicTimestampGenerator }
@@ -0,0 +1,347 @@
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 errors from "./errors.js"
19
+ import utils from "./utils.js"
20
+ import types from "./types/index.js"
21
+ import promiseUtils from "./promise-utils.js"
22
+
23
+ /**
24
+ * Encapsulates the logic for dealing with the different prepare request and response flows, including failover when
25
+ * trying to prepare a query.
26
+ */
27
+ class PrepareHandler {
28
+ /**
29
+ * Creates a new instance of PrepareHandler
30
+ * @param {Client} client
31
+ * @param {LoadBalancingPolicy} loadBalancing
32
+ */
33
+ constructor(client, loadBalancing) {
34
+ this._client = client
35
+ this._loadBalancing = loadBalancing
36
+ this.logEmitter = client.options.logEmitter
37
+ this.log = utils.log
38
+ }
39
+
40
+ /**
41
+ * Gets the query id and metadata for a prepared statement, preparing it on
42
+ * single host or on all hosts depending on the options.
43
+ * @param {Client} client
44
+ * @param {LoadBalancingPolicy} loadBalancing
45
+ * @param {String} query
46
+ * @param {String} keyspace
47
+ * @returns {Promise<{queryId, meta}>}
48
+ * @static
49
+ */
50
+ static async getPrepared(client, loadBalancing, query, keyspace) {
51
+ const info = client.metadata.getPreparedInfo(keyspace, query)
52
+ if (info.queryId) {
53
+ return info
54
+ }
55
+
56
+ if (info.preparing) {
57
+ // It's already being prepared
58
+ return await promiseUtils.fromEvent(info, "prepared")
59
+ }
60
+
61
+ const instance = new PrepareHandler(client, loadBalancing)
62
+ return await instance._prepare(info, query, keyspace)
63
+ }
64
+
65
+ /**
66
+ * @param {Client} client
67
+ * @param {LoadBalancingPolicy} loadBalancing
68
+ * @param {Array} queries
69
+ * @param {String} keyspace
70
+ * @static
71
+ */
72
+ static async getPreparedMultiple(client, loadBalancing, queries, keyspace) {
73
+ const result = []
74
+
75
+ for (const item of queries) {
76
+ let query
77
+
78
+ if (item) {
79
+ query = typeof item === "string" ? item : item.query
80
+ }
81
+
82
+ if (typeof query !== "string") {
83
+ throw new errors.ArgumentError("Query item should be a string")
84
+ }
85
+
86
+ const { queryId, meta } = await PrepareHandler.getPrepared(
87
+ client,
88
+ loadBalancing,
89
+ query,
90
+ keyspace,
91
+ )
92
+ result.push({
93
+ query,
94
+ params: utils.adaptNamedParamsPrepared(
95
+ item.params,
96
+ meta.columns,
97
+ ),
98
+ queryId,
99
+ meta,
100
+ })
101
+ }
102
+
103
+ return result
104
+ }
105
+
106
+ /**
107
+ * Prepares the query on a single host or on all hosts depending on the options.
108
+ * Uses the info 'prepared' event to emit the result.
109
+ * @param {Object} info
110
+ * @param {String} query
111
+ * @param {String} keyspace
112
+ * @returns {Promise<{queryId, meta}>}
113
+ */
114
+ async _prepare(info, query, keyspace) {
115
+ info.preparing = true
116
+ let iterator
117
+
118
+ try {
119
+ iterator = await promiseUtils.newQueryPlan(
120
+ this._loadBalancing,
121
+ keyspace,
122
+ null,
123
+ )
124
+ return await this._prepareWithQueryPlan(
125
+ info,
126
+ iterator,
127
+ query,
128
+ keyspace,
129
+ )
130
+ } catch (err) {
131
+ info.preparing = false
132
+ err.query = query
133
+ info.emit("prepared", err)
134
+
135
+ throw err
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Uses the query plan to prepare the query on the first host and optionally on the rest of the hosts.
141
+ * @param {Object} info
142
+ * @param {Iterator} iterator
143
+ * @param {String} query
144
+ * @param {String} keyspace
145
+ * @returns {Promise<{queryId, meta}>}
146
+ * @private
147
+ */
148
+ async _prepareWithQueryPlan(info, iterator, query, keyspace) {
149
+ const triedHosts = {}
150
+
151
+ while (true) {
152
+ const host = PrepareHandler.getNextHost(
153
+ iterator,
154
+ this._client.profileManager,
155
+ triedHosts,
156
+ )
157
+
158
+ if (host === null) {
159
+ throw new errors.NoHostAvailableError(triedHosts)
160
+ }
161
+
162
+ try {
163
+ const connection = await PrepareHandler._borrowWithKeyspace(
164
+ host,
165
+ keyspace,
166
+ )
167
+ const response = await connection.prepareOnceAsync(
168
+ query,
169
+ keyspace,
170
+ )
171
+
172
+ if (this._client.options.prepareOnAllHosts) {
173
+ await this._prepareOnAllHosts(iterator, query, keyspace)
174
+ }
175
+
176
+ // Set the prepared metadata
177
+ info.preparing = false
178
+ info.queryId = response.id
179
+ info.meta = response.meta
180
+ this._client.metadata.setPreparedById(info)
181
+ info.emit("prepared", null, info)
182
+
183
+ return info
184
+ } catch (err) {
185
+ triedHosts[host.address] = err
186
+
187
+ if (
188
+ !err.isSocketError &&
189
+ !(err instanceof errors.OperationTimedOutError)
190
+ ) {
191
+ // There's no point in retrying syntax errors and other response errors
192
+ throw err
193
+ }
194
+ }
195
+ }
196
+ }
197
+
198
+ /**
199
+ * Gets the next host from the query plan.
200
+ * @param {Iterator} iterator
201
+ * @param {ProfileManager} profileManager
202
+ * @param {Object} [triedHosts]
203
+ * @return {Host|null}
204
+ */
205
+ static getNextHost(iterator, profileManager, triedHosts) {
206
+ let host
207
+ // Get a host that is UP in a sync loop
208
+ while (true) {
209
+ const item = iterator.next()
210
+ if (item.done) {
211
+ return null
212
+ }
213
+
214
+ host = item.value
215
+
216
+ // set the distance relative to the client first
217
+ const distance = profileManager.getDistance(host)
218
+ if (distance === types.distance.ignored) {
219
+ //If its marked as ignore by the load balancing policy, move on.
220
+ continue
221
+ }
222
+
223
+ if (host.isUp()) {
224
+ break
225
+ }
226
+
227
+ if (triedHosts) {
228
+ triedHosts[host.address] = "Host considered as DOWN"
229
+ }
230
+ }
231
+
232
+ return host
233
+ }
234
+
235
+ /**
236
+ * Prepares all queries on a single host.
237
+ * @param {Host} host
238
+ * @param {Array} allPrepared
239
+ */
240
+ static async prepareAllQueries(host, allPrepared) {
241
+ const anyKeyspaceQueries = []
242
+
243
+ const queriesByKeyspace = new Map()
244
+ allPrepared.forEach((info) => {
245
+ let arr
246
+ if (info.keyspace) {
247
+ arr = queriesByKeyspace.get(info.keyspace)
248
+
249
+ if (!arr) {
250
+ arr = []
251
+ queriesByKeyspace.set(info.keyspace, arr)
252
+ }
253
+ } else {
254
+ arr = anyKeyspaceQueries
255
+ }
256
+
257
+ arr.push(info.query)
258
+ })
259
+
260
+ for (const [keyspace, queries] of queriesByKeyspace) {
261
+ await PrepareHandler._borrowAndPrepare(host, keyspace, queries)
262
+ }
263
+
264
+ await PrepareHandler._borrowAndPrepare(host, null, anyKeyspaceQueries)
265
+ }
266
+
267
+ /**
268
+ * Borrows a connection from the host and prepares the queries provided.
269
+ * @param {Host} host
270
+ * @param {String} keyspace
271
+ * @param {Array} queries
272
+ * @returns {Promise<void>}
273
+ * @private
274
+ */
275
+ static async _borrowAndPrepare(host, keyspace, queries) {
276
+ if (queries.length === 0) {
277
+ return
278
+ }
279
+
280
+ const connection = await PrepareHandler._borrowWithKeyspace(
281
+ host,
282
+ keyspace,
283
+ )
284
+
285
+ for (const query of queries) {
286
+ await connection.prepareOnceAsync(query, keyspace)
287
+ }
288
+ }
289
+
290
+ /**
291
+ * Borrows a connection and changes the active keyspace on the connection, if needed.
292
+ * It does not perform any retry or error handling.
293
+ * @param {Host!} host
294
+ * @param {string} keyspace
295
+ * @returns {Promise<Connection>}
296
+ * @throws {errors.BusyConnectionError} When the connection is busy.
297
+ * @throws {errors.ResponseError} For invalid keyspaces.
298
+ * @throws {Error} For socket errors.
299
+ * @private
300
+ */
301
+ static async _borrowWithKeyspace(host, keyspace) {
302
+ const connection = host.borrowConnection()
303
+
304
+ if (keyspace && connection.keyspace !== keyspace) {
305
+ await connection.changeKeyspace(keyspace)
306
+ }
307
+
308
+ return connection
309
+ }
310
+
311
+ /**
312
+ * Prepares the provided query on all hosts, except the host provided.
313
+ * @param {Iterator} iterator
314
+ * @param {String} query
315
+ * @param {String} keyspace
316
+ * @private
317
+ */
318
+ _prepareOnAllHosts(iterator, query, keyspace) {
319
+ const queries = [query]
320
+ let h
321
+ const hosts = []
322
+
323
+ while (
324
+ (h = PrepareHandler.getNextHost(
325
+ iterator,
326
+ this._client.profileManager,
327
+ )) !== null
328
+ ) {
329
+ hosts.push(h)
330
+ }
331
+
332
+ return Promise.all(
333
+ hosts.map((h) =>
334
+ PrepareHandler._borrowAndPrepare(h, keyspace, queries).catch(
335
+ (err) =>
336
+ this.log(
337
+ "verbose",
338
+ `Unexpected error while preparing query (${query}) on ${h.address}`,
339
+ err,
340
+ ),
341
+ ),
342
+ ),
343
+ )
344
+ }
345
+ }
346
+
347
+ export default PrepareHandler
@@ -0,0 +1,191 @@
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
+
19
+ /**
20
+ * Creates a non-clearable timer that resolves the promise once elapses.
21
+ * @param {number} ms
22
+ * @returns {Promise<void>}
23
+ */
24
+ function delay(ms) {
25
+ return new Promise((r) => setTimeout(r, ms || 0))
26
+ }
27
+
28
+ /**
29
+ * Creates a Promise that gets resolved or rejected based on an event.
30
+ * @param {object} emitter
31
+ * @param {string} eventName
32
+ * @returns {Promise}
33
+ */
34
+ function fromEvent(emitter, eventName) {
35
+ return new Promise((resolve, reject) =>
36
+ emitter.once(eventName, (err, result) => {
37
+ if (err) {
38
+ reject(err)
39
+ } else {
40
+ resolve(result)
41
+ }
42
+ }),
43
+ )
44
+ }
45
+
46
+ /**
47
+ * Creates a Promise from a callback based function.
48
+ * @param {Function} fn
49
+ * @returns {Promise}
50
+ */
51
+ function fromCallback(fn) {
52
+ return new Promise((resolve, reject) =>
53
+ fn((err, result) => {
54
+ if (err) {
55
+ reject(err)
56
+ } else {
57
+ resolve(result)
58
+ }
59
+ }),
60
+ )
61
+ }
62
+
63
+ /**
64
+ * Gets a function that has the signature of a callback that invokes the appropriate promise handler parameters.
65
+ * @param {Function} resolve
66
+ * @param {Function} reject
67
+ * @returns {Function}
68
+ */
69
+ function getCallback(resolve, reject) {
70
+ return function (err, result) {
71
+ if (err) {
72
+ reject(err)
73
+ } else {
74
+ resolve(result)
75
+ }
76
+ }
77
+ }
78
+
79
+ async function invokeSequentially(info, length, fn) {
80
+ let index
81
+ while ((index = info.counter++) < length) {
82
+ await fn(index)
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Invokes the new query plan of the load balancing policy and returns a Promise.
88
+ * @param {LoadBalancingPolicy} lbp The load balancing policy.
89
+ * @param {String} keyspace Name of currently logged keyspace at <code>Client</code> level.
90
+ * @param {ExecutionOptions|null} executionOptions The information related to the execution of the request.
91
+ * @returns {Promise<Iterator>}
92
+ */
93
+ function newQueryPlan(lbp, keyspace, executionOptions) {
94
+ return new Promise((resolve, reject) => {
95
+ lbp.newQueryPlan(keyspace, executionOptions, (err, iterator) => {
96
+ if (err) {
97
+ reject(err)
98
+ } else {
99
+ resolve(iterator)
100
+ }
101
+ })
102
+ })
103
+ }
104
+
105
+ /**
106
+ * Method that handles optional callbacks (dual promise and callback support).
107
+ * When callback is undefined it returns the promise.
108
+ * When using a callback, it will use it as handlers of the continuation of the promise.
109
+ * @param {Promise} promise
110
+ * @param {Function?} callback
111
+ * @returns {Promise|undefined}
112
+ */
113
+ function optionalCallback(promise, callback) {
114
+ if (!callback) {
115
+ return promise
116
+ }
117
+
118
+ toCallback(promise, callback)
119
+ }
120
+
121
+ /**
122
+ * Invokes the provided function multiple times, considering the concurrency level limit.
123
+ * @param {Number} count
124
+ * @param {Number} limit
125
+ * @param {Function} fn
126
+ * @returns {Promise}
127
+ */
128
+ function times(count, limit, fn) {
129
+ if (limit > count) {
130
+ limit = count
131
+ }
132
+
133
+ const promises = new Array(limit)
134
+
135
+ const info = {
136
+ counter: 0,
137
+ }
138
+
139
+ for (let i = 0; i < limit; i++) {
140
+ promises[i] = invokeSequentially(info, count, fn)
141
+ }
142
+
143
+ return Promise.all(promises)
144
+ }
145
+
146
+ /**
147
+ * Deals with unexpected rejections in order to avoid the unhandled promise rejection warning or failure.
148
+ * @param {Promise} promise
149
+ * @returns {undefined}
150
+ */
151
+ function toBackground(promise) {
152
+ promise.catch(() => {})
153
+ }
154
+
155
+ /**
156
+ * Invokes the callback once outside the promise chain the promise is resolved or rejected.
157
+ * @param {Promise} promise
158
+ * @param {Function?} callback
159
+ * @returns {undefined}
160
+ */
161
+ function toCallback(promise, callback) {
162
+ promise.then(
163
+ (result) => process.nextTick(() => callback(null, result)),
164
+ // Avoid marking the promise as rejected
165
+ (err) => process.nextTick(() => callback(err)),
166
+ )
167
+ }
168
+
169
+ export {
170
+ delay,
171
+ fromCallback,
172
+ fromEvent,
173
+ getCallback,
174
+ newQueryPlan,
175
+ optionalCallback,
176
+ times,
177
+ toBackground,
178
+ toCallback,
179
+ }
180
+
181
+ export default {
182
+ delay,
183
+ fromCallback,
184
+ fromEvent,
185
+ getCallback,
186
+ newQueryPlan,
187
+ optionalCallback,
188
+ times,
189
+ toBackground,
190
+ toCallback,
191
+ }