@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,2316 @@
|
|
|
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
|
+
|
|
20
|
+
import types from "./types/index.js"
|
|
21
|
+
const dataTypes = types.dataTypes
|
|
22
|
+
const Long = types.Long
|
|
23
|
+
const Integer = types.Integer
|
|
24
|
+
const BigDecimal = types.BigDecimal
|
|
25
|
+
import MutableLong from "./types/mutable-long.js"
|
|
26
|
+
import utils from "./utils.js"
|
|
27
|
+
import token from "./token.js"
|
|
28
|
+
import Vector from "./types/vector.js"
|
|
29
|
+
|
|
30
|
+
const uuidRegex =
|
|
31
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
|
|
32
|
+
|
|
33
|
+
const buffers = {
|
|
34
|
+
int16Zero: utils.allocBufferFromArray([0, 0]),
|
|
35
|
+
int32Zero: utils.allocBufferFromArray([0, 0, 0, 0]),
|
|
36
|
+
int8Zero: utils.allocBufferFromArray([0]),
|
|
37
|
+
int8One: utils.allocBufferFromArray([1]),
|
|
38
|
+
int8MaxValue: utils.allocBufferFromArray([0xff]),
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// BigInt: Avoid using literals (e.g., 32n) as we must be able to compile with older engines
|
|
42
|
+
const isBigIntSupported = typeof BigInt !== "undefined"
|
|
43
|
+
const bigInt32 = isBigIntSupported ? BigInt(32) : null
|
|
44
|
+
const bigInt8 = isBigIntSupported ? BigInt(8) : null
|
|
45
|
+
const bigInt0 = isBigIntSupported ? BigInt(0) : null
|
|
46
|
+
const bigIntMinus1 = isBigIntSupported ? BigInt(-1) : null
|
|
47
|
+
const bigInt32BitsOn = isBigIntSupported ? BigInt(0xffffffff) : null
|
|
48
|
+
const bigInt8BitsOn = isBigIntSupported ? BigInt(0xff) : null
|
|
49
|
+
|
|
50
|
+
const complexTypeNames = Object.freeze({
|
|
51
|
+
list: "org.apache.cassandra.db.marshal.ListType",
|
|
52
|
+
set: "org.apache.cassandra.db.marshal.SetType",
|
|
53
|
+
map: "org.apache.cassandra.db.marshal.MapType",
|
|
54
|
+
udt: "org.apache.cassandra.db.marshal.UserType",
|
|
55
|
+
tuple: "org.apache.cassandra.db.marshal.TupleType",
|
|
56
|
+
frozen: "org.apache.cassandra.db.marshal.FrozenType",
|
|
57
|
+
reversed: "org.apache.cassandra.db.marshal.ReversedType",
|
|
58
|
+
composite: "org.apache.cassandra.db.marshal.CompositeType",
|
|
59
|
+
empty: "org.apache.cassandra.db.marshal.EmptyType",
|
|
60
|
+
collection: "org.apache.cassandra.db.marshal.ColumnToCollectionType",
|
|
61
|
+
})
|
|
62
|
+
const cqlNames = Object.freeze({
|
|
63
|
+
frozen: "frozen",
|
|
64
|
+
list: "list",
|
|
65
|
+
set: "set",
|
|
66
|
+
map: "map",
|
|
67
|
+
tuple: "tuple",
|
|
68
|
+
empty: "empty",
|
|
69
|
+
duration: "duration",
|
|
70
|
+
vector: "vector",
|
|
71
|
+
})
|
|
72
|
+
const singleTypeNames = Object.freeze({
|
|
73
|
+
"org.apache.cassandra.db.marshal.UTF8Type": dataTypes.varchar,
|
|
74
|
+
"org.apache.cassandra.db.marshal.AsciiType": dataTypes.ascii,
|
|
75
|
+
"org.apache.cassandra.db.marshal.UUIDType": dataTypes.uuid,
|
|
76
|
+
"org.apache.cassandra.db.marshal.TimeUUIDType": dataTypes.timeuuid,
|
|
77
|
+
"org.apache.cassandra.db.marshal.Int32Type": dataTypes.int,
|
|
78
|
+
"org.apache.cassandra.db.marshal.BytesType": dataTypes.blob,
|
|
79
|
+
"org.apache.cassandra.db.marshal.FloatType": dataTypes.float,
|
|
80
|
+
"org.apache.cassandra.db.marshal.DoubleType": dataTypes.double,
|
|
81
|
+
"org.apache.cassandra.db.marshal.BooleanType": dataTypes.boolean,
|
|
82
|
+
"org.apache.cassandra.db.marshal.InetAddressType": dataTypes.inet,
|
|
83
|
+
"org.apache.cassandra.db.marshal.SimpleDateType": dataTypes.date,
|
|
84
|
+
"org.apache.cassandra.db.marshal.TimeType": dataTypes.time,
|
|
85
|
+
"org.apache.cassandra.db.marshal.ShortType": dataTypes.smallint,
|
|
86
|
+
"org.apache.cassandra.db.marshal.ByteType": dataTypes.tinyint,
|
|
87
|
+
"org.apache.cassandra.db.marshal.DateType": dataTypes.timestamp,
|
|
88
|
+
"org.apache.cassandra.db.marshal.TimestampType": dataTypes.timestamp,
|
|
89
|
+
"org.apache.cassandra.db.marshal.LongType": dataTypes.bigint,
|
|
90
|
+
"org.apache.cassandra.db.marshal.DecimalType": dataTypes.decimal,
|
|
91
|
+
"org.apache.cassandra.db.marshal.IntegerType": dataTypes.varint,
|
|
92
|
+
"org.apache.cassandra.db.marshal.CounterColumnType": dataTypes.counter,
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
// eslint-disable-next-line no-unused-vars
|
|
96
|
+
const singleTypeNamesByDataType = invertObject(singleTypeNames)
|
|
97
|
+
const singleFqTypeNamesLength = Object.keys(singleTypeNames).reduce(function (
|
|
98
|
+
previous,
|
|
99
|
+
current,
|
|
100
|
+
) {
|
|
101
|
+
return current.length > previous ? current.length : previous
|
|
102
|
+
}, 0)
|
|
103
|
+
|
|
104
|
+
const customTypeNames = Object.freeze({
|
|
105
|
+
duration: "org.apache.cassandra.db.marshal.DurationType",
|
|
106
|
+
vector: "org.apache.cassandra.db.marshal.VectorType",
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
const nullValueBuffer = utils.allocBufferFromArray([255, 255, 255, 255])
|
|
110
|
+
const unsetValueBuffer = utils.allocBufferFromArray([255, 255, 255, 254])
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* For backwards compatibility, empty buffers as text/blob/custom values are supported.
|
|
114
|
+
* In the case of other types, they are going to be decoded as a <code>null</code> value.
|
|
115
|
+
* @private
|
|
116
|
+
* @type {Set}
|
|
117
|
+
*/
|
|
118
|
+
const zeroLengthTypesSupported = new Set([
|
|
119
|
+
dataTypes.text,
|
|
120
|
+
dataTypes.ascii,
|
|
121
|
+
dataTypes.varchar,
|
|
122
|
+
dataTypes.custom,
|
|
123
|
+
dataTypes.blob,
|
|
124
|
+
])
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Serializes and deserializes to and from a CQL type and a Javascript Type.
|
|
128
|
+
* @param {Number} protocolVersion
|
|
129
|
+
* @constructor
|
|
130
|
+
*/
|
|
131
|
+
function Encoder(protocolVersion, options) {
|
|
132
|
+
this.encodingOptions = options.encoding || utils.emptyObject
|
|
133
|
+
defineInstanceMembers.call(this)
|
|
134
|
+
this.setProtocolVersion(protocolVersion)
|
|
135
|
+
setEncoders.call(this)
|
|
136
|
+
if (this.encodingOptions.copyBuffer) {
|
|
137
|
+
this.handleBuffer = handleBufferCopy
|
|
138
|
+
} else {
|
|
139
|
+
this.handleBuffer = handleBufferRef
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Declares the privileged instance members.
|
|
145
|
+
* @private
|
|
146
|
+
*/
|
|
147
|
+
function defineInstanceMembers() {
|
|
148
|
+
/**
|
|
149
|
+
* Sets the protocol version and the encoding/decoding methods depending on the protocol version
|
|
150
|
+
* @param {Number} value
|
|
151
|
+
* @ignore
|
|
152
|
+
* @internal
|
|
153
|
+
*/
|
|
154
|
+
this.setProtocolVersion = function (value) {
|
|
155
|
+
this.protocolVersion = value
|
|
156
|
+
//Set the collection serialization based on the protocol version
|
|
157
|
+
this.decodeCollectionLength = decodeCollectionLengthV3
|
|
158
|
+
this.getLengthBuffer = getLengthBufferV3
|
|
159
|
+
this.collectionLengthSize = 4
|
|
160
|
+
if (
|
|
161
|
+
!types.protocolVersion.uses4BytesCollectionLength(
|
|
162
|
+
this.protocolVersion,
|
|
163
|
+
)
|
|
164
|
+
) {
|
|
165
|
+
this.decodeCollectionLength = decodeCollectionLengthV2
|
|
166
|
+
this.getLengthBuffer = getLengthBufferV2
|
|
167
|
+
this.collectionLengthSize = 2
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const customDecoders = {
|
|
172
|
+
[customTypeNames.duration]: decodeDuration,
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const customEncoders = {
|
|
176
|
+
[customTypeNames.duration]: encodeDuration,
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Decoding methods
|
|
180
|
+
this.decodeBlob = function (bytes) {
|
|
181
|
+
return this.handleBuffer(bytes)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
*
|
|
186
|
+
* @param {Buffer} bytes
|
|
187
|
+
* @param {OtherCustomColumnInfo | VectorColumnInfo} columnInfo
|
|
188
|
+
*/
|
|
189
|
+
this.decodeCustom = function (bytes, columnInfo) {
|
|
190
|
+
// Make sure we actually have something to process in typeName before we go any further
|
|
191
|
+
if (!columnInfo) {
|
|
192
|
+
return this.handleBuffer(bytes)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Special handling for vector custom types (since they have args)
|
|
196
|
+
if (
|
|
197
|
+
"customTypeName" in columnInfo &&
|
|
198
|
+
columnInfo.customTypeName === "vector"
|
|
199
|
+
) {
|
|
200
|
+
return this.decodeVector(bytes, columnInfo)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (
|
|
204
|
+
typeof columnInfo.info === "string" &&
|
|
205
|
+
columnInfo.info.startsWith(customTypeNames.vector)
|
|
206
|
+
) {
|
|
207
|
+
const vectorColumnInfo = /** @type {VectorColumnInfo} */ (
|
|
208
|
+
this.parseFqTypeName(columnInfo.info)
|
|
209
|
+
)
|
|
210
|
+
return this.decodeVector(bytes, vectorColumnInfo)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const handler = customDecoders[columnInfo.info]
|
|
214
|
+
if (handler) {
|
|
215
|
+
return handler.call(this, bytes)
|
|
216
|
+
}
|
|
217
|
+
return this.handleBuffer(bytes)
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
this.decodeUtf8String = function (bytes) {
|
|
221
|
+
return bytes.toString("utf8")
|
|
222
|
+
}
|
|
223
|
+
this.decodeAsciiString = function (bytes) {
|
|
224
|
+
return bytes.toString("ascii")
|
|
225
|
+
}
|
|
226
|
+
this.decodeBoolean = function (bytes) {
|
|
227
|
+
return !!bytes.readUInt8(0)
|
|
228
|
+
}
|
|
229
|
+
this.decodeDouble = function (bytes) {
|
|
230
|
+
return bytes.readDoubleBE(0)
|
|
231
|
+
}
|
|
232
|
+
this.decodeFloat = function (bytes) {
|
|
233
|
+
return bytes.readFloatBE(0)
|
|
234
|
+
}
|
|
235
|
+
this.decodeInt = function (bytes) {
|
|
236
|
+
return bytes.readInt32BE(0)
|
|
237
|
+
}
|
|
238
|
+
this.decodeSmallint = function (bytes) {
|
|
239
|
+
return bytes.readInt16BE(0)
|
|
240
|
+
}
|
|
241
|
+
this.decodeTinyint = function (bytes) {
|
|
242
|
+
return bytes.readInt8(0)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
this._decodeCqlLongAsLong = function (bytes) {
|
|
246
|
+
return Long.fromBuffer(bytes)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
this._decodeCqlLongAsBigInt = function (bytes) {
|
|
250
|
+
return BigInt.asIntN(
|
|
251
|
+
64,
|
|
252
|
+
(BigInt(bytes.readUInt32BE(0)) << bigInt32) |
|
|
253
|
+
BigInt(bytes.readUInt32BE(4)),
|
|
254
|
+
)
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
this.decodeLong = this.encodingOptions.useBigIntAsLong
|
|
258
|
+
? this._decodeCqlLongAsBigInt
|
|
259
|
+
: this._decodeCqlLongAsLong
|
|
260
|
+
|
|
261
|
+
this._decodeVarintAsInteger = function (bytes) {
|
|
262
|
+
return Integer.fromBuffer(bytes)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
this._decodeVarintAsBigInt = function decodeVarintAsBigInt(bytes) {
|
|
266
|
+
let result = bigInt0
|
|
267
|
+
if (bytes[0] <= 0x7f) {
|
|
268
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
269
|
+
const b = BigInt(bytes[bytes.length - 1 - i])
|
|
270
|
+
result = result | (b << BigInt(i * 8))
|
|
271
|
+
}
|
|
272
|
+
} else {
|
|
273
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
274
|
+
const b = BigInt(bytes[bytes.length - 1 - i])
|
|
275
|
+
result = result | ((~b & bigInt8BitsOn) << BigInt(i * 8))
|
|
276
|
+
}
|
|
277
|
+
result = ~result
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return result
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
this.decodeVarint = this.encodingOptions.useBigIntAsVarint
|
|
284
|
+
? this._decodeVarintAsBigInt
|
|
285
|
+
: this._decodeVarintAsInteger
|
|
286
|
+
|
|
287
|
+
this.decodeDecimal = function (bytes) {
|
|
288
|
+
return BigDecimal.fromBuffer(bytes)
|
|
289
|
+
}
|
|
290
|
+
this.decodeTimestamp = function (bytes) {
|
|
291
|
+
return new Date(this._decodeCqlLongAsLong(bytes).toNumber())
|
|
292
|
+
}
|
|
293
|
+
this.decodeDate = function (bytes) {
|
|
294
|
+
return types.LocalDate.fromBuffer(bytes)
|
|
295
|
+
}
|
|
296
|
+
this.decodeTime = function (bytes) {
|
|
297
|
+
return types.LocalTime.fromBuffer(bytes)
|
|
298
|
+
}
|
|
299
|
+
/*
|
|
300
|
+
* Reads a list from bytes
|
|
301
|
+
*/
|
|
302
|
+
this.decodeList = function (bytes, columnInfo) {
|
|
303
|
+
const subtype = columnInfo.info
|
|
304
|
+
const totalItems = this.decodeCollectionLength(bytes, 0)
|
|
305
|
+
let offset = this.collectionLengthSize
|
|
306
|
+
const list = new Array(totalItems)
|
|
307
|
+
for (let i = 0; i < totalItems; i++) {
|
|
308
|
+
//bytes length of the item
|
|
309
|
+
const length = this.decodeCollectionLength(bytes, offset)
|
|
310
|
+
offset += this.collectionLengthSize
|
|
311
|
+
//slice it
|
|
312
|
+
list[i] = this.decode(bytes.slice(offset, offset + length), subtype)
|
|
313
|
+
offset += length
|
|
314
|
+
}
|
|
315
|
+
return list
|
|
316
|
+
}
|
|
317
|
+
/*
|
|
318
|
+
* Reads a Set from bytes
|
|
319
|
+
*/
|
|
320
|
+
this.decodeSet = function (bytes, columnInfo) {
|
|
321
|
+
const arr = this.decodeList(bytes, columnInfo)
|
|
322
|
+
if (this.encodingOptions.set) {
|
|
323
|
+
const setConstructor = this.encodingOptions.set
|
|
324
|
+
return new setConstructor(arr)
|
|
325
|
+
}
|
|
326
|
+
return arr
|
|
327
|
+
}
|
|
328
|
+
/*
|
|
329
|
+
* Reads a map (key / value) from bytes
|
|
330
|
+
*/
|
|
331
|
+
this.decodeMap = function (bytes, columnInfo) {
|
|
332
|
+
const subtypes = columnInfo.info
|
|
333
|
+
let map
|
|
334
|
+
const totalItems = this.decodeCollectionLength(bytes, 0)
|
|
335
|
+
let offset = this.collectionLengthSize
|
|
336
|
+
const self = this
|
|
337
|
+
function readValues(callback, thisArg) {
|
|
338
|
+
for (let i = 0; i < totalItems; i++) {
|
|
339
|
+
const keyLength = self.decodeCollectionLength(bytes, offset)
|
|
340
|
+
offset += self.collectionLengthSize
|
|
341
|
+
const key = self.decode(
|
|
342
|
+
bytes.slice(offset, offset + keyLength),
|
|
343
|
+
subtypes[0],
|
|
344
|
+
)
|
|
345
|
+
offset += keyLength
|
|
346
|
+
const valueLength = self.decodeCollectionLength(bytes, offset)
|
|
347
|
+
offset += self.collectionLengthSize
|
|
348
|
+
if (valueLength < 0) {
|
|
349
|
+
callback.call(thisArg, key, null)
|
|
350
|
+
continue
|
|
351
|
+
}
|
|
352
|
+
const value = self.decode(
|
|
353
|
+
bytes.slice(offset, offset + valueLength),
|
|
354
|
+
subtypes[1],
|
|
355
|
+
)
|
|
356
|
+
offset += valueLength
|
|
357
|
+
callback.call(thisArg, key, value)
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
if (this.encodingOptions.map) {
|
|
361
|
+
const mapConstructor = this.encodingOptions.map
|
|
362
|
+
map = new mapConstructor()
|
|
363
|
+
readValues(map.set, map)
|
|
364
|
+
} else {
|
|
365
|
+
map = {}
|
|
366
|
+
readValues(function (key, value) {
|
|
367
|
+
map[key] = value
|
|
368
|
+
})
|
|
369
|
+
}
|
|
370
|
+
return map
|
|
371
|
+
}
|
|
372
|
+
this.decodeUuid = function (bytes) {
|
|
373
|
+
return new types.Uuid(this.handleBuffer(bytes))
|
|
374
|
+
}
|
|
375
|
+
this.decodeTimeUuid = function (bytes) {
|
|
376
|
+
return new types.TimeUuid(this.handleBuffer(bytes))
|
|
377
|
+
}
|
|
378
|
+
this.decodeInet = function (bytes) {
|
|
379
|
+
return new types.InetAddress(this.handleBuffer(bytes))
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Decodes a user defined type into an object
|
|
383
|
+
* @param {Buffer} bytes
|
|
384
|
+
* @param {UdtColumnInfo} columnInfo
|
|
385
|
+
* @private
|
|
386
|
+
*/
|
|
387
|
+
this.decodeUdt = function (bytes, columnInfo) {
|
|
388
|
+
const udtInfo = columnInfo.info
|
|
389
|
+
const result = {}
|
|
390
|
+
let offset = 0
|
|
391
|
+
for (
|
|
392
|
+
let i = 0;
|
|
393
|
+
i < udtInfo.fields.length && offset < bytes.length;
|
|
394
|
+
i++
|
|
395
|
+
) {
|
|
396
|
+
//bytes length of the field value
|
|
397
|
+
const length = bytes.readInt32BE(offset)
|
|
398
|
+
offset += 4
|
|
399
|
+
//slice it
|
|
400
|
+
const field = udtInfo.fields[i]
|
|
401
|
+
if (length < 0) {
|
|
402
|
+
result[field.name] = null
|
|
403
|
+
continue
|
|
404
|
+
}
|
|
405
|
+
result[field.name] = this.decode(
|
|
406
|
+
bytes.slice(offset, offset + length),
|
|
407
|
+
field.type,
|
|
408
|
+
)
|
|
409
|
+
offset += length
|
|
410
|
+
}
|
|
411
|
+
return result
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
this.decodeTuple = function (bytes, columnInfo) {
|
|
415
|
+
const tupleInfo = columnInfo.info
|
|
416
|
+
const elements = new Array(tupleInfo.length)
|
|
417
|
+
let offset = 0
|
|
418
|
+
|
|
419
|
+
for (let i = 0; i < tupleInfo.length && offset < bytes.length; i++) {
|
|
420
|
+
const length = bytes.readInt32BE(offset)
|
|
421
|
+
offset += 4
|
|
422
|
+
|
|
423
|
+
if (length < 0) {
|
|
424
|
+
elements[i] = null
|
|
425
|
+
continue
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
elements[i] = this.decode(
|
|
429
|
+
bytes.slice(offset, offset + length),
|
|
430
|
+
tupleInfo[i],
|
|
431
|
+
)
|
|
432
|
+
offset += length
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return types.Tuple.fromArray(elements)
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
//Encoding methods
|
|
439
|
+
this.encodeFloat = function (value) {
|
|
440
|
+
if (typeof value === "string") {
|
|
441
|
+
// All numeric types are supported as strings for historical reasons
|
|
442
|
+
value = parseFloat(value)
|
|
443
|
+
|
|
444
|
+
if (Number.isNaN(value)) {
|
|
445
|
+
throw new TypeError(
|
|
446
|
+
`Expected string representation of a number, obtained ${util.inspect(value)}`,
|
|
447
|
+
)
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (typeof value !== "number") {
|
|
452
|
+
throw new TypeError(
|
|
453
|
+
"Expected Number, obtained " + util.inspect(value),
|
|
454
|
+
)
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
const buf = utils.allocBufferUnsafe(4)
|
|
458
|
+
buf.writeFloatBE(value, 0)
|
|
459
|
+
return buf
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
this.encodeDouble = function (value) {
|
|
463
|
+
if (typeof value === "string") {
|
|
464
|
+
// All numeric types are supported as strings for historical reasons
|
|
465
|
+
value = parseFloat(value)
|
|
466
|
+
|
|
467
|
+
if (Number.isNaN(value)) {
|
|
468
|
+
throw new TypeError(
|
|
469
|
+
`Expected string representation of a number, obtained ${util.inspect(value)}`,
|
|
470
|
+
)
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
if (typeof value !== "number") {
|
|
475
|
+
throw new TypeError(
|
|
476
|
+
"Expected Number, obtained " + util.inspect(value),
|
|
477
|
+
)
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
const buf = utils.allocBufferUnsafe(8)
|
|
481
|
+
buf.writeDoubleBE(value, 0)
|
|
482
|
+
return buf
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* @param {Date|String|Long|Number} value
|
|
487
|
+
* @private
|
|
488
|
+
*/
|
|
489
|
+
this.encodeTimestamp = function (value) {
|
|
490
|
+
const originalValue = value
|
|
491
|
+
if (typeof value === "string") {
|
|
492
|
+
value = new Date(value)
|
|
493
|
+
}
|
|
494
|
+
if (value instanceof Date) {
|
|
495
|
+
//milliseconds since epoch
|
|
496
|
+
value = value.getTime()
|
|
497
|
+
if (isNaN(value)) {
|
|
498
|
+
throw new TypeError("Invalid date: " + originalValue)
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
if (this.encodingOptions.useBigIntAsLong) {
|
|
502
|
+
value = BigInt(value)
|
|
503
|
+
}
|
|
504
|
+
return this.encodeLong(value)
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* @param {Date|String|LocalDate} value
|
|
508
|
+
* @returns {Buffer}
|
|
509
|
+
* @throws {TypeError}
|
|
510
|
+
* @private
|
|
511
|
+
*/
|
|
512
|
+
this.encodeDate = function (value) {
|
|
513
|
+
const originalValue = value
|
|
514
|
+
try {
|
|
515
|
+
if (typeof value === "string") {
|
|
516
|
+
value = types.LocalDate.fromString(value)
|
|
517
|
+
}
|
|
518
|
+
if (value instanceof Date) {
|
|
519
|
+
value = types.LocalDate.fromDate(value)
|
|
520
|
+
}
|
|
521
|
+
} catch (err) {
|
|
522
|
+
//Wrap into a TypeError
|
|
523
|
+
throw new TypeError("LocalDate could not be parsed " + err)
|
|
524
|
+
}
|
|
525
|
+
if (!(value instanceof types.LocalDate)) {
|
|
526
|
+
throw new TypeError(
|
|
527
|
+
"Expected Date/String/LocalDate, obtained " +
|
|
528
|
+
util.inspect(originalValue),
|
|
529
|
+
)
|
|
530
|
+
}
|
|
531
|
+
return value.toBuffer()
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* @param {String|LocalDate} value
|
|
535
|
+
* @returns {Buffer}
|
|
536
|
+
* @throws {TypeError}
|
|
537
|
+
* @private
|
|
538
|
+
*/
|
|
539
|
+
this.encodeTime = function (value) {
|
|
540
|
+
const originalValue = value
|
|
541
|
+
try {
|
|
542
|
+
if (typeof value === "string") {
|
|
543
|
+
value = types.LocalTime.fromString(value)
|
|
544
|
+
}
|
|
545
|
+
} catch (err) {
|
|
546
|
+
//Wrap into a TypeError
|
|
547
|
+
throw new TypeError("LocalTime could not be parsed " + err)
|
|
548
|
+
}
|
|
549
|
+
if (!(value instanceof types.LocalTime)) {
|
|
550
|
+
throw new TypeError(
|
|
551
|
+
"Expected String/LocalTime, obtained " +
|
|
552
|
+
util.inspect(originalValue),
|
|
553
|
+
)
|
|
554
|
+
}
|
|
555
|
+
return value.toBuffer()
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* @param {Uuid|String|Buffer} value
|
|
559
|
+
* @private
|
|
560
|
+
*/
|
|
561
|
+
this.encodeUuid = function (value) {
|
|
562
|
+
if (typeof value === "string") {
|
|
563
|
+
try {
|
|
564
|
+
value = types.Uuid.fromString(value).getBuffer()
|
|
565
|
+
} catch (err) {
|
|
566
|
+
throw new TypeError(err.message)
|
|
567
|
+
}
|
|
568
|
+
} else if (value instanceof types.Uuid) {
|
|
569
|
+
value = value.getBuffer()
|
|
570
|
+
} else {
|
|
571
|
+
throw new TypeError(
|
|
572
|
+
"Not a valid Uuid, expected Uuid/String/Buffer, obtained " +
|
|
573
|
+
util.inspect(value),
|
|
574
|
+
)
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
return value
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* @param {String|InetAddress|Buffer} value
|
|
581
|
+
* @returns {Buffer}
|
|
582
|
+
* @private
|
|
583
|
+
*/
|
|
584
|
+
this.encodeInet = function (value) {
|
|
585
|
+
if (typeof value === "string") {
|
|
586
|
+
value = types.InetAddress.fromString(value)
|
|
587
|
+
}
|
|
588
|
+
if (value instanceof types.InetAddress) {
|
|
589
|
+
value = value.getBuffer()
|
|
590
|
+
}
|
|
591
|
+
if (!(value instanceof Buffer)) {
|
|
592
|
+
throw new TypeError(
|
|
593
|
+
"Not a valid Inet, expected InetAddress/Buffer, obtained " +
|
|
594
|
+
util.inspect(value),
|
|
595
|
+
)
|
|
596
|
+
}
|
|
597
|
+
return value
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* @param {Long|Buffer|String|Number} value
|
|
602
|
+
* @private
|
|
603
|
+
*/
|
|
604
|
+
this._encodeBigIntFromLong = function (value) {
|
|
605
|
+
if (typeof value === "number") {
|
|
606
|
+
value = Long.fromNumber(value)
|
|
607
|
+
} else if (typeof value === "string") {
|
|
608
|
+
value = Long.fromString(value)
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
let buf = null
|
|
612
|
+
|
|
613
|
+
if (value instanceof Long) {
|
|
614
|
+
buf = Long.toBuffer(value)
|
|
615
|
+
} else if (value instanceof MutableLong) {
|
|
616
|
+
buf = Long.toBuffer(value.toImmutable())
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
if (buf === null) {
|
|
620
|
+
throw new TypeError(
|
|
621
|
+
"Not a valid bigint, expected Long/Number/String/Buffer, obtained " +
|
|
622
|
+
util.inspect(value),
|
|
623
|
+
)
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
return buf
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
this._encodeBigIntFromBigInt = function (value) {
|
|
630
|
+
if (typeof value === "string") {
|
|
631
|
+
// All numeric types are supported as strings for historical reasons
|
|
632
|
+
value = BigInt(value)
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// eslint-disable-next-line valid-typeof
|
|
636
|
+
if (typeof value !== "bigint") {
|
|
637
|
+
// Only BigInt values are supported
|
|
638
|
+
throw new TypeError(
|
|
639
|
+
"Not a valid BigInt value, obtained " + util.inspect(value),
|
|
640
|
+
)
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
const buffer = utils.allocBufferUnsafe(8)
|
|
644
|
+
buffer.writeUInt32BE(Number(value >> bigInt32) >>> 0, 0)
|
|
645
|
+
buffer.writeUInt32BE(Number(value & bigInt32BitsOn), 4)
|
|
646
|
+
return buffer
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
this.encodeLong = this.encodingOptions.useBigIntAsLong
|
|
650
|
+
? this._encodeBigIntFromBigInt
|
|
651
|
+
: this._encodeBigIntFromLong
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* @param {Integer|Buffer|String|Number} value
|
|
655
|
+
* @returns {Buffer}
|
|
656
|
+
* @private
|
|
657
|
+
*/
|
|
658
|
+
this._encodeVarintFromInteger = function (value) {
|
|
659
|
+
if (typeof value === "number") {
|
|
660
|
+
value = Integer.fromNumber(value)
|
|
661
|
+
}
|
|
662
|
+
if (typeof value === "string") {
|
|
663
|
+
value = Integer.fromString(value)
|
|
664
|
+
}
|
|
665
|
+
let buf = null
|
|
666
|
+
if (value instanceof Buffer) {
|
|
667
|
+
buf = value
|
|
668
|
+
}
|
|
669
|
+
if (value instanceof Integer) {
|
|
670
|
+
buf = Integer.toBuffer(value)
|
|
671
|
+
}
|
|
672
|
+
if (buf === null) {
|
|
673
|
+
throw new TypeError(
|
|
674
|
+
"Not a valid varint, expected Integer/Number/String/Buffer, obtained " +
|
|
675
|
+
util.inspect(value),
|
|
676
|
+
)
|
|
677
|
+
}
|
|
678
|
+
return buf
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
this._encodeVarintFromBigInt = function (value) {
|
|
682
|
+
if (typeof value === "string") {
|
|
683
|
+
// All numeric types are supported as strings for historical reasons
|
|
684
|
+
value = BigInt(value)
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// eslint-disable-next-line valid-typeof
|
|
688
|
+
if (typeof value !== "bigint") {
|
|
689
|
+
throw new TypeError(
|
|
690
|
+
"Not a valid varint, expected BigInt, obtained " +
|
|
691
|
+
util.inspect(value),
|
|
692
|
+
)
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
if (value === bigInt0) {
|
|
696
|
+
return buffers.int8Zero
|
|
697
|
+
} else if (value === bigIntMinus1) {
|
|
698
|
+
return buffers.int8MaxValue
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
const parts = []
|
|
702
|
+
|
|
703
|
+
if (value > bigInt0) {
|
|
704
|
+
while (value !== bigInt0) {
|
|
705
|
+
parts.unshift(Number(value & bigInt8BitsOn))
|
|
706
|
+
value = value >> bigInt8
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
if (parts[0] > 0x7f) {
|
|
710
|
+
// Positive value needs a padding
|
|
711
|
+
parts.unshift(0)
|
|
712
|
+
}
|
|
713
|
+
} else {
|
|
714
|
+
while (value !== bigIntMinus1) {
|
|
715
|
+
parts.unshift(Number(value & bigInt8BitsOn))
|
|
716
|
+
value = value >> bigInt8
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
if (parts[0] <= 0x7f) {
|
|
720
|
+
// Negative value needs a padding
|
|
721
|
+
parts.unshift(0xff)
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
return utils.allocBufferFromArray(parts)
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
this.encodeVarint = this.encodingOptions.useBigIntAsVarint
|
|
729
|
+
? this._encodeVarintFromBigInt
|
|
730
|
+
: this._encodeVarintFromInteger
|
|
731
|
+
|
|
732
|
+
/**
|
|
733
|
+
* @param {BigDecimal|Buffer|String|Number} value
|
|
734
|
+
* @returns {Buffer}
|
|
735
|
+
* @private
|
|
736
|
+
*/
|
|
737
|
+
this.encodeDecimal = function (value) {
|
|
738
|
+
if (typeof value === "number") {
|
|
739
|
+
value = BigDecimal.fromNumber(value)
|
|
740
|
+
} else if (typeof value === "string") {
|
|
741
|
+
value = BigDecimal.fromString(value)
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
let buf = null
|
|
745
|
+
|
|
746
|
+
if (value instanceof BigDecimal) {
|
|
747
|
+
buf = BigDecimal.toBuffer(value)
|
|
748
|
+
} else {
|
|
749
|
+
throw new TypeError(
|
|
750
|
+
"Not a valid varint, expected BigDecimal/Number/String/Buffer, obtained " +
|
|
751
|
+
util.inspect(value),
|
|
752
|
+
)
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
return buf
|
|
756
|
+
}
|
|
757
|
+
this.encodeString = function (value, encoding) {
|
|
758
|
+
if (typeof value !== "string") {
|
|
759
|
+
throw new TypeError(
|
|
760
|
+
"Not a valid text value, expected String obtained " +
|
|
761
|
+
util.inspect(value),
|
|
762
|
+
)
|
|
763
|
+
}
|
|
764
|
+
return utils.allocBufferFromString(value, encoding)
|
|
765
|
+
}
|
|
766
|
+
this.encodeUtf8String = function (value) {
|
|
767
|
+
return this.encodeString(value, "utf8")
|
|
768
|
+
}
|
|
769
|
+
this.encodeAsciiString = function (value) {
|
|
770
|
+
return this.encodeString(value, "ascii")
|
|
771
|
+
}
|
|
772
|
+
this.encodeBlob = function (value) {
|
|
773
|
+
if (!(value instanceof Buffer)) {
|
|
774
|
+
throw new TypeError(
|
|
775
|
+
"Not a valid blob, expected Buffer obtained " +
|
|
776
|
+
util.inspect(value),
|
|
777
|
+
)
|
|
778
|
+
}
|
|
779
|
+
return value
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
*
|
|
784
|
+
* @param {any} value
|
|
785
|
+
* @param {OtherCustomColumnInfo | VectorColumnInfo} columnInfo
|
|
786
|
+
*/
|
|
787
|
+
this.encodeCustom = function (value, columnInfo) {
|
|
788
|
+
if (
|
|
789
|
+
"customTypeName" in columnInfo &&
|
|
790
|
+
columnInfo.customTypeName === "vector"
|
|
791
|
+
) {
|
|
792
|
+
return this.encodeVector(value, columnInfo)
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
if (
|
|
796
|
+
typeof columnInfo.info === "string" &&
|
|
797
|
+
columnInfo.info.startsWith(customTypeNames.vector)
|
|
798
|
+
) {
|
|
799
|
+
const vectorColumnInfo = /** @type {VectorColumnInfo} */ (
|
|
800
|
+
this.parseFqTypeName(columnInfo.info)
|
|
801
|
+
)
|
|
802
|
+
return this.encodeVector(value, vectorColumnInfo)
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
const handler = customEncoders[columnInfo.info]
|
|
806
|
+
if (handler) {
|
|
807
|
+
return handler.call(this, value)
|
|
808
|
+
}
|
|
809
|
+
throw new TypeError("No encoding handler found for type " + columnInfo)
|
|
810
|
+
}
|
|
811
|
+
/**
|
|
812
|
+
* @param {Boolean} value
|
|
813
|
+
* @returns {Buffer}
|
|
814
|
+
* @private
|
|
815
|
+
*/
|
|
816
|
+
this.encodeBoolean = function (value) {
|
|
817
|
+
return value ? buffers.int8One : buffers.int8Zero
|
|
818
|
+
}
|
|
819
|
+
/**
|
|
820
|
+
* @param {Number|String} value
|
|
821
|
+
* @private
|
|
822
|
+
*/
|
|
823
|
+
this.encodeInt = function (value) {
|
|
824
|
+
if (isNaN(value)) {
|
|
825
|
+
throw new TypeError(
|
|
826
|
+
"Expected Number, obtained " + util.inspect(value),
|
|
827
|
+
)
|
|
828
|
+
}
|
|
829
|
+
const buf = utils.allocBufferUnsafe(4)
|
|
830
|
+
buf.writeInt32BE(value, 0)
|
|
831
|
+
return buf
|
|
832
|
+
}
|
|
833
|
+
/**
|
|
834
|
+
* @param {Number|String} value
|
|
835
|
+
* @private
|
|
836
|
+
*/
|
|
837
|
+
this.encodeSmallint = function (value) {
|
|
838
|
+
if (isNaN(value)) {
|
|
839
|
+
throw new TypeError(
|
|
840
|
+
"Expected Number, obtained " + util.inspect(value),
|
|
841
|
+
)
|
|
842
|
+
}
|
|
843
|
+
const buf = utils.allocBufferUnsafe(2)
|
|
844
|
+
buf.writeInt16BE(value, 0)
|
|
845
|
+
return buf
|
|
846
|
+
}
|
|
847
|
+
/**
|
|
848
|
+
* @param {Number} value
|
|
849
|
+
* @private
|
|
850
|
+
*/
|
|
851
|
+
this.encodeTinyint = function (value) {
|
|
852
|
+
if (isNaN(value)) {
|
|
853
|
+
throw new TypeError(
|
|
854
|
+
"Expected Number, obtained " + util.inspect(value),
|
|
855
|
+
)
|
|
856
|
+
}
|
|
857
|
+
const buf = utils.allocBufferUnsafe(1)
|
|
858
|
+
buf.writeInt8(value, 0)
|
|
859
|
+
return buf
|
|
860
|
+
}
|
|
861
|
+
this.encodeList = function (value, columnInfo) {
|
|
862
|
+
const subtype = columnInfo.info
|
|
863
|
+
if (!Array.isArray(value)) {
|
|
864
|
+
throw new TypeError(
|
|
865
|
+
"Not a valid list value, expected Array obtained " +
|
|
866
|
+
util.inspect(value),
|
|
867
|
+
)
|
|
868
|
+
}
|
|
869
|
+
if (value.length === 0) {
|
|
870
|
+
return null
|
|
871
|
+
}
|
|
872
|
+
const parts = []
|
|
873
|
+
parts.push(this.getLengthBuffer(value))
|
|
874
|
+
for (let i = 0; i < value.length; i++) {
|
|
875
|
+
const val = value[i]
|
|
876
|
+
if (
|
|
877
|
+
val === null ||
|
|
878
|
+
typeof val === "undefined" ||
|
|
879
|
+
val === types.unset
|
|
880
|
+
) {
|
|
881
|
+
throw new TypeError(
|
|
882
|
+
"A collection can't contain null or unset values",
|
|
883
|
+
)
|
|
884
|
+
}
|
|
885
|
+
const bytes = this.encode(val, subtype)
|
|
886
|
+
//include item byte length
|
|
887
|
+
parts.push(this.getLengthBuffer(bytes))
|
|
888
|
+
//include item
|
|
889
|
+
parts.push(bytes)
|
|
890
|
+
}
|
|
891
|
+
return Buffer.concat(parts)
|
|
892
|
+
}
|
|
893
|
+
this.encodeSet = function (value, columnInfo) {
|
|
894
|
+
if (
|
|
895
|
+
this.encodingOptions.set &&
|
|
896
|
+
value instanceof this.encodingOptions.set
|
|
897
|
+
) {
|
|
898
|
+
const arr = []
|
|
899
|
+
value.forEach(function (x) {
|
|
900
|
+
arr.push(x)
|
|
901
|
+
})
|
|
902
|
+
return this.encodeList(arr, columnInfo)
|
|
903
|
+
}
|
|
904
|
+
return this.encodeList(value, columnInfo)
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
907
|
+
* Serializes a map into a Buffer
|
|
908
|
+
* @param value
|
|
909
|
+
* @param {MapColumnInfo} columnInfo
|
|
910
|
+
* @returns {Buffer}
|
|
911
|
+
* @private
|
|
912
|
+
*/
|
|
913
|
+
this.encodeMap = function (value, columnInfo) {
|
|
914
|
+
const subtypes = columnInfo.info
|
|
915
|
+
const parts = []
|
|
916
|
+
let propCounter = 0
|
|
917
|
+
let keySubtype = null
|
|
918
|
+
let valueSubtype = null
|
|
919
|
+
const self = this
|
|
920
|
+
if (subtypes) {
|
|
921
|
+
keySubtype = subtypes[0]
|
|
922
|
+
valueSubtype = subtypes[1]
|
|
923
|
+
}
|
|
924
|
+
function addItem(val, key) {
|
|
925
|
+
if (
|
|
926
|
+
key === null ||
|
|
927
|
+
typeof key === "undefined" ||
|
|
928
|
+
key === types.unset
|
|
929
|
+
) {
|
|
930
|
+
throw new TypeError("A map can't contain null or unset keys")
|
|
931
|
+
}
|
|
932
|
+
if (
|
|
933
|
+
val === null ||
|
|
934
|
+
typeof val === "undefined" ||
|
|
935
|
+
val === types.unset
|
|
936
|
+
) {
|
|
937
|
+
throw new TypeError("A map can't contain null or unset values")
|
|
938
|
+
}
|
|
939
|
+
const keyBuffer = self.encode(key, keySubtype)
|
|
940
|
+
//include item byte length
|
|
941
|
+
parts.push(self.getLengthBuffer(keyBuffer))
|
|
942
|
+
//include item
|
|
943
|
+
parts.push(keyBuffer)
|
|
944
|
+
//value
|
|
945
|
+
const valueBuffer = self.encode(val, valueSubtype)
|
|
946
|
+
//include item byte length
|
|
947
|
+
parts.push(self.getLengthBuffer(valueBuffer))
|
|
948
|
+
//include item
|
|
949
|
+
if (valueBuffer !== null) {
|
|
950
|
+
parts.push(valueBuffer)
|
|
951
|
+
}
|
|
952
|
+
propCounter++
|
|
953
|
+
}
|
|
954
|
+
if (
|
|
955
|
+
this.encodingOptions.map &&
|
|
956
|
+
value instanceof this.encodingOptions.map
|
|
957
|
+
) {
|
|
958
|
+
//Use Map#forEach() method to iterate
|
|
959
|
+
value.forEach(addItem)
|
|
960
|
+
} else {
|
|
961
|
+
//Use object
|
|
962
|
+
for (const key in value) {
|
|
963
|
+
if (!value.hasOwnProperty(key)) {
|
|
964
|
+
continue
|
|
965
|
+
}
|
|
966
|
+
const val = value[key]
|
|
967
|
+
addItem(val, key)
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
parts.unshift(this.getLengthBuffer(propCounter))
|
|
972
|
+
return Buffer.concat(parts)
|
|
973
|
+
}
|
|
974
|
+
/**
|
|
975
|
+
*
|
|
976
|
+
* @param {any} value
|
|
977
|
+
* @param {UdtColumnInfo} columnInfo
|
|
978
|
+
*/
|
|
979
|
+
this.encodeUdt = function (value, columnInfo) {
|
|
980
|
+
const udtInfo = columnInfo.info
|
|
981
|
+
const parts = []
|
|
982
|
+
let totalLength = 0
|
|
983
|
+
for (let i = 0; i < udtInfo.fields.length; i++) {
|
|
984
|
+
const field = udtInfo.fields[i]
|
|
985
|
+
const item = this.encode(value[field.name], field.type)
|
|
986
|
+
if (!item) {
|
|
987
|
+
parts.push(nullValueBuffer)
|
|
988
|
+
totalLength += 4
|
|
989
|
+
continue
|
|
990
|
+
}
|
|
991
|
+
if (item === types.unset) {
|
|
992
|
+
parts.push(unsetValueBuffer)
|
|
993
|
+
totalLength += 4
|
|
994
|
+
continue
|
|
995
|
+
}
|
|
996
|
+
const lengthBuffer = utils.allocBufferUnsafe(4)
|
|
997
|
+
lengthBuffer.writeInt32BE(item.length, 0)
|
|
998
|
+
parts.push(lengthBuffer)
|
|
999
|
+
parts.push(item)
|
|
1000
|
+
totalLength += item.length + 4
|
|
1001
|
+
}
|
|
1002
|
+
return Buffer.concat(parts, totalLength)
|
|
1003
|
+
}
|
|
1004
|
+
/**
|
|
1005
|
+
*
|
|
1006
|
+
* @param {any} value
|
|
1007
|
+
* @param {TupleColumnInfo} columnInfo
|
|
1008
|
+
*/
|
|
1009
|
+
this.encodeTuple = function (value, columnInfo) {
|
|
1010
|
+
const tupleInfo = columnInfo.info
|
|
1011
|
+
const parts = []
|
|
1012
|
+
let totalLength = 0
|
|
1013
|
+
const length = Math.min(tupleInfo.length, value.length)
|
|
1014
|
+
|
|
1015
|
+
for (let i = 0; i < length; i++) {
|
|
1016
|
+
const type = tupleInfo[i]
|
|
1017
|
+
const item = this.encode(value.get(i), type)
|
|
1018
|
+
|
|
1019
|
+
if (!item) {
|
|
1020
|
+
parts.push(nullValueBuffer)
|
|
1021
|
+
totalLength += 4
|
|
1022
|
+
continue
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
if (item === types.unset) {
|
|
1026
|
+
parts.push(unsetValueBuffer)
|
|
1027
|
+
totalLength += 4
|
|
1028
|
+
continue
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
const lengthBuffer = utils.allocBufferUnsafe(4)
|
|
1032
|
+
lengthBuffer.writeInt32BE(item.length, 0)
|
|
1033
|
+
parts.push(lengthBuffer)
|
|
1034
|
+
parts.push(item)
|
|
1035
|
+
totalLength += item.length + 4
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
return Buffer.concat(parts, totalLength)
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
/**
|
|
1042
|
+
*
|
|
1043
|
+
* @param {Buffer} buffer
|
|
1044
|
+
* @param {VectorColumnInfo} params
|
|
1045
|
+
* @returns {Vector}
|
|
1046
|
+
*/
|
|
1047
|
+
this.decodeVector = function (buffer, params) {
|
|
1048
|
+
const subtype = params.info[0]
|
|
1049
|
+
const dimension = params.info[1]
|
|
1050
|
+
const elemLength = this.serializationSizeIfFixed(subtype)
|
|
1051
|
+
|
|
1052
|
+
const rv = []
|
|
1053
|
+
let offset = 0
|
|
1054
|
+
for (let i = 0; i < dimension; i++) {
|
|
1055
|
+
if (elemLength === -1) {
|
|
1056
|
+
// var sized
|
|
1057
|
+
const [size, bytesRead] = utils.VIntCoding.uvintUnpack(
|
|
1058
|
+
buffer.subarray(offset),
|
|
1059
|
+
)
|
|
1060
|
+
offset += bytesRead
|
|
1061
|
+
if (offset + size > buffer.length) {
|
|
1062
|
+
throw new TypeError("Not enough bytes to decode the vector")
|
|
1063
|
+
}
|
|
1064
|
+
rv[i] = this.decode(
|
|
1065
|
+
buffer.subarray(offset, offset + size),
|
|
1066
|
+
subtype,
|
|
1067
|
+
)
|
|
1068
|
+
offset += size
|
|
1069
|
+
} else {
|
|
1070
|
+
if (offset + elemLength > buffer.length) {
|
|
1071
|
+
throw new TypeError("Not enough bytes to decode the vector")
|
|
1072
|
+
}
|
|
1073
|
+
rv[i] = this.decode(
|
|
1074
|
+
buffer.subarray(offset, offset + elemLength),
|
|
1075
|
+
subtype,
|
|
1076
|
+
)
|
|
1077
|
+
offset += elemLength
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
if (offset !== buffer.length) {
|
|
1081
|
+
throw new TypeError("Extra bytes found after decoding the vector")
|
|
1082
|
+
}
|
|
1083
|
+
const typeInfo = types.getDataTypeNameByCode(subtype)
|
|
1084
|
+
return new Vector(rv, typeInfo)
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
/**
|
|
1088
|
+
* @param {ColumnInfo} cqlType
|
|
1089
|
+
* @returns {Number}
|
|
1090
|
+
*/
|
|
1091
|
+
this.serializationSizeIfFixed = function (cqlType) {
|
|
1092
|
+
switch (cqlType.code) {
|
|
1093
|
+
case dataTypes.bigint:
|
|
1094
|
+
return 8
|
|
1095
|
+
case dataTypes.boolean:
|
|
1096
|
+
return 1
|
|
1097
|
+
case dataTypes.timestamp:
|
|
1098
|
+
return 8
|
|
1099
|
+
case dataTypes.double:
|
|
1100
|
+
return 8
|
|
1101
|
+
case dataTypes.float:
|
|
1102
|
+
return 4
|
|
1103
|
+
case dataTypes.int:
|
|
1104
|
+
return 4
|
|
1105
|
+
case dataTypes.timeuuid:
|
|
1106
|
+
return 16
|
|
1107
|
+
case dataTypes.uuid:
|
|
1108
|
+
return 16
|
|
1109
|
+
case dataTypes.custom:
|
|
1110
|
+
if (
|
|
1111
|
+
"customTypeName" in cqlType &&
|
|
1112
|
+
cqlType.customTypeName === "vector"
|
|
1113
|
+
) {
|
|
1114
|
+
const subtypeSerialSize = this.serializationSizeIfFixed(
|
|
1115
|
+
cqlType.info[0],
|
|
1116
|
+
)
|
|
1117
|
+
if (subtypeSerialSize === -1) {
|
|
1118
|
+
return -1
|
|
1119
|
+
}
|
|
1120
|
+
return subtypeSerialSize * cqlType.info[1]
|
|
1121
|
+
}
|
|
1122
|
+
return -1
|
|
1123
|
+
default:
|
|
1124
|
+
return -1
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
/**
|
|
1128
|
+
* @param {Vector} value
|
|
1129
|
+
* @param {VectorColumnInfo} params
|
|
1130
|
+
* @returns {Buffer}
|
|
1131
|
+
*/
|
|
1132
|
+
this.encodeVector = function (value, params) {
|
|
1133
|
+
if (!(value instanceof Vector)) {
|
|
1134
|
+
throw new TypeError(
|
|
1135
|
+
"Driver only supports Vector type when encoding a vector",
|
|
1136
|
+
)
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
const dimension = params.info[1]
|
|
1140
|
+
if (value.length !== dimension) {
|
|
1141
|
+
throw new TypeError(
|
|
1142
|
+
`Expected vector with ${dimension} dimensions, observed size of ${value.length}`,
|
|
1143
|
+
)
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
if (value.length === 0) {
|
|
1147
|
+
throw new TypeError("Cannot encode empty array as vector")
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
const serializationSize = this.serializationSizeIfFixed(params.info[0])
|
|
1151
|
+
const encoded = []
|
|
1152
|
+
for (const elem of value) {
|
|
1153
|
+
const elemBuffer = this.encode(elem, params.info[0])
|
|
1154
|
+
if (serializationSize === -1) {
|
|
1155
|
+
encoded.push(utils.VIntCoding.uvintPack(elemBuffer.length))
|
|
1156
|
+
}
|
|
1157
|
+
encoded.push(elemBuffer)
|
|
1158
|
+
}
|
|
1159
|
+
return Buffer.concat(encoded)
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
/**
|
|
1163
|
+
* Extract the (typed) arguments from a vector type
|
|
1164
|
+
*
|
|
1165
|
+
* @param {String} typeName
|
|
1166
|
+
* @param {String} stringToExclude Leading string indicating this is a vector type (to be excluded when eval'ing args)
|
|
1167
|
+
* @param {Function} subtypeResolveFn Function used to resolve subtype type; varies depending on type naming convention
|
|
1168
|
+
* @returns {VectorColumnInfo}
|
|
1169
|
+
* @internal
|
|
1170
|
+
*/
|
|
1171
|
+
this.parseVectorTypeArgs = function (
|
|
1172
|
+
typeName,
|
|
1173
|
+
stringToExclude,
|
|
1174
|
+
subtypeResolveFn,
|
|
1175
|
+
) {
|
|
1176
|
+
const argsStartIndex = stringToExclude.length + 1
|
|
1177
|
+
const argsLength = typeName.length - (stringToExclude.length + 2)
|
|
1178
|
+
const params = parseParams(typeName, argsStartIndex, argsLength)
|
|
1179
|
+
if (params.length === 2) {
|
|
1180
|
+
/** @type {VectorColumnInfo} */
|
|
1181
|
+
const columnInfo = {
|
|
1182
|
+
code: dataTypes.custom,
|
|
1183
|
+
info: [
|
|
1184
|
+
subtypeResolveFn.bind(this)(params[0].trim()),
|
|
1185
|
+
parseInt(params[1].trim(), 10),
|
|
1186
|
+
],
|
|
1187
|
+
customTypeName: "vector",
|
|
1188
|
+
}
|
|
1189
|
+
return columnInfo
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
throw new TypeError("Not a valid type " + typeName)
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
/**
|
|
1196
|
+
* If not provided, it uses the array of buffers or the parameters and hints to build the routingKey
|
|
1197
|
+
* @param {Array} params
|
|
1198
|
+
* @param [keys] parameter keys and positions in the params array
|
|
1199
|
+
* @throws TypeError
|
|
1200
|
+
* @internal
|
|
1201
|
+
* @ignore
|
|
1202
|
+
*/
|
|
1203
|
+
this.setRoutingKeyFromUser = function (params, execOptions, keys) {
|
|
1204
|
+
let totalLength = 0
|
|
1205
|
+
const userRoutingKey = execOptions.getRoutingKey()
|
|
1206
|
+
if (Array.isArray(userRoutingKey)) {
|
|
1207
|
+
if (userRoutingKey.length === 1) {
|
|
1208
|
+
execOptions.setRoutingKey(userRoutingKey[0])
|
|
1209
|
+
return
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
// Its a composite routing key
|
|
1213
|
+
totalLength = 0
|
|
1214
|
+
for (let i = 0; i < userRoutingKey.length; i++) {
|
|
1215
|
+
const item = userRoutingKey[i]
|
|
1216
|
+
if (!item) {
|
|
1217
|
+
// Invalid routing key part provided by the user, clear the value
|
|
1218
|
+
execOptions.setRoutingKey(null)
|
|
1219
|
+
return
|
|
1220
|
+
}
|
|
1221
|
+
totalLength += item.length + 3
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
execOptions.setRoutingKey(
|
|
1225
|
+
concatRoutingKey(userRoutingKey, totalLength),
|
|
1226
|
+
)
|
|
1227
|
+
return
|
|
1228
|
+
}
|
|
1229
|
+
// If routingKey is present, ensure it is a Buffer, Token, or TokenRange. Otherwise throw an error.
|
|
1230
|
+
if (userRoutingKey) {
|
|
1231
|
+
if (
|
|
1232
|
+
userRoutingKey instanceof Buffer ||
|
|
1233
|
+
userRoutingKey instanceof token.Token ||
|
|
1234
|
+
userRoutingKey instanceof token.TokenRange
|
|
1235
|
+
) {
|
|
1236
|
+
return
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
throw new TypeError(
|
|
1240
|
+
`Unexpected routingKey '${util.inspect(userRoutingKey)}' provided. ` +
|
|
1241
|
+
`Expected Buffer, Array<Buffer>, Token, or TokenRange.`,
|
|
1242
|
+
)
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
// If no params are present, return as routing key cannot be determined.
|
|
1246
|
+
if (!params || params.length === 0) {
|
|
1247
|
+
return
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
let routingIndexes = execOptions.getRoutingIndexes()
|
|
1251
|
+
if (execOptions.getRoutingNames()) {
|
|
1252
|
+
routingIndexes = execOptions.getRoutingNames().map((k) => keys[k])
|
|
1253
|
+
}
|
|
1254
|
+
if (!routingIndexes) {
|
|
1255
|
+
return
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
const parts = []
|
|
1259
|
+
const hints = execOptions.getHints() || utils.emptyArray
|
|
1260
|
+
|
|
1261
|
+
const encodeParam = !keys
|
|
1262
|
+
? (i) => this.encode(params[i], hints[i])
|
|
1263
|
+
: (i) => this.encode(params[i].value, hints[i])
|
|
1264
|
+
|
|
1265
|
+
try {
|
|
1266
|
+
totalLength = this._encodeRoutingKeyParts(
|
|
1267
|
+
parts,
|
|
1268
|
+
routingIndexes,
|
|
1269
|
+
encodeParam,
|
|
1270
|
+
)
|
|
1271
|
+
} catch (e) {
|
|
1272
|
+
// There was an error encoding a parameter that is part of the routing key,
|
|
1273
|
+
// ignore now to fail afterwards
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
if (totalLength === 0) {
|
|
1277
|
+
return
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
execOptions.setRoutingKey(concatRoutingKey(parts, totalLength))
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
/**
|
|
1284
|
+
* Sets the routing key in the options based on the prepared statement metadata.
|
|
1285
|
+
* @param {Object} meta Prepared metadata
|
|
1286
|
+
* @param {Array} params Array of parameters
|
|
1287
|
+
* @param {ExecutionOptions} execOptions
|
|
1288
|
+
* @throws TypeError
|
|
1289
|
+
* @internal
|
|
1290
|
+
* @ignore
|
|
1291
|
+
*/
|
|
1292
|
+
this.setRoutingKeyFromMeta = function (meta, params, execOptions) {
|
|
1293
|
+
const routingIndexes = execOptions.getRoutingIndexes()
|
|
1294
|
+
if (!routingIndexes) {
|
|
1295
|
+
return
|
|
1296
|
+
}
|
|
1297
|
+
const parts = new Array(routingIndexes.length)
|
|
1298
|
+
const encodeParam = (i) => {
|
|
1299
|
+
const columnInfo = meta.columns[i]
|
|
1300
|
+
return this.encode(params[i], columnInfo ? columnInfo.type : null)
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
let totalLength = 0
|
|
1304
|
+
|
|
1305
|
+
try {
|
|
1306
|
+
totalLength = this._encodeRoutingKeyParts(
|
|
1307
|
+
parts,
|
|
1308
|
+
routingIndexes,
|
|
1309
|
+
encodeParam,
|
|
1310
|
+
)
|
|
1311
|
+
} catch (e) {
|
|
1312
|
+
// There was an error encoding a parameter that is part of the routing key,
|
|
1313
|
+
// ignore now to fail afterwards
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
if (totalLength === 0) {
|
|
1317
|
+
return
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
execOptions.setRoutingKey(concatRoutingKey(parts, totalLength))
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
/**
|
|
1324
|
+
* @param {Array} parts
|
|
1325
|
+
* @param {Array} routingIndexes
|
|
1326
|
+
* @param {Function} encodeParam
|
|
1327
|
+
* @returns {Number} The total length
|
|
1328
|
+
* @private
|
|
1329
|
+
*/
|
|
1330
|
+
this._encodeRoutingKeyParts = function (
|
|
1331
|
+
parts,
|
|
1332
|
+
routingIndexes,
|
|
1333
|
+
encodeParam,
|
|
1334
|
+
) {
|
|
1335
|
+
let totalLength = 0
|
|
1336
|
+
for (let i = 0; i < routingIndexes.length; i++) {
|
|
1337
|
+
const paramIndex = routingIndexes[i]
|
|
1338
|
+
if (paramIndex === undefined) {
|
|
1339
|
+
// Bad input from the user, ignore
|
|
1340
|
+
return 0
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
const item = encodeParam(paramIndex)
|
|
1344
|
+
if (item === null || item === undefined || item === types.unset) {
|
|
1345
|
+
// The encoded partition key should an instance of Buffer
|
|
1346
|
+
// Let it fail later in the pipeline for null/undefined parameter values
|
|
1347
|
+
return 0
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
// Per each part of the routing key, 3 extra bytes are needed
|
|
1351
|
+
totalLength += item.length + 3
|
|
1352
|
+
parts[i] = item
|
|
1353
|
+
}
|
|
1354
|
+
return totalLength
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
/**
|
|
1358
|
+
* Parses a CQL name string into data type information
|
|
1359
|
+
* @param {String} keyspace
|
|
1360
|
+
* @param {String} typeName
|
|
1361
|
+
* @param {Number} startIndex
|
|
1362
|
+
* @param {Number|null} length
|
|
1363
|
+
* @param {Function} udtResolver
|
|
1364
|
+
* @async
|
|
1365
|
+
* @returns {Promise.<ColumnInfo>} callback Callback invoked with err and {{code: number, info: Object|Array|null, options: {frozen: Boolean}}}
|
|
1366
|
+
* @internal
|
|
1367
|
+
* @throws {Error}
|
|
1368
|
+
* @ignore
|
|
1369
|
+
*/
|
|
1370
|
+
this.parseTypeName = async function (
|
|
1371
|
+
keyspace,
|
|
1372
|
+
typeName,
|
|
1373
|
+
startIndex,
|
|
1374
|
+
length,
|
|
1375
|
+
udtResolver,
|
|
1376
|
+
) {
|
|
1377
|
+
startIndex = startIndex || 0
|
|
1378
|
+
if (!length) {
|
|
1379
|
+
length = typeName.length
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
let innerTypes
|
|
1383
|
+
let frozen = false
|
|
1384
|
+
|
|
1385
|
+
if (typeName.indexOf("'", startIndex) === startIndex) {
|
|
1386
|
+
//If quoted, this is a custom type.
|
|
1387
|
+
const info = typeName.substr(startIndex + 1, length - 2)
|
|
1388
|
+
return {
|
|
1389
|
+
code: dataTypes.custom,
|
|
1390
|
+
info: info,
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
if (!length) {
|
|
1395
|
+
length = typeName.length
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
if (typeName.indexOf(cqlNames.frozen, startIndex) === startIndex) {
|
|
1399
|
+
//Remove the frozen token
|
|
1400
|
+
startIndex += cqlNames.frozen.length + 1
|
|
1401
|
+
length -= cqlNames.frozen.length + 2
|
|
1402
|
+
frozen = true
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
if (typeName.indexOf(cqlNames.list, startIndex) === startIndex) {
|
|
1406
|
+
//move cursor across the name and bypass the angle brackets
|
|
1407
|
+
startIndex += cqlNames.list.length + 1
|
|
1408
|
+
length -= cqlNames.list.length + 2
|
|
1409
|
+
innerTypes = parseParams(typeName, startIndex, length, "<", ">")
|
|
1410
|
+
|
|
1411
|
+
if (innerTypes.length !== 1) {
|
|
1412
|
+
throw new TypeError("Not a valid type " + typeName)
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
const info = await this.parseTypeName(
|
|
1416
|
+
keyspace,
|
|
1417
|
+
innerTypes[0],
|
|
1418
|
+
0,
|
|
1419
|
+
null,
|
|
1420
|
+
udtResolver,
|
|
1421
|
+
)
|
|
1422
|
+
return {
|
|
1423
|
+
code: dataTypes.list,
|
|
1424
|
+
info: info,
|
|
1425
|
+
options: {
|
|
1426
|
+
frozen: frozen,
|
|
1427
|
+
},
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
if (typeName.indexOf(cqlNames.set, startIndex) === startIndex) {
|
|
1432
|
+
//move cursor across the name and bypass the angle brackets
|
|
1433
|
+
startIndex += cqlNames.set.length + 1
|
|
1434
|
+
length -= cqlNames.set.length + 2
|
|
1435
|
+
innerTypes = parseParams(typeName, startIndex, length, "<", ">")
|
|
1436
|
+
|
|
1437
|
+
if (innerTypes.length !== 1) {
|
|
1438
|
+
throw new TypeError("Not a valid type " + typeName)
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
const info = await this.parseTypeName(
|
|
1442
|
+
keyspace,
|
|
1443
|
+
innerTypes[0],
|
|
1444
|
+
0,
|
|
1445
|
+
null,
|
|
1446
|
+
udtResolver,
|
|
1447
|
+
)
|
|
1448
|
+
return {
|
|
1449
|
+
code: dataTypes.set,
|
|
1450
|
+
info: info,
|
|
1451
|
+
options: {
|
|
1452
|
+
frozen: frozen,
|
|
1453
|
+
},
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
if (typeName.indexOf(cqlNames.map, startIndex) === startIndex) {
|
|
1458
|
+
//move cursor across the name and bypass the angle brackets
|
|
1459
|
+
startIndex += cqlNames.map.length + 1
|
|
1460
|
+
length -= cqlNames.map.length + 2
|
|
1461
|
+
innerTypes = parseParams(typeName, startIndex, length, "<", ">")
|
|
1462
|
+
|
|
1463
|
+
//It should contain the key and value types
|
|
1464
|
+
if (innerTypes.length !== 2) {
|
|
1465
|
+
throw new TypeError("Not a valid type " + typeName)
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
const info = await this._parseChildTypes(
|
|
1469
|
+
keyspace,
|
|
1470
|
+
innerTypes,
|
|
1471
|
+
udtResolver,
|
|
1472
|
+
)
|
|
1473
|
+
return {
|
|
1474
|
+
code: dataTypes.map,
|
|
1475
|
+
info: info,
|
|
1476
|
+
options: {
|
|
1477
|
+
frozen: frozen,
|
|
1478
|
+
},
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
if (typeName.indexOf(cqlNames.tuple, startIndex) === startIndex) {
|
|
1483
|
+
//move cursor across the name and bypass the angle brackets
|
|
1484
|
+
startIndex += cqlNames.tuple.length + 1
|
|
1485
|
+
length -= cqlNames.tuple.length + 2
|
|
1486
|
+
innerTypes = parseParams(typeName, startIndex, length, "<", ">")
|
|
1487
|
+
|
|
1488
|
+
if (innerTypes.length < 1) {
|
|
1489
|
+
throw new TypeError("Not a valid type " + typeName)
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
const info = await this._parseChildTypes(
|
|
1493
|
+
keyspace,
|
|
1494
|
+
innerTypes,
|
|
1495
|
+
udtResolver,
|
|
1496
|
+
)
|
|
1497
|
+
return {
|
|
1498
|
+
code: dataTypes.tuple,
|
|
1499
|
+
info: info,
|
|
1500
|
+
options: { frozen: frozen },
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
if (typeName.indexOf(cqlNames.vector, startIndex) === startIndex) {
|
|
1505
|
+
// It's a vector, so record the subtype and dimension.
|
|
1506
|
+
|
|
1507
|
+
// parseVectorTypeArgs is not an async function but we are. To keep things simple let's ask the
|
|
1508
|
+
// function to just return whatever it finds for an arg and we'll eval it after the fact
|
|
1509
|
+
const params = this.parseVectorTypeArgs.bind(this)(
|
|
1510
|
+
typeName,
|
|
1511
|
+
cqlNames.vector,
|
|
1512
|
+
(arg) => arg,
|
|
1513
|
+
)
|
|
1514
|
+
params["info"][0] = await this.parseTypeName(
|
|
1515
|
+
keyspace,
|
|
1516
|
+
params["info"][0],
|
|
1517
|
+
)
|
|
1518
|
+
|
|
1519
|
+
return params
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
const quoted = typeName.indexOf('"', startIndex) === startIndex
|
|
1523
|
+
if (quoted) {
|
|
1524
|
+
// Remove quotes
|
|
1525
|
+
startIndex++
|
|
1526
|
+
length -= 2
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
// Quick check if its a single type
|
|
1530
|
+
if (startIndex > 0) {
|
|
1531
|
+
typeName = typeName.substr(startIndex, length)
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
// Un-escape double quotes if quoted.
|
|
1535
|
+
if (quoted) {
|
|
1536
|
+
typeName = typeName.replace('""', '"')
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
const typeCode = dataTypes[typeName]
|
|
1540
|
+
if (typeof typeCode === "number") {
|
|
1541
|
+
return { code: typeCode, info: null }
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
if (typeName === cqlNames.duration) {
|
|
1545
|
+
return { code: dataTypes.custom, info: customTypeNames.duration }
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
if (typeName === cqlNames.empty) {
|
|
1549
|
+
// Set as custom
|
|
1550
|
+
return { code: dataTypes.custom, info: "empty" }
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
const udtInfo = await udtResolver(keyspace, typeName)
|
|
1554
|
+
if (udtInfo) {
|
|
1555
|
+
return {
|
|
1556
|
+
code: dataTypes.udt,
|
|
1557
|
+
info: udtInfo,
|
|
1558
|
+
options: {
|
|
1559
|
+
frozen: frozen,
|
|
1560
|
+
},
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
throw new TypeError('Not a valid type "' + typeName + '"')
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
/**
|
|
1568
|
+
* @param {String} keyspace
|
|
1569
|
+
* @param {Array} typeNames
|
|
1570
|
+
* @param {Function} udtResolver
|
|
1571
|
+
* @returns {Promise}
|
|
1572
|
+
* @private
|
|
1573
|
+
*/
|
|
1574
|
+
this._parseChildTypes = function (keyspace, typeNames, udtResolver) {
|
|
1575
|
+
return Promise.all(
|
|
1576
|
+
typeNames.map((name) =>
|
|
1577
|
+
this.parseTypeName(keyspace, name.trim(), 0, null, udtResolver),
|
|
1578
|
+
),
|
|
1579
|
+
)
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
/**
|
|
1583
|
+
* Parses a Cassandra fully-qualified class name string into data type information
|
|
1584
|
+
* @param {String} typeName
|
|
1585
|
+
* @param {Number} [startIndex]
|
|
1586
|
+
* @param {Number} [length]
|
|
1587
|
+
* @throws {TypeError}
|
|
1588
|
+
* @returns {ColumnInfo}
|
|
1589
|
+
* @internal
|
|
1590
|
+
* @ignore
|
|
1591
|
+
*/
|
|
1592
|
+
this.parseFqTypeName = function (typeName, startIndex, length) {
|
|
1593
|
+
let frozen = false
|
|
1594
|
+
let reversed = false
|
|
1595
|
+
startIndex = startIndex || 0
|
|
1596
|
+
let params
|
|
1597
|
+
if (!length) {
|
|
1598
|
+
length = typeName.length
|
|
1599
|
+
}
|
|
1600
|
+
if (
|
|
1601
|
+
length > complexTypeNames.reversed.length &&
|
|
1602
|
+
typeName.indexOf(complexTypeNames.reversed) === startIndex
|
|
1603
|
+
) {
|
|
1604
|
+
//Remove the reversed token
|
|
1605
|
+
startIndex += complexTypeNames.reversed.length + 1
|
|
1606
|
+
length -= complexTypeNames.reversed.length + 2
|
|
1607
|
+
reversed = true
|
|
1608
|
+
}
|
|
1609
|
+
if (
|
|
1610
|
+
length > complexTypeNames.frozen.length &&
|
|
1611
|
+
typeName.indexOf(complexTypeNames.frozen, startIndex) === startIndex
|
|
1612
|
+
) {
|
|
1613
|
+
//Remove the frozen token
|
|
1614
|
+
startIndex += complexTypeNames.frozen.length + 1
|
|
1615
|
+
length -= complexTypeNames.frozen.length + 2
|
|
1616
|
+
frozen = true
|
|
1617
|
+
}
|
|
1618
|
+
const options = {
|
|
1619
|
+
frozen: frozen,
|
|
1620
|
+
reversed: reversed,
|
|
1621
|
+
}
|
|
1622
|
+
if (typeName === complexTypeNames.empty) {
|
|
1623
|
+
//set as custom
|
|
1624
|
+
return {
|
|
1625
|
+
code: dataTypes.custom,
|
|
1626
|
+
info: "empty",
|
|
1627
|
+
options: options,
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
//Quick check if its a single type
|
|
1631
|
+
if (length <= singleFqTypeNamesLength) {
|
|
1632
|
+
if (startIndex > 0) {
|
|
1633
|
+
typeName = typeName.substr(startIndex, length)
|
|
1634
|
+
}
|
|
1635
|
+
const typeCode = singleTypeNames[typeName]
|
|
1636
|
+
if (typeof typeCode === "number") {
|
|
1637
|
+
return { code: typeCode, info: null, options: options }
|
|
1638
|
+
}
|
|
1639
|
+
// special handling for duration
|
|
1640
|
+
if (typeName === customTypeNames.duration) {
|
|
1641
|
+
return { code: dataTypes.duration, options: options }
|
|
1642
|
+
}
|
|
1643
|
+
throw new TypeError('Not a valid type "' + typeName + '"')
|
|
1644
|
+
}
|
|
1645
|
+
if (
|
|
1646
|
+
typeName.indexOf(complexTypeNames.list, startIndex) === startIndex
|
|
1647
|
+
) {
|
|
1648
|
+
//Its a list
|
|
1649
|
+
//org.apache.cassandra.db.marshal.ListType(innerType)
|
|
1650
|
+
//move cursor across the name and bypass the parenthesis
|
|
1651
|
+
startIndex += complexTypeNames.list.length + 1
|
|
1652
|
+
length -= complexTypeNames.list.length + 2
|
|
1653
|
+
params = parseParams(typeName, startIndex, length)
|
|
1654
|
+
if (params.length !== 1) {
|
|
1655
|
+
throw new TypeError("Not a valid type " + typeName)
|
|
1656
|
+
}
|
|
1657
|
+
const info = this.parseFqTypeName(params[0])
|
|
1658
|
+
return {
|
|
1659
|
+
code: dataTypes.list,
|
|
1660
|
+
info: info,
|
|
1661
|
+
options: options,
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
if (typeName.indexOf(complexTypeNames.set, startIndex) === startIndex) {
|
|
1665
|
+
//Its a set
|
|
1666
|
+
//org.apache.cassandra.db.marshal.SetType(innerType)
|
|
1667
|
+
//move cursor across the name and bypass the parenthesis
|
|
1668
|
+
startIndex += complexTypeNames.set.length + 1
|
|
1669
|
+
length -= complexTypeNames.set.length + 2
|
|
1670
|
+
params = parseParams(typeName, startIndex, length)
|
|
1671
|
+
if (params.length !== 1) {
|
|
1672
|
+
throw new TypeError("Not a valid type " + typeName)
|
|
1673
|
+
}
|
|
1674
|
+
const info = this.parseFqTypeName(params[0])
|
|
1675
|
+
return {
|
|
1676
|
+
code: dataTypes.set,
|
|
1677
|
+
info: info,
|
|
1678
|
+
options: options,
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
if (typeName.indexOf(complexTypeNames.map, startIndex) === startIndex) {
|
|
1682
|
+
//org.apache.cassandra.db.marshal.MapType(keyType,valueType)
|
|
1683
|
+
//move cursor across the name and bypass the parenthesis
|
|
1684
|
+
startIndex += complexTypeNames.map.length + 1
|
|
1685
|
+
length -= complexTypeNames.map.length + 2
|
|
1686
|
+
params = parseParams(typeName, startIndex, length)
|
|
1687
|
+
//It should contain the key and value types
|
|
1688
|
+
if (params.length !== 2) {
|
|
1689
|
+
throw new TypeError("Not a valid type " + typeName)
|
|
1690
|
+
}
|
|
1691
|
+
const info1 = this.parseFqTypeName(params[0])
|
|
1692
|
+
const info2 = this.parseFqTypeName(params[1])
|
|
1693
|
+
return {
|
|
1694
|
+
code: dataTypes.map,
|
|
1695
|
+
info: [info1, info2],
|
|
1696
|
+
options: options,
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
if (typeName.indexOf(complexTypeNames.udt, startIndex) === startIndex) {
|
|
1700
|
+
//move cursor across the name and bypass the parenthesis
|
|
1701
|
+
startIndex += complexTypeNames.udt.length + 1
|
|
1702
|
+
length -= complexTypeNames.udt.length + 2
|
|
1703
|
+
const udtType = this._parseUdtName(typeName, startIndex, length)
|
|
1704
|
+
udtType.options = options
|
|
1705
|
+
return udtType
|
|
1706
|
+
}
|
|
1707
|
+
if (
|
|
1708
|
+
typeName.indexOf(complexTypeNames.tuple, startIndex) === startIndex
|
|
1709
|
+
) {
|
|
1710
|
+
//move cursor across the name and bypass the parenthesis
|
|
1711
|
+
startIndex += complexTypeNames.tuple.length + 1
|
|
1712
|
+
length -= complexTypeNames.tuple.length + 2
|
|
1713
|
+
params = parseParams(typeName, startIndex, length)
|
|
1714
|
+
if (params.length < 1) {
|
|
1715
|
+
throw new TypeError("Not a valid type " + typeName)
|
|
1716
|
+
}
|
|
1717
|
+
const info = params.map((x) => this.parseFqTypeName(x))
|
|
1718
|
+
return {
|
|
1719
|
+
code: dataTypes.tuple,
|
|
1720
|
+
info: info,
|
|
1721
|
+
options: options,
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
if (
|
|
1726
|
+
typeName.indexOf(customTypeNames.vector, startIndex) === startIndex
|
|
1727
|
+
) {
|
|
1728
|
+
// It's a vector, so record the subtype and dimension.
|
|
1729
|
+
const params = this.parseVectorTypeArgs.bind(this)(
|
|
1730
|
+
typeName,
|
|
1731
|
+
customTypeNames.vector,
|
|
1732
|
+
this.parseFqTypeName,
|
|
1733
|
+
)
|
|
1734
|
+
params.options = options
|
|
1735
|
+
return params
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
// Assume custom type if cannot be parsed up to this point.
|
|
1739
|
+
const info = typeName.substr(startIndex, length)
|
|
1740
|
+
return {
|
|
1741
|
+
code: dataTypes.custom,
|
|
1742
|
+
info: info,
|
|
1743
|
+
options: options,
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
/**
|
|
1747
|
+
* Parses type names with composites
|
|
1748
|
+
* @param {String} typesString
|
|
1749
|
+
* @returns {{types: Array, isComposite: Boolean, hasCollections: Boolean}}
|
|
1750
|
+
* @internal
|
|
1751
|
+
* @ignore
|
|
1752
|
+
*/
|
|
1753
|
+
this.parseKeyTypes = function (typesString) {
|
|
1754
|
+
let i = 0
|
|
1755
|
+
let length = typesString.length
|
|
1756
|
+
const isComposite =
|
|
1757
|
+
typesString.indexOf(complexTypeNames.composite) === 0
|
|
1758
|
+
if (isComposite) {
|
|
1759
|
+
i = complexTypeNames.composite.length + 1
|
|
1760
|
+
length--
|
|
1761
|
+
}
|
|
1762
|
+
const types = []
|
|
1763
|
+
let startIndex = i
|
|
1764
|
+
let nested = 0
|
|
1765
|
+
let inCollectionType = false
|
|
1766
|
+
let hasCollections = false
|
|
1767
|
+
//as collection types are not allowed, it is safe to split by ,
|
|
1768
|
+
while (++i < length) {
|
|
1769
|
+
switch (typesString[i]) {
|
|
1770
|
+
case ",":
|
|
1771
|
+
if (nested > 0) {
|
|
1772
|
+
break
|
|
1773
|
+
}
|
|
1774
|
+
if (inCollectionType) {
|
|
1775
|
+
//remove type id
|
|
1776
|
+
startIndex = typesString.indexOf(":", startIndex) + 1
|
|
1777
|
+
}
|
|
1778
|
+
types.push(typesString.substring(startIndex, i))
|
|
1779
|
+
startIndex = i + 1
|
|
1780
|
+
break
|
|
1781
|
+
case "(":
|
|
1782
|
+
if (
|
|
1783
|
+
nested === 0 &&
|
|
1784
|
+
typesString.indexOf(
|
|
1785
|
+
complexTypeNames.collection,
|
|
1786
|
+
startIndex,
|
|
1787
|
+
) === startIndex
|
|
1788
|
+
) {
|
|
1789
|
+
inCollectionType = true
|
|
1790
|
+
hasCollections = true
|
|
1791
|
+
//skip collection type
|
|
1792
|
+
i++
|
|
1793
|
+
startIndex = i
|
|
1794
|
+
break
|
|
1795
|
+
}
|
|
1796
|
+
nested++
|
|
1797
|
+
break
|
|
1798
|
+
case ")":
|
|
1799
|
+
if (inCollectionType && nested === 0) {
|
|
1800
|
+
types.push(
|
|
1801
|
+
typesString.substring(
|
|
1802
|
+
typesString.indexOf(":", startIndex) + 1,
|
|
1803
|
+
i,
|
|
1804
|
+
),
|
|
1805
|
+
)
|
|
1806
|
+
startIndex = i + 1
|
|
1807
|
+
break
|
|
1808
|
+
}
|
|
1809
|
+
nested--
|
|
1810
|
+
break
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
if (startIndex < length) {
|
|
1814
|
+
types.push(typesString.substring(startIndex, length))
|
|
1815
|
+
}
|
|
1816
|
+
return {
|
|
1817
|
+
types: types.map((name) => this.parseFqTypeName(name)),
|
|
1818
|
+
hasCollections: hasCollections,
|
|
1819
|
+
isComposite: isComposite,
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
/**
|
|
1823
|
+
*
|
|
1824
|
+
* @param {string} typeName
|
|
1825
|
+
* @param {number} startIndex
|
|
1826
|
+
* @param {number} length
|
|
1827
|
+
* @returns {UdtColumnInfo}
|
|
1828
|
+
*/
|
|
1829
|
+
this._parseUdtName = function (typeName, startIndex, length) {
|
|
1830
|
+
const udtParams = parseParams(typeName, startIndex, length)
|
|
1831
|
+
if (udtParams.length < 2) {
|
|
1832
|
+
//It should contain at least the keyspace, name of the udt and a type
|
|
1833
|
+
throw new TypeError("Not a valid type " + typeName)
|
|
1834
|
+
}
|
|
1835
|
+
/**
|
|
1836
|
+
* @type {{keyspace: String, name: String, fields: Array}}
|
|
1837
|
+
*/
|
|
1838
|
+
const udtInfo = {
|
|
1839
|
+
keyspace: udtParams[0],
|
|
1840
|
+
name: utils.allocBufferFromString(udtParams[1], "hex").toString(),
|
|
1841
|
+
fields: [],
|
|
1842
|
+
}
|
|
1843
|
+
for (let i = 2; i < udtParams.length; i++) {
|
|
1844
|
+
const p = udtParams[i]
|
|
1845
|
+
const separatorIndex = p.indexOf(":")
|
|
1846
|
+
const fieldType = this.parseFqTypeName(
|
|
1847
|
+
p,
|
|
1848
|
+
separatorIndex + 1,
|
|
1849
|
+
p.length - (separatorIndex + 1),
|
|
1850
|
+
)
|
|
1851
|
+
udtInfo.fields.push({
|
|
1852
|
+
name: utils
|
|
1853
|
+
.allocBufferFromString(p.substr(0, separatorIndex), "hex")
|
|
1854
|
+
.toString(),
|
|
1855
|
+
type: fieldType,
|
|
1856
|
+
})
|
|
1857
|
+
}
|
|
1858
|
+
return {
|
|
1859
|
+
code: dataTypes.udt,
|
|
1860
|
+
info: udtInfo,
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
}
|
|
1864
|
+
|
|
1865
|
+
/**
|
|
1866
|
+
* Sets the encoder and decoder methods for this instance
|
|
1867
|
+
* @private
|
|
1868
|
+
*/
|
|
1869
|
+
function setEncoders() {
|
|
1870
|
+
this.decoders = {
|
|
1871
|
+
[dataTypes.custom]: this.decodeCustom,
|
|
1872
|
+
[dataTypes.ascii]: this.decodeAsciiString,
|
|
1873
|
+
[dataTypes.bigint]: this.decodeLong,
|
|
1874
|
+
[dataTypes.blob]: this.decodeBlob,
|
|
1875
|
+
[dataTypes.boolean]: this.decodeBoolean,
|
|
1876
|
+
[dataTypes.counter]: this.decodeLong,
|
|
1877
|
+
[dataTypes.decimal]: this.decodeDecimal,
|
|
1878
|
+
[dataTypes.double]: this.decodeDouble,
|
|
1879
|
+
[dataTypes.float]: this.decodeFloat,
|
|
1880
|
+
[dataTypes.int]: this.decodeInt,
|
|
1881
|
+
[dataTypes.text]: this.decodeUtf8String,
|
|
1882
|
+
[dataTypes.timestamp]: this.decodeTimestamp,
|
|
1883
|
+
[dataTypes.uuid]: this.decodeUuid,
|
|
1884
|
+
[dataTypes.varchar]: this.decodeUtf8String,
|
|
1885
|
+
[dataTypes.varint]: this.decodeVarint,
|
|
1886
|
+
[dataTypes.timeuuid]: this.decodeTimeUuid,
|
|
1887
|
+
[dataTypes.inet]: this.decodeInet,
|
|
1888
|
+
[dataTypes.date]: this.decodeDate,
|
|
1889
|
+
[dataTypes.time]: this.decodeTime,
|
|
1890
|
+
[dataTypes.smallint]: this.decodeSmallint,
|
|
1891
|
+
[dataTypes.tinyint]: this.decodeTinyint,
|
|
1892
|
+
[dataTypes.duration]: decodeDuration,
|
|
1893
|
+
[dataTypes.list]: this.decodeList,
|
|
1894
|
+
[dataTypes.map]: this.decodeMap,
|
|
1895
|
+
[dataTypes.set]: this.decodeSet,
|
|
1896
|
+
[dataTypes.udt]: this.decodeUdt,
|
|
1897
|
+
[dataTypes.tuple]: this.decodeTuple,
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
this.encoders = {
|
|
1901
|
+
[dataTypes.custom]: this.encodeCustom,
|
|
1902
|
+
[dataTypes.ascii]: this.encodeAsciiString,
|
|
1903
|
+
[dataTypes.bigint]: this.encodeLong,
|
|
1904
|
+
[dataTypes.blob]: this.encodeBlob,
|
|
1905
|
+
[dataTypes.boolean]: this.encodeBoolean,
|
|
1906
|
+
[dataTypes.counter]: this.encodeLong,
|
|
1907
|
+
[dataTypes.decimal]: this.encodeDecimal,
|
|
1908
|
+
[dataTypes.double]: this.encodeDouble,
|
|
1909
|
+
[dataTypes.float]: this.encodeFloat,
|
|
1910
|
+
[dataTypes.int]: this.encodeInt,
|
|
1911
|
+
[dataTypes.text]: this.encodeUtf8String,
|
|
1912
|
+
[dataTypes.timestamp]: this.encodeTimestamp,
|
|
1913
|
+
[dataTypes.uuid]: this.encodeUuid,
|
|
1914
|
+
[dataTypes.varchar]: this.encodeUtf8String,
|
|
1915
|
+
[dataTypes.varint]: this.encodeVarint,
|
|
1916
|
+
[dataTypes.timeuuid]: this.encodeUuid,
|
|
1917
|
+
[dataTypes.inet]: this.encodeInet,
|
|
1918
|
+
[dataTypes.date]: this.encodeDate,
|
|
1919
|
+
[dataTypes.time]: this.encodeTime,
|
|
1920
|
+
[dataTypes.smallint]: this.encodeSmallint,
|
|
1921
|
+
[dataTypes.tinyint]: this.encodeTinyint,
|
|
1922
|
+
[dataTypes.duration]: encodeDuration,
|
|
1923
|
+
[dataTypes.list]: this.encodeList,
|
|
1924
|
+
[dataTypes.map]: this.encodeMap,
|
|
1925
|
+
[dataTypes.set]: this.encodeSet,
|
|
1926
|
+
[dataTypes.udt]: this.encodeUdt,
|
|
1927
|
+
[dataTypes.tuple]: this.encodeTuple,
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
/**
|
|
1932
|
+
* Decodes Cassandra bytes into Javascript values.
|
|
1933
|
+
* <p>
|
|
1934
|
+
* This is part of an <b>experimental</b> API, this can be changed future releases.
|
|
1935
|
+
* </p>
|
|
1936
|
+
* @param {Buffer} buffer Raw buffer to be decoded.
|
|
1937
|
+
* @param {ColumnInfo} type
|
|
1938
|
+
*/
|
|
1939
|
+
Encoder.prototype.decode = function (buffer, type) {
|
|
1940
|
+
if (
|
|
1941
|
+
buffer === null ||
|
|
1942
|
+
(buffer.length === 0 && !zeroLengthTypesSupported.has(type.code))
|
|
1943
|
+
) {
|
|
1944
|
+
return null
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
const decoder = this.decoders[type.code]
|
|
1948
|
+
|
|
1949
|
+
if (!decoder) {
|
|
1950
|
+
throw new Error("Unknown data type: " + type.code)
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1953
|
+
return decoder.call(this, buffer, type)
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
/**
|
|
1957
|
+
* Encodes Javascript types into Buffer according to the Cassandra protocol.
|
|
1958
|
+
* <p>
|
|
1959
|
+
* This is part of an <b>experimental</b> API, this can be changed future releases.
|
|
1960
|
+
* </p>
|
|
1961
|
+
* @param {*} value The value to be converted.
|
|
1962
|
+
* @param {ColumnInfo | Number | String} typeInfo The type information.
|
|
1963
|
+
* <p>It can be either a:</p>
|
|
1964
|
+
* <ul>
|
|
1965
|
+
* <li>A <code>String</code> representing the data type.</li>
|
|
1966
|
+
* <li>A <code>Number</code> with one of the values of {@link module:types~dataTypes dataTypes}.</li>
|
|
1967
|
+
* <li>An <code>Object</code> containing the <code>type.code</code> as one of the values of
|
|
1968
|
+
* {@link module:types~dataTypes dataTypes} and <code>type.info</code>.
|
|
1969
|
+
* </li>
|
|
1970
|
+
* </ul>
|
|
1971
|
+
* @returns {Buffer}
|
|
1972
|
+
* @throws {TypeError} When there is an encoding error
|
|
1973
|
+
*/
|
|
1974
|
+
Encoder.prototype.encode = function (value, typeInfo) {
|
|
1975
|
+
if (value === undefined) {
|
|
1976
|
+
value =
|
|
1977
|
+
this.encodingOptions.useUndefinedAsUnset &&
|
|
1978
|
+
this.protocolVersion >= 4
|
|
1979
|
+
? types.unset
|
|
1980
|
+
: null
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
if (value === types.unset) {
|
|
1984
|
+
if (!types.protocolVersion.supportsUnset(this.protocolVersion)) {
|
|
1985
|
+
throw new TypeError(
|
|
1986
|
+
"Unset value can not be used for this version of Cassandra, protocol version: " +
|
|
1987
|
+
this.protocolVersion,
|
|
1988
|
+
)
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
return value
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1994
|
+
if (value === null || value instanceof Buffer) {
|
|
1995
|
+
return value
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
/** @type {ColumnInfo | null} */
|
|
1999
|
+
let type = null
|
|
2000
|
+
|
|
2001
|
+
if (typeInfo) {
|
|
2002
|
+
if (typeof typeInfo === "number") {
|
|
2003
|
+
type = {
|
|
2004
|
+
code: typeInfo,
|
|
2005
|
+
}
|
|
2006
|
+
} else if (typeof typeInfo === "string") {
|
|
2007
|
+
type = dataTypes.getByName(typeInfo)
|
|
2008
|
+
} else if (typeof typeInfo.code === "number") {
|
|
2009
|
+
type = typeInfo
|
|
2010
|
+
}
|
|
2011
|
+
if (type == null || typeof type.code !== "number") {
|
|
2012
|
+
throw new TypeError(
|
|
2013
|
+
"Type information not valid, only String and Number values are valid hints",
|
|
2014
|
+
)
|
|
2015
|
+
}
|
|
2016
|
+
} else {
|
|
2017
|
+
//Lets guess
|
|
2018
|
+
type = Encoder.guessDataType(value)
|
|
2019
|
+
if (!type) {
|
|
2020
|
+
throw new TypeError(
|
|
2021
|
+
"Target data type could not be guessed, you should use prepared statements for accurate type mapping. Value: " +
|
|
2022
|
+
util.inspect(value),
|
|
2023
|
+
)
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
const encoder = this.encoders[type.code]
|
|
2028
|
+
|
|
2029
|
+
if (!encoder) {
|
|
2030
|
+
throw new Error("Type not supported " + type.code)
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
return encoder.call(this, value, type)
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
/**
|
|
2037
|
+
* Try to guess the Cassandra type to be stored, based on the javascript value type
|
|
2038
|
+
* @param value
|
|
2039
|
+
* @returns {ColumnInfo | null}
|
|
2040
|
+
* @ignore
|
|
2041
|
+
* @internal
|
|
2042
|
+
*/
|
|
2043
|
+
Encoder.guessDataType = function (value) {
|
|
2044
|
+
const esTypeName = typeof value
|
|
2045
|
+
if (esTypeName === "number") {
|
|
2046
|
+
return { code: dataTypes.double }
|
|
2047
|
+
} else if (esTypeName === "string") {
|
|
2048
|
+
if (value.length === 36 && uuidRegex.test(value)) {
|
|
2049
|
+
return { code: dataTypes.uuid }
|
|
2050
|
+
}
|
|
2051
|
+
return { code: dataTypes.text }
|
|
2052
|
+
} else if (esTypeName === "boolean") {
|
|
2053
|
+
return { code: dataTypes.boolean }
|
|
2054
|
+
} else if (value instanceof Buffer) {
|
|
2055
|
+
return { code: dataTypes.blob }
|
|
2056
|
+
} else if (value instanceof Date) {
|
|
2057
|
+
return { code: dataTypes.timestamp }
|
|
2058
|
+
} else if (value instanceof Long) {
|
|
2059
|
+
return { code: dataTypes.bigint }
|
|
2060
|
+
} else if (value instanceof Integer) {
|
|
2061
|
+
return { code: dataTypes.varint }
|
|
2062
|
+
} else if (value instanceof BigDecimal) {
|
|
2063
|
+
return { code: dataTypes.decimal }
|
|
2064
|
+
} else if (value instanceof types.Uuid) {
|
|
2065
|
+
return { code: dataTypes.uuid }
|
|
2066
|
+
} else if (value instanceof types.InetAddress) {
|
|
2067
|
+
return { code: dataTypes.inet }
|
|
2068
|
+
} else if (value instanceof types.Tuple) {
|
|
2069
|
+
return { code: dataTypes.tuple }
|
|
2070
|
+
} else if (value instanceof types.LocalDate) {
|
|
2071
|
+
return { code: dataTypes.date }
|
|
2072
|
+
} else if (value instanceof types.LocalTime) {
|
|
2073
|
+
return { code: dataTypes.time }
|
|
2074
|
+
} else if (value instanceof types.Duration) {
|
|
2075
|
+
return { code: dataTypes.custom, info: customTypeNames.duration }
|
|
2076
|
+
}
|
|
2077
|
+
// Map JS TypedArrays onto vectors
|
|
2078
|
+
else if (value instanceof types.Vector) {
|
|
2079
|
+
if (value && value.length > 0) {
|
|
2080
|
+
if (value instanceof Float32Array) {
|
|
2081
|
+
return {
|
|
2082
|
+
code: dataTypes.custom,
|
|
2083
|
+
customTypeName: "vector",
|
|
2084
|
+
info: [{ code: dataTypes.float }, value.length],
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
|
|
2088
|
+
/** @type {ColumnInfo?} */
|
|
2089
|
+
let subtypeColumnInfo = null
|
|
2090
|
+
// try to fetch the subtype from the Vector, or else guess
|
|
2091
|
+
if (value.subtype) {
|
|
2092
|
+
try {
|
|
2093
|
+
subtypeColumnInfo = dataTypes.getByName(value.subtype)
|
|
2094
|
+
} catch (TypeError) {
|
|
2095
|
+
// ignore
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
2098
|
+
if (subtypeColumnInfo == null) {
|
|
2099
|
+
subtypeColumnInfo = this.guessDataType(value[0])
|
|
2100
|
+
}
|
|
2101
|
+
if (subtypeColumnInfo != null) {
|
|
2102
|
+
return {
|
|
2103
|
+
code: dataTypes.custom,
|
|
2104
|
+
customTypeName: "vector",
|
|
2105
|
+
info: [subtypeColumnInfo, value.length],
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
throw new TypeError("Cannot guess subtype from element " + value[0])
|
|
2109
|
+
} else {
|
|
2110
|
+
throw new TypeError("Cannot guess subtype of empty vector")
|
|
2111
|
+
}
|
|
2112
|
+
} else if (Array.isArray(value)) {
|
|
2113
|
+
return { code: dataTypes.list }
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
return null
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
/**
|
|
2120
|
+
* Gets a buffer containing with the bytes (BE) representing the collection length for protocol v2 and below
|
|
2121
|
+
* @param {Buffer|Number} value
|
|
2122
|
+
* @returns {Buffer}
|
|
2123
|
+
* @private
|
|
2124
|
+
*/
|
|
2125
|
+
function getLengthBufferV2(value) {
|
|
2126
|
+
if (!value) {
|
|
2127
|
+
return buffers.int16Zero
|
|
2128
|
+
}
|
|
2129
|
+
const lengthBuffer = utils.allocBufferUnsafe(2)
|
|
2130
|
+
if (typeof value === "number") {
|
|
2131
|
+
lengthBuffer.writeUInt16BE(value, 0)
|
|
2132
|
+
} else {
|
|
2133
|
+
lengthBuffer.writeUInt16BE(value.length, 0)
|
|
2134
|
+
}
|
|
2135
|
+
return lengthBuffer
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2138
|
+
/**
|
|
2139
|
+
* Gets a buffer containing with the bytes (BE) representing the collection length for protocol v3 and above
|
|
2140
|
+
* @param {Buffer|Number} value
|
|
2141
|
+
* @returns {Buffer}
|
|
2142
|
+
* @private
|
|
2143
|
+
*/
|
|
2144
|
+
function getLengthBufferV3(value) {
|
|
2145
|
+
if (!value) {
|
|
2146
|
+
return buffers.int32Zero
|
|
2147
|
+
}
|
|
2148
|
+
const lengthBuffer = utils.allocBufferUnsafe(4)
|
|
2149
|
+
if (typeof value === "number") {
|
|
2150
|
+
lengthBuffer.writeInt32BE(value, 0)
|
|
2151
|
+
} else {
|
|
2152
|
+
lengthBuffer.writeInt32BE(value.length, 0)
|
|
2153
|
+
}
|
|
2154
|
+
return lengthBuffer
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
/**
|
|
2158
|
+
* @param {Buffer} buffer
|
|
2159
|
+
* @private
|
|
2160
|
+
*/
|
|
2161
|
+
function handleBufferCopy(buffer) {
|
|
2162
|
+
if (buffer === null) {
|
|
2163
|
+
return null
|
|
2164
|
+
}
|
|
2165
|
+
return utils.copyBuffer(buffer)
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
/**
|
|
2169
|
+
* @param {Buffer} buffer
|
|
2170
|
+
* @private
|
|
2171
|
+
*/
|
|
2172
|
+
function handleBufferRef(buffer) {
|
|
2173
|
+
return buffer
|
|
2174
|
+
}
|
|
2175
|
+
/**
|
|
2176
|
+
* Decodes collection length for protocol v3 and above
|
|
2177
|
+
* @param bytes
|
|
2178
|
+
* @param offset
|
|
2179
|
+
* @returns {Number}
|
|
2180
|
+
* @private
|
|
2181
|
+
*/
|
|
2182
|
+
function decodeCollectionLengthV3(bytes, offset) {
|
|
2183
|
+
return bytes.readInt32BE(offset)
|
|
2184
|
+
}
|
|
2185
|
+
/**
|
|
2186
|
+
* Decodes collection length for protocol v2 and below
|
|
2187
|
+
* @param bytes
|
|
2188
|
+
* @param offset
|
|
2189
|
+
* @returns {Number}
|
|
2190
|
+
* @private
|
|
2191
|
+
*/
|
|
2192
|
+
function decodeCollectionLengthV2(bytes, offset) {
|
|
2193
|
+
return bytes.readUInt16BE(offset)
|
|
2194
|
+
}
|
|
2195
|
+
|
|
2196
|
+
function decodeDuration(bytes) {
|
|
2197
|
+
return types.Duration.fromBuffer(bytes)
|
|
2198
|
+
}
|
|
2199
|
+
|
|
2200
|
+
function encodeDuration(value) {
|
|
2201
|
+
if (!(value instanceof types.Duration)) {
|
|
2202
|
+
throw new TypeError(
|
|
2203
|
+
"Not a valid duration, expected Duration/Buffer obtained " +
|
|
2204
|
+
util.inspect(value),
|
|
2205
|
+
)
|
|
2206
|
+
}
|
|
2207
|
+
return value.toBuffer()
|
|
2208
|
+
}
|
|
2209
|
+
|
|
2210
|
+
/**
|
|
2211
|
+
* @private
|
|
2212
|
+
* @param {Buffer} buffer
|
|
2213
|
+
*/
|
|
2214
|
+
// geometry and daterange types not supported in this build
|
|
2215
|
+
function decodeLineString() {
|
|
2216
|
+
throw new Error("LineString type not supported")
|
|
2217
|
+
}
|
|
2218
|
+
function encodeLineString() {
|
|
2219
|
+
throw new Error("LineString type not supported")
|
|
2220
|
+
}
|
|
2221
|
+
function decodePoint() {
|
|
2222
|
+
throw new Error("Point type not supported")
|
|
2223
|
+
}
|
|
2224
|
+
function encodePoint() {
|
|
2225
|
+
throw new Error("Point type not supported")
|
|
2226
|
+
}
|
|
2227
|
+
function decodePolygon() {
|
|
2228
|
+
throw new Error("Polygon type not supported")
|
|
2229
|
+
}
|
|
2230
|
+
function encodePolygon() {
|
|
2231
|
+
throw new Error("Polygon type not supported")
|
|
2232
|
+
}
|
|
2233
|
+
function decodeDateRange() {
|
|
2234
|
+
throw new Error("DateRange type not supported")
|
|
2235
|
+
}
|
|
2236
|
+
function encodeDateRange() {
|
|
2237
|
+
throw new Error("DateRange type not supported")
|
|
2238
|
+
}
|
|
2239
|
+
|
|
2240
|
+
/**
|
|
2241
|
+
* @param {String} value
|
|
2242
|
+
* @param {Number} startIndex
|
|
2243
|
+
* @param {Number} length
|
|
2244
|
+
* @param {String} [open]
|
|
2245
|
+
* @param {String} [close]
|
|
2246
|
+
* @returns {Array<String>}
|
|
2247
|
+
* @private
|
|
2248
|
+
*/
|
|
2249
|
+
function parseParams(value, startIndex, length, open, close) {
|
|
2250
|
+
open = open || "("
|
|
2251
|
+
close = close || ")"
|
|
2252
|
+
const types = []
|
|
2253
|
+
let paramStart = startIndex
|
|
2254
|
+
let level = 0
|
|
2255
|
+
for (let i = startIndex; i < startIndex + length; i++) {
|
|
2256
|
+
const c = value[i]
|
|
2257
|
+
if (c === open) {
|
|
2258
|
+
level++
|
|
2259
|
+
}
|
|
2260
|
+
if (c === close) {
|
|
2261
|
+
level--
|
|
2262
|
+
}
|
|
2263
|
+
if (level === 0 && c === ",") {
|
|
2264
|
+
types.push(value.substr(paramStart, i - paramStart))
|
|
2265
|
+
paramStart = i + 1
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
//Add the last one
|
|
2269
|
+
types.push(value.substr(paramStart, length - (paramStart - startIndex)))
|
|
2270
|
+
return types
|
|
2271
|
+
}
|
|
2272
|
+
|
|
2273
|
+
/**
|
|
2274
|
+
* @param {Array.<Buffer>} parts
|
|
2275
|
+
* @param {Number} totalLength
|
|
2276
|
+
* @returns {Buffer}
|
|
2277
|
+
* @private
|
|
2278
|
+
*/
|
|
2279
|
+
function concatRoutingKey(parts, totalLength) {
|
|
2280
|
+
if (totalLength === 0) {
|
|
2281
|
+
return null
|
|
2282
|
+
}
|
|
2283
|
+
if (parts.length === 1) {
|
|
2284
|
+
return parts[0]
|
|
2285
|
+
}
|
|
2286
|
+
const routingKey = utils.allocBufferUnsafe(totalLength)
|
|
2287
|
+
let offset = 0
|
|
2288
|
+
for (let i = 0; i < parts.length; i++) {
|
|
2289
|
+
const item = parts[i]
|
|
2290
|
+
routingKey.writeUInt16BE(item.length, offset)
|
|
2291
|
+
offset += 2
|
|
2292
|
+
item.copy(routingKey, offset)
|
|
2293
|
+
offset += item.length
|
|
2294
|
+
routingKey[offset] = 0
|
|
2295
|
+
offset++
|
|
2296
|
+
}
|
|
2297
|
+
return routingKey
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
function invertObject(obj) {
|
|
2301
|
+
const rv = {}
|
|
2302
|
+
for (const k in obj) {
|
|
2303
|
+
if (obj.hasOwnProperty(k)) {
|
|
2304
|
+
rv[obj[k]] = k
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2307
|
+
return rv
|
|
2308
|
+
}
|
|
2309
|
+
Encoder.isTypedArray = function (arg) {
|
|
2310
|
+
// The TypedArray superclass isn't available directly so to detect an instance of a TypedArray
|
|
2311
|
+
// subclass we have to access the prototype of a concrete instance. There's nothing magical about
|
|
2312
|
+
// Uint8Array here; we could just as easily use any of the other TypedArray subclasses.
|
|
2313
|
+
return arg instanceof Object.getPrototypeOf(Uint8Array)
|
|
2314
|
+
}
|
|
2315
|
+
|
|
2316
|
+
export default Encoder
|