@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.
- 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 +11 -12
- 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
|
@@ -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 }
|