@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.
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 +7 -7
  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,745 @@
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
+ import util from "util"
20
+ import { Transform, Writable } from "stream"
21
+
22
+ import types from "./types/index.js"
23
+ import utils from "./utils.js"
24
+ import errors from "./errors.js"
25
+ import { FrameReader } from "./readers.js"
26
+
27
+ const { FrameHeader } = types
28
+
29
+ // type codes that support zero-length buffers (matching zeroLengthTypesSupported in encoder)
30
+ const zeroLenTypeCodes = new Set([0x0000, 0x0001, 0x0003, 0x000a, 0x000d])
31
+ // custom=0x0000, ascii=0x0001, blob=0x0003, text=0x000a, varchar=0x000d
32
+
33
+ /**
34
+ * Transforms chunks, emits data objects {header, chunk}
35
+ * @param options Stream options
36
+ * @extends Transform
37
+ */
38
+ function Protocol(options) {
39
+ Transform.call(this, options)
40
+ this.header = null
41
+ this.bodyLength = 0
42
+ this.clearHeaderChunks()
43
+ this.version = 0
44
+ this.headerSize = 0
45
+ }
46
+
47
+ util.inherits(Protocol, Transform)
48
+
49
+ Protocol.prototype._transform = function (chunk, encoding, callback) {
50
+ let error = null
51
+ try {
52
+ this.readItems(chunk)
53
+ } catch (err) {
54
+ error = err
55
+ }
56
+ callback(error)
57
+ }
58
+
59
+ /**
60
+ * Parses the chunk into frames (header and body).
61
+ * Emits (push) complete frames or frames with incomplete bodies. Following chunks containing the rest of the body will
62
+ * be emitted using the same frame.
63
+ * It buffers incomplete headers.
64
+ * @param {Buffer} chunk
65
+ */
66
+ Protocol.prototype.readItems = function (chunk) {
67
+ if (!chunk || chunk.length === 0) {
68
+ return
69
+ }
70
+ if (this.version === 0) {
71
+ //The server replies the first message with the max protocol version supported
72
+ this.version = FrameHeader.getProtocolVersion(chunk)
73
+ this.headerSize = FrameHeader.size(this.version)
74
+ }
75
+ let offset = 0
76
+ let currentHeader = this.header
77
+ this.header = null
78
+ if (this.headerChunks.byteLength !== 0) {
79
+ //incomplete header was buffered try to read the header from the buffered chunks
80
+ this.headerChunks.parts.push(chunk)
81
+ if (this.headerChunks.byteLength + chunk.length < this.headerSize) {
82
+ this.headerChunks.byteLength += chunk.length
83
+ return
84
+ }
85
+ currentHeader = FrameHeader.fromBuffer(
86
+ Buffer.concat(this.headerChunks.parts, this.headerSize),
87
+ )
88
+ offset = this.headerSize - this.headerChunks.byteLength
89
+ this.clearHeaderChunks()
90
+ }
91
+ const items = []
92
+ while (true) {
93
+ if (!currentHeader) {
94
+ if (this.headerSize > chunk.length - offset) {
95
+ if (chunk.length - offset <= 0) {
96
+ break
97
+ }
98
+ //the header is incomplete, buffer it until the next chunk
99
+ const headerPart = chunk.slice(offset, chunk.length)
100
+ this.headerChunks.parts.push(headerPart)
101
+ this.headerChunks.byteLength = headerPart.length
102
+ break
103
+ }
104
+ //read header
105
+ currentHeader = FrameHeader.fromBuffer(chunk, offset)
106
+ offset += this.headerSize
107
+ }
108
+ //parse body
109
+ const remaining = chunk.length - offset
110
+ if (currentHeader.bodyLength <= remaining + this.bodyLength) {
111
+ items.push({
112
+ header: currentHeader,
113
+ chunk: chunk,
114
+ offset: offset,
115
+ frameEnded: true,
116
+ })
117
+ offset += currentHeader.bodyLength - this.bodyLength
118
+ //reset the body length
119
+ this.bodyLength = 0
120
+ } else if (remaining >= 0) {
121
+ //the body is not fully contained in this chunk
122
+ //will continue later
123
+ this.header = currentHeader
124
+ this.bodyLength += remaining
125
+ if (remaining > 0) {
126
+ //emit if there is at least a byte to emit
127
+ items.push({
128
+ header: currentHeader,
129
+ chunk: chunk,
130
+ offset: offset,
131
+ frameEnded: false,
132
+ })
133
+ }
134
+ break
135
+ }
136
+ currentHeader = null
137
+ }
138
+ for (let i = 0; i < items.length; i++) {
139
+ this.push(items[i])
140
+ }
141
+ }
142
+
143
+ Protocol.prototype.clearHeaderChunks = function () {
144
+ this.headerChunks = { byteLength: 0, parts: [] }
145
+ }
146
+
147
+ /**
148
+ * A stream that gets reads header + body chunks and transforms them into header + (row | error)
149
+ * @param {Object} streamOptions Node Stream options
150
+ * @param {Encoder} encoder Encoder instance for the parser to use
151
+ * @extends Transform
152
+ */
153
+ function Parser(streamOptions, encoder) {
154
+ Transform.call(this, streamOptions)
155
+ //frames that are streaming, indexed by id
156
+ this.frames = {}
157
+ this.encoder = encoder
158
+ }
159
+
160
+ util.inherits(Parser, Transform)
161
+
162
+ Parser.prototype._transform = function (item, encoding, callback) {
163
+ const frameInfo = this.frameState(item)
164
+
165
+ let error = null
166
+ try {
167
+ this.parseBody(frameInfo, item)
168
+ } catch (err) {
169
+ error = err
170
+ }
171
+ callback(error)
172
+
173
+ if (item.frameEnded) {
174
+ if (frameInfo.cellBuffer) {
175
+ //Frame was being streamed but an error force it to buffer the result
176
+ this.push({
177
+ header: frameInfo.header,
178
+ error: new errors.DriverInternalError(
179
+ "There was an problem while parsing streaming frame, opcode " +
180
+ frameInfo.header.opcode,
181
+ ),
182
+ })
183
+ }
184
+ //all the parsing finished and it was streamed down
185
+ //emit an item that signals it
186
+ this.push({ header: frameInfo.header, frameEnded: true })
187
+ }
188
+ }
189
+
190
+ /**
191
+ * @param frameInfo
192
+ * @param {{header: FrameHeader, chunk: Buffer, offset: Number}} item
193
+ */
194
+ Parser.prototype.parseBody = function (frameInfo, item) {
195
+ frameInfo.isStreaming =
196
+ frameInfo.byRow && item.header.opcode === types.opcodes.result
197
+ if (!this.handleFrameBuffers(frameInfo, item)) {
198
+ // Frame isn't complete and we are not streaming the frame
199
+ return
200
+ }
201
+ const reader = new FrameReader(item.header, item.chunk, item.offset)
202
+ // Check that flags have not been parsed yet for this frame
203
+ if (frameInfo.flagsInfo === undefined) {
204
+ const originalOffset = reader.offset
205
+ try {
206
+ frameInfo.flagsInfo = reader.readFlagsInfo()
207
+ } catch (e) {
208
+ return this.handleParsingError(e, frameInfo, reader, originalOffset)
209
+ }
210
+ }
211
+
212
+ //All the body for most operations is already buffered at this stage
213
+ //Except for RESULT
214
+ switch (item.header.opcode) {
215
+ case types.opcodes.result:
216
+ return this.parseResult(frameInfo, reader)
217
+ case types.opcodes.ready:
218
+ case types.opcodes.authSuccess:
219
+ return this.push({ header: frameInfo.header, ready: true })
220
+ case types.opcodes.authChallenge:
221
+ return this.push({
222
+ header: frameInfo.header,
223
+ authChallenge: true,
224
+ token: reader.readBytes(),
225
+ })
226
+ case types.opcodes.authenticate:
227
+ return this.push({
228
+ header: frameInfo.header,
229
+ mustAuthenticate: true,
230
+ authenticatorName: reader.readString(),
231
+ })
232
+ case types.opcodes.error:
233
+ return this.push({
234
+ header: frameInfo.header,
235
+ error: reader.readError(),
236
+ })
237
+ case types.opcodes.supported:
238
+ return this.push({
239
+ header: frameInfo.header,
240
+ supported: reader.readStringMultiMap(),
241
+ })
242
+ case types.opcodes.event:
243
+ return this.push({
244
+ header: frameInfo.header,
245
+ event: reader.readEvent(),
246
+ })
247
+ default:
248
+ return this.push({
249
+ header: frameInfo.header,
250
+ error: new Error(
251
+ "Received invalid opcode: " + item.header.opcode,
252
+ ),
253
+ })
254
+ }
255
+ }
256
+
257
+ /**
258
+ * Buffers if needed and returns true if it has all the necessary data to continue parsing the frame.
259
+ * @param frameInfo
260
+ * @param {{header: FrameHeader, chunk: Buffer, offset: Number}} item
261
+ * @returns {Boolean}
262
+ */
263
+ Parser.prototype.handleFrameBuffers = function (frameInfo, item) {
264
+ if (!frameInfo.isStreaming) {
265
+ // Handle buffering for complete frame bodies
266
+ const currentLength =
267
+ (frameInfo.bufferLength || 0) + item.chunk.length - item.offset
268
+ if (currentLength < item.header.bodyLength) {
269
+ //buffer until the frame is completed
270
+ this.addFrameBuffer(frameInfo, item)
271
+ return false
272
+ }
273
+ //We have received the full frame body
274
+ if (frameInfo.buffers) {
275
+ item.chunk = this.getFrameBuffer(frameInfo, item)
276
+ item.offset = 0
277
+ }
278
+ return true
279
+ }
280
+ if (frameInfo.cellBuffer) {
281
+ // Handle buffering for frame cells (row cells or metadata cells)
282
+ if (item.offset !== 0) {
283
+ throw new errors.DriverInternalError(
284
+ "Following chunks can not have an offset greater than zero",
285
+ )
286
+ }
287
+ frameInfo.cellBuffer.parts.push(item.chunk)
288
+ if (!frameInfo.cellBuffer.expectedLength) {
289
+ //Its a buffer outside a row cell (metadata or other)
290
+ if (frameInfo.cellBuffer.parts.length !== 2) {
291
+ throw new errors.DriverInternalError(
292
+ "Buffer for streaming frame can not contain more than 1 item",
293
+ )
294
+ }
295
+ item.chunk = Buffer.concat(
296
+ frameInfo.cellBuffer.parts,
297
+ frameInfo.cellBuffer.byteLength + item.chunk.length,
298
+ )
299
+ frameInfo.cellBuffer = null
300
+ return true
301
+ }
302
+ if (
303
+ frameInfo.cellBuffer.expectedLength >
304
+ frameInfo.cellBuffer.byteLength + item.chunk.length
305
+ ) {
306
+ //We still haven't got the cell data
307
+ frameInfo.cellBuffer.byteLength += item.chunk.length
308
+ return false
309
+ }
310
+ item.chunk = Buffer.concat(
311
+ frameInfo.cellBuffer.parts,
312
+ frameInfo.cellBuffer.byteLength + item.chunk.length,
313
+ )
314
+ frameInfo.cellBuffer = null
315
+ }
316
+ return true
317
+ }
318
+
319
+ /**
320
+ * Adds this chunk to the frame buffers.
321
+ * @param frameInfo
322
+ * @param {{header: FrameHeader, chunk: Buffer, offset: Number}} item
323
+ */
324
+ Parser.prototype.addFrameBuffer = function (frameInfo, item) {
325
+ if (!frameInfo.buffers) {
326
+ frameInfo.buffers = [item.chunk.slice(item.offset)]
327
+ frameInfo.bufferLength = item.chunk.length - item.offset
328
+ return
329
+ }
330
+ if (item.offset > 0) {
331
+ throw new errors.DriverInternalError(
332
+ "Following chunks can not have an offset greater than zero",
333
+ )
334
+ }
335
+ frameInfo.buffers.push(item.chunk)
336
+ frameInfo.bufferLength += item.chunk.length
337
+ }
338
+
339
+ /**
340
+ * Adds the last chunk and concatenates the frame buffers
341
+ * @param frameInfo
342
+ * @param {{header: FrameHeader, chunk: Buffer, offset: Number}} item
343
+ */
344
+ Parser.prototype.getFrameBuffer = function (frameInfo, item) {
345
+ frameInfo.buffers.push(item.chunk)
346
+ const result = Buffer.concat(frameInfo.buffers, frameInfo.bodyLength)
347
+ frameInfo.buffers = null
348
+ return result
349
+ }
350
+
351
+ /**
352
+ * Tries to read the result in the body of a message
353
+ * @param frameInfo Frame information, header / metadata
354
+ * @param {FrameReader} reader
355
+ */
356
+ Parser.prototype.parseResult = function (frameInfo, reader) {
357
+ let result
358
+ // As we might be streaming and the frame buffer might not be complete,
359
+ // read the metadata and different types of result values in a try-catch.
360
+ // Store the reader position
361
+ const originalOffset = reader.offset
362
+ try {
363
+ if (!frameInfo.meta) {
364
+ frameInfo.kind = reader.readInt()
365
+ // Spec 4.2.5
366
+ switch (frameInfo.kind) {
367
+ case types.resultKind.voidResult:
368
+ result = {
369
+ header: frameInfo.header,
370
+ flags: frameInfo.flagsInfo,
371
+ }
372
+ break
373
+ case types.resultKind.rows:
374
+ // Parse the rows metadata, the rest of the response is going to be parsed afterwards
375
+ frameInfo.meta = reader.readMetadata(frameInfo.kind)
376
+ break
377
+ case types.resultKind.setKeyspace:
378
+ result = {
379
+ header: frameInfo.header,
380
+ keyspaceSet: reader.readString(),
381
+ flags: frameInfo.flagsInfo,
382
+ }
383
+ break
384
+ case types.resultKind.prepared: {
385
+ const preparedId = utils.copyBuffer(reader.readShortBytes())
386
+ frameInfo.meta = reader.readMetadata(frameInfo.kind)
387
+ result = {
388
+ header: frameInfo.header,
389
+ id: preparedId,
390
+ meta: frameInfo.meta,
391
+ flags: frameInfo.flagsInfo,
392
+ }
393
+ break
394
+ }
395
+ case types.resultKind.schemaChange:
396
+ result = {
397
+ header: frameInfo.header,
398
+ schemaChange: reader.parseSchemaChange(),
399
+ flags: frameInfo.flagsInfo,
400
+ }
401
+ break
402
+ default:
403
+ throw errors.DriverInternalError(
404
+ "Unexpected result kind: " + frameInfo.kind,
405
+ )
406
+ }
407
+ }
408
+ } catch (e) {
409
+ return this.handleParsingError(e, frameInfo, reader, originalOffset)
410
+ }
411
+ if (result) {
412
+ if (frameInfo.emitted) {
413
+ // It may contain additional metadata and info that it's not being parsed
414
+ return
415
+ }
416
+ frameInfo.emitted = true
417
+ return this.push(result)
418
+ }
419
+ if (reader.remainingLength() > 0) {
420
+ this.parseRows(frameInfo, reader)
421
+ }
422
+ }
423
+
424
+ /**
425
+ * Max rows to parse per tick before yielding to the event loop.
426
+ * Prevents parseRows from blocking when handling large result sets.
427
+ * @const
428
+ * @type {number}
429
+ */
430
+ const rowBatchSize = 100
431
+
432
+ /**
433
+ * @param frameInfo
434
+ * @param {FrameReader} reader
435
+ */
436
+ Parser.prototype.parseRows = function (frameInfo, reader) {
437
+ if (frameInfo.parsingError) {
438
+ //No more processing on this frame
439
+ return
440
+ }
441
+ if (frameInfo.rowLength === undefined) {
442
+ try {
443
+ frameInfo.rowLength = reader.readInt()
444
+ } catch (e) {
445
+ return this.handleParsingError(e, frameInfo, reader)
446
+ }
447
+ }
448
+ if (frameInfo.rowLength === 0) {
449
+ return this.push({
450
+ header: frameInfo.header,
451
+ result: {
452
+ rows: utils.emptyArray,
453
+ meta: frameInfo.meta,
454
+ flags: frameInfo.flagsInfo,
455
+ },
456
+ })
457
+ }
458
+
459
+ const meta = frameInfo.meta
460
+ frameInfo.rowIndex = frameInfo.rowIndex || 0
461
+
462
+ // pre-resolve column decoders once per metadata to avoid hash lookup per cell
463
+ if (!frameInfo._colDecoders) {
464
+ const colDecoders = new Array(meta.columns.length)
465
+ for (let j = 0; j < meta.columns.length; j++) {
466
+ const typeCode = meta.columns[j].type.code
467
+ colDecoders[j] = this.encoder.decoders[typeCode]
468
+ }
469
+ frameInfo._colDecoders = colDecoders
470
+ }
471
+ const colDecoders = frameInfo._colDecoders
472
+ const colTypes = meta.columns
473
+
474
+ const endRow = Math.min(
475
+ frameInfo.rowIndex + rowBatchSize,
476
+ frameInfo.rowLength,
477
+ )
478
+
479
+ for (let i = frameInfo.rowIndex; i < endRow; i++) {
480
+ const rowOffset = reader.offset
481
+ const row = new types.Row(meta.columns)
482
+ let cellBuffer
483
+ for (let j = 0; j < colTypes.length; j++) {
484
+ const c = colTypes[j]
485
+ try {
486
+ cellBuffer = reader.readBytes()
487
+ } catch (e) {
488
+ return this.handleParsingError(
489
+ e,
490
+ frameInfo,
491
+ reader,
492
+ rowOffset,
493
+ i,
494
+ )
495
+ }
496
+ try {
497
+ // replicate the null/empty guard present in Encoder.prototype.decode
498
+ if (
499
+ cellBuffer === null ||
500
+ (cellBuffer.length === 0 &&
501
+ !zeroLenTypeCodes.has(c.type.code))
502
+ ) {
503
+ row[c.name] = null
504
+ } else {
505
+ row[c.name] = colDecoders[j].call(
506
+ this.encoder,
507
+ cellBuffer,
508
+ c.type,
509
+ )
510
+ }
511
+ } catch (e) {
512
+ return this.handleParsingError(e, frameInfo, null)
513
+ }
514
+ }
515
+ this.push({
516
+ header: frameInfo.header,
517
+ row: row,
518
+ meta: frameInfo.meta,
519
+ byRow: frameInfo.byRow,
520
+ length: frameInfo.rowLength,
521
+ flags: frameInfo.flagsInfo,
522
+ })
523
+ }
524
+
525
+ frameInfo.rowIndex = endRow
526
+
527
+ if (endRow < frameInfo.rowLength) {
528
+ // save reader state and yield to the event loop to avoid blocking
529
+ frameInfo._reader = reader
530
+ const self = this
531
+ setImmediate(() => self.parseRows(frameInfo, frameInfo._reader))
532
+ return
533
+ }
534
+
535
+ // all rows processed, clean up
536
+ frameInfo._colDecoders = null
537
+ frameInfo._reader = null
538
+
539
+ if (frameInfo.byRow) {
540
+ // Use an event item to identify that all the streaming rows have finished processing
541
+ this.push({
542
+ header: frameInfo.header,
543
+ byRowCompleted: true,
544
+ meta: frameInfo.meta,
545
+ length: frameInfo.rowLength,
546
+ flags: frameInfo.flagsInfo,
547
+ })
548
+ }
549
+ }
550
+
551
+ /**
552
+ * Sets parser options (ie: how to yield the results as they are parsed)
553
+ * @param {Number} id Id of the stream
554
+ * @param options
555
+ */
556
+ Parser.prototype.setOptions = function (id, options) {
557
+ if (this.frames[id.toString()]) {
558
+ throw new types.DriverError("There was already state for this frame")
559
+ }
560
+ this.frames[id.toString()] = options
561
+ }
562
+
563
+ /**
564
+ * Manually clears the frame options.
565
+ * This class already clears the provided options when the frame ends, so it's usually not required to invoke this
566
+ * method.
567
+ * When manually setting the options for continuous paging, it's possible that the frame options are set while
568
+ * it's being cancelled.
569
+ * @param {Number} id The streamId
570
+ */
571
+ Parser.prototype.clearOptions = function (id) {
572
+ delete this.frames[id.toString()]
573
+ }
574
+
575
+ /**
576
+ * Gets the frame info from the internal state.
577
+ * In case it is not there, it creates it.
578
+ * In case the frame ended
579
+ */
580
+ Parser.prototype.frameState = function (item) {
581
+ let frameInfo = this.frames[item.header.streamId]
582
+ if (!frameInfo) {
583
+ frameInfo = {}
584
+ if (!item.frameEnded) {
585
+ //store it in the frames
586
+ this.frames[item.header.streamId] = frameInfo
587
+ }
588
+ } else if (item.frameEnded) {
589
+ //if it was already stored, remove it
590
+ delete this.frames[item.header.streamId]
591
+ }
592
+ frameInfo.header = item.header
593
+ return frameInfo
594
+ }
595
+
596
+ /**
597
+ * Handles parsing error: pushing an error if its unexpected or buffer the cell if its streaming
598
+ * @param {Error} e
599
+ * @param frameInfo
600
+ * @param {FrameReader} reader
601
+ * @param {Number} [originalOffset]
602
+ * @param {Number} [rowIndex]
603
+ */
604
+ Parser.prototype.handleParsingError = function (
605
+ e,
606
+ frameInfo,
607
+ reader,
608
+ originalOffset,
609
+ rowIndex,
610
+ ) {
611
+ if (reader && frameInfo.isStreaming && e instanceof RangeError) {
612
+ //A controlled error, buffer from offset and move on
613
+ return this.bufferResultCell(
614
+ frameInfo,
615
+ reader,
616
+ originalOffset,
617
+ rowIndex,
618
+ e.expectedLength,
619
+ )
620
+ }
621
+ frameInfo.parsingError = true
622
+ frameInfo.cellBuffer = null
623
+ this.push({ header: frameInfo.header, error: e })
624
+ }
625
+
626
+ /**
627
+ * When streaming, it buffers data since originalOffset.
628
+ * @param frameInfo
629
+ * @param {FrameReader} reader
630
+ * @param {Number} [originalOffset]
631
+ * @param {Number} [rowIndex]
632
+ * @param {Number} [expectedLength]
633
+ */
634
+ Parser.prototype.bufferResultCell = function (
635
+ frameInfo,
636
+ reader,
637
+ originalOffset,
638
+ rowIndex,
639
+ expectedLength,
640
+ ) {
641
+ if (!originalOffset && originalOffset !== 0) {
642
+ originalOffset = reader.offset
643
+ }
644
+ frameInfo.rowIndex = rowIndex
645
+ const buffer = reader.slice(originalOffset)
646
+ frameInfo.cellBuffer = {
647
+ parts: [buffer],
648
+ byteLength: buffer.length,
649
+ expectedLength: expectedLength,
650
+ }
651
+ }
652
+
653
+ /**
654
+ * Represents a writable streams that emits results
655
+ */
656
+ function ResultEmitter(options) {
657
+ Writable.call(this, options)
658
+ /**
659
+ * Stores the rows for frames that needs to be yielded as one result with many rows
660
+ */
661
+ this.rowBuffer = {}
662
+ }
663
+
664
+ util.inherits(ResultEmitter, Writable)
665
+
666
+ ResultEmitter.prototype._write = function (item, encoding, callback) {
667
+ let error = null
668
+ try {
669
+ this.each(item)
670
+ } catch (err) {
671
+ error = err
672
+ }
673
+ callback(error)
674
+ }
675
+
676
+ /**
677
+ * Analyzes the item and emit the corresponding event
678
+ */
679
+ ResultEmitter.prototype.each = function (item) {
680
+ if (item.error || item.result) {
681
+ //Its either an error or an empty array rows
682
+ //no transformation needs to be made
683
+ return this.emit("result", item.header, item.error, item.result)
684
+ }
685
+ if (item.frameEnded) {
686
+ return this.emit("frameEnded", item.header)
687
+ }
688
+ if (item.lastContinuousPage) {
689
+ return this.emit("lastContinuousPage", item.header)
690
+ }
691
+ if (item.byRowCompleted) {
692
+ return this.emit(
693
+ "byRowCompleted",
694
+ item.header,
695
+ item.row,
696
+ item.meta,
697
+ item.flags,
698
+ )
699
+ }
700
+ if (item.byRow) {
701
+ //it should be yielded by row
702
+ return this.emit(
703
+ "row",
704
+ item.header,
705
+ item.row,
706
+ item.meta,
707
+ item.length,
708
+ item.flags,
709
+ )
710
+ }
711
+ if (item.row) {
712
+ //it should be yielded as a result
713
+ //it needs to be buffered to an array of rows
714
+ return this.bufferAndEmit(item)
715
+ }
716
+ if (item.event) {
717
+ //its an event from Cassandra
718
+ return this.emit("nodeEvent", item.header, item.event)
719
+ }
720
+ //its a raw response (object with flags)
721
+ return this.emit("result", item.header, null, item)
722
+ }
723
+
724
+ /**
725
+ * Buffers the rows until the result set is completed and emits the result event.
726
+ */
727
+ ResultEmitter.prototype.bufferAndEmit = function (item) {
728
+ let rows = this.rowBuffer[item.header.streamId]
729
+ if (!rows) {
730
+ rows = this.rowBuffer[item.header.streamId] = []
731
+ }
732
+ rows.push(item.row)
733
+ if (rows.length === item.length) {
734
+ this.emit("result", item.header, null, {
735
+ rows: rows,
736
+ meta: item.meta,
737
+ flags: item.flags,
738
+ })
739
+ delete this.rowBuffer[item.header.streamId]
740
+ }
741
+ }
742
+
743
+ export { Protocol, Parser, ResultEmitter }
744
+
745
+ export default { Protocol, Parser, ResultEmitter }