bson 4.1.0 → 4.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/HISTORY.md +48 -1
- package/README.md +7 -9
- package/bower.json +1 -1
- package/bson.d.ts +986 -0
- package/dist/bson.browser.esm.js +7811 -5011
- package/dist/bson.browser.esm.js.map +1 -0
- package/dist/bson.browser.umd.js +7862 -5099
- package/dist/bson.browser.umd.js.map +1 -0
- package/dist/bson.bundle.js +8723 -9228
- package/dist/bson.bundle.js.map +1 -0
- package/dist/bson.esm.js +5728 -4951
- package/dist/bson.esm.js.map +1 -0
- package/etc/prepare.js +19 -0
- package/lib/binary.js +218 -398
- package/lib/binary.js.map +1 -0
- package/lib/bson.js +201 -240
- package/lib/bson.js.map +1 -0
- package/lib/code.js +41 -41
- package/lib/code.js.map +1 -0
- package/lib/constants.js +78 -203
- package/lib/constants.js.map +1 -0
- package/lib/db_ref.js +88 -81
- package/lib/db_ref.js.map +1 -0
- package/lib/decimal128.js +667 -777
- package/lib/decimal128.js.map +1 -0
- package/lib/double.js +68 -70
- package/lib/double.js.map +1 -0
- package/lib/ensure_buffer.js +22 -18
- package/lib/ensure_buffer.js.map +1 -0
- package/lib/extended_json.js +310 -321
- package/lib/extended_json.js.map +1 -0
- package/lib/float_parser.js +98 -104
- package/lib/float_parser.js.map +1 -0
- package/lib/int_32.js +50 -49
- package/lib/int_32.js.map +1 -0
- package/lib/long.js +881 -16
- package/lib/long.js.map +1 -0
- package/lib/map.js +130 -122
- package/lib/map.js.map +1 -0
- package/lib/max_key.js +28 -25
- package/lib/max_key.js.map +1 -0
- package/lib/min_key.js +28 -25
- package/lib/min_key.js.map +1 -0
- package/lib/objectid.js +300 -410
- package/lib/objectid.js.map +1 -0
- package/lib/parser/calculate_size.js +188 -224
- package/lib/parser/calculate_size.js.map +1 -0
- package/lib/parser/deserializer.js +545 -621
- package/lib/parser/deserializer.js.map +1 -0
- package/lib/parser/serializer.js +798 -923
- package/lib/parser/serializer.js.map +1 -0
- package/lib/parser/utils.js +92 -30
- package/lib/parser/utils.js.map +1 -0
- package/lib/regexp.js +61 -74
- package/lib/regexp.js.map +1 -0
- package/lib/symbol.js +45 -58
- package/lib/symbol.js.map +1 -0
- package/lib/timestamp.js +91 -95
- package/lib/timestamp.js.map +1 -0
- package/lib/uuid.js +48 -0
- package/lib/uuid.js.map +1 -0
- package/lib/validate_utf8.js +41 -42
- package/lib/validate_utf8.js.map +1 -0
- package/package.json +53 -31
- package/src/binary.ts +272 -0
- package/src/bson.ts +326 -0
- package/src/code.ts +61 -0
- package/src/constants.ts +104 -0
- package/src/db_ref.ts +119 -0
- package/src/decimal128.ts +803 -0
- package/src/double.ts +87 -0
- package/src/ensure_buffer.ts +26 -0
- package/src/extended_json.ts +395 -0
- package/src/float_parser.ts +152 -0
- package/src/int_32.ts +66 -0
- package/src/long.ts +1002 -0
- package/src/map.ts +139 -0
- package/src/max_key.ts +37 -0
- package/src/min_key.ts +37 -0
- package/src/objectid.ts +379 -0
- package/src/parser/calculate_size.ts +230 -0
- package/src/parser/deserializer.ts +655 -0
- package/src/parser/serializer.ts +1069 -0
- package/src/parser/utils.ts +93 -0
- package/src/regexp.ts +94 -0
- package/src/symbol.ts +59 -0
- package/src/timestamp.ts +108 -0
- package/src/uuid.ts +57 -0
- package/src/validate_utf8.ts +47 -0
- package/lib/fnv1a.js +0 -48
|
@@ -0,0 +1,1069 @@
|
|
|
1
|
+
import type { Buffer } from 'buffer';
|
|
2
|
+
import { Binary } from '../binary';
|
|
3
|
+
import type { BSONSymbol, DBRef, Document, MaxKey } from '../bson';
|
|
4
|
+
import type { Code } from '../code';
|
|
5
|
+
import * as constants from '../constants';
|
|
6
|
+
import type { DBRefLike } from '../db_ref';
|
|
7
|
+
import type { Decimal128 } from '../decimal128';
|
|
8
|
+
import type { Double } from '../double';
|
|
9
|
+
import { ensureBuffer } from '../ensure_buffer';
|
|
10
|
+
import { isBSONType } from '../extended_json';
|
|
11
|
+
import { writeIEEE754 } from '../float_parser';
|
|
12
|
+
import type { Int32 } from '../int_32';
|
|
13
|
+
import { Long } from '../long';
|
|
14
|
+
import { Map } from '../map';
|
|
15
|
+
import type { MinKey } from '../min_key';
|
|
16
|
+
import type { ObjectId } from '../objectid';
|
|
17
|
+
import type { BSONRegExp } from '../regexp';
|
|
18
|
+
import {
|
|
19
|
+
isBigInt64Array,
|
|
20
|
+
isBigUInt64Array,
|
|
21
|
+
isBuffer,
|
|
22
|
+
isDate,
|
|
23
|
+
isUint8Array,
|
|
24
|
+
normalizedFunctionString
|
|
25
|
+
} from './utils';
|
|
26
|
+
|
|
27
|
+
/** @public */
|
|
28
|
+
export interface SerializeOptions {
|
|
29
|
+
/** the serializer will check if keys are valid. */
|
|
30
|
+
checkKeys?: boolean;
|
|
31
|
+
/** serialize the javascript functions **(default:false)**. */
|
|
32
|
+
serializeFunctions?: boolean;
|
|
33
|
+
/** serialize will not emit undefined fields **(default:true)** */
|
|
34
|
+
ignoreUndefined?: boolean;
|
|
35
|
+
/** @internal Resize internal buffer */
|
|
36
|
+
minInternalBufferSize?: number;
|
|
37
|
+
/** the index in the buffer where we wish to start serializing into */
|
|
38
|
+
index?: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const regexp = /\x00/; // eslint-disable-line no-control-regex
|
|
42
|
+
const ignoreKeys = new Set(['$db', '$ref', '$id', '$clusterTime']);
|
|
43
|
+
|
|
44
|
+
function isRegExp(d: unknown): d is RegExp {
|
|
45
|
+
return Object.prototype.toString.call(d) === '[object RegExp]';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/*
|
|
49
|
+
* isArray indicates if we are writing to a BSON array (type 0x04)
|
|
50
|
+
* which forces the "key" which really an array index as a string to be written as ascii
|
|
51
|
+
* This will catch any errors in index as a string generation
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
function serializeString(
|
|
55
|
+
buffer: Buffer,
|
|
56
|
+
key: string,
|
|
57
|
+
value: string,
|
|
58
|
+
index: number,
|
|
59
|
+
isArray?: boolean
|
|
60
|
+
) {
|
|
61
|
+
// Encode String type
|
|
62
|
+
buffer[index++] = constants.BSON_DATA_STRING;
|
|
63
|
+
// Number of written bytes
|
|
64
|
+
const numberOfWrittenBytes = !isArray
|
|
65
|
+
? buffer.write(key, index, undefined, 'utf8')
|
|
66
|
+
: buffer.write(key, index, undefined, 'ascii');
|
|
67
|
+
// Encode the name
|
|
68
|
+
index = index + numberOfWrittenBytes + 1;
|
|
69
|
+
buffer[index - 1] = 0;
|
|
70
|
+
// Write the string
|
|
71
|
+
const size = buffer.write(value, index + 4, undefined, 'utf8');
|
|
72
|
+
// Write the size of the string to buffer
|
|
73
|
+
buffer[index + 3] = ((size + 1) >> 24) & 0xff;
|
|
74
|
+
buffer[index + 2] = ((size + 1) >> 16) & 0xff;
|
|
75
|
+
buffer[index + 1] = ((size + 1) >> 8) & 0xff;
|
|
76
|
+
buffer[index] = (size + 1) & 0xff;
|
|
77
|
+
// Update index
|
|
78
|
+
index = index + 4 + size;
|
|
79
|
+
// Write zero
|
|
80
|
+
buffer[index++] = 0;
|
|
81
|
+
return index;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function serializeNumber(
|
|
85
|
+
buffer: Buffer,
|
|
86
|
+
key: string,
|
|
87
|
+
value: number,
|
|
88
|
+
index: number,
|
|
89
|
+
isArray?: boolean
|
|
90
|
+
) {
|
|
91
|
+
// We have an integer value
|
|
92
|
+
// TODO(NODE-2529): Add support for big int
|
|
93
|
+
if (
|
|
94
|
+
Number.isInteger(value) &&
|
|
95
|
+
value >= constants.BSON_INT32_MIN &&
|
|
96
|
+
value <= constants.BSON_INT32_MAX
|
|
97
|
+
) {
|
|
98
|
+
// If the value fits in 32 bits encode as int32
|
|
99
|
+
// Set int type 32 bits or less
|
|
100
|
+
buffer[index++] = constants.BSON_DATA_INT;
|
|
101
|
+
// Number of written bytes
|
|
102
|
+
const numberOfWrittenBytes = !isArray
|
|
103
|
+
? buffer.write(key, index, undefined, 'utf8')
|
|
104
|
+
: buffer.write(key, index, undefined, 'ascii');
|
|
105
|
+
// Encode the name
|
|
106
|
+
index = index + numberOfWrittenBytes;
|
|
107
|
+
buffer[index++] = 0;
|
|
108
|
+
// Write the int value
|
|
109
|
+
buffer[index++] = value & 0xff;
|
|
110
|
+
buffer[index++] = (value >> 8) & 0xff;
|
|
111
|
+
buffer[index++] = (value >> 16) & 0xff;
|
|
112
|
+
buffer[index++] = (value >> 24) & 0xff;
|
|
113
|
+
} else {
|
|
114
|
+
// Encode as double
|
|
115
|
+
buffer[index++] = constants.BSON_DATA_NUMBER;
|
|
116
|
+
// Number of written bytes
|
|
117
|
+
const numberOfWrittenBytes = !isArray
|
|
118
|
+
? buffer.write(key, index, undefined, 'utf8')
|
|
119
|
+
: buffer.write(key, index, undefined, 'ascii');
|
|
120
|
+
// Encode the name
|
|
121
|
+
index = index + numberOfWrittenBytes;
|
|
122
|
+
buffer[index++] = 0;
|
|
123
|
+
// Write float
|
|
124
|
+
writeIEEE754(buffer, value, index, 'little', 52, 8);
|
|
125
|
+
// Adjust index
|
|
126
|
+
index = index + 8;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return index;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function serializeNull(buffer: Buffer, key: string, _: unknown, index: number, isArray?: boolean) {
|
|
133
|
+
// Set long type
|
|
134
|
+
buffer[index++] = constants.BSON_DATA_NULL;
|
|
135
|
+
|
|
136
|
+
// Number of written bytes
|
|
137
|
+
const numberOfWrittenBytes = !isArray
|
|
138
|
+
? buffer.write(key, index, undefined, 'utf8')
|
|
139
|
+
: buffer.write(key, index, undefined, 'ascii');
|
|
140
|
+
|
|
141
|
+
// Encode the name
|
|
142
|
+
index = index + numberOfWrittenBytes;
|
|
143
|
+
buffer[index++] = 0;
|
|
144
|
+
return index;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function serializeBoolean(
|
|
148
|
+
buffer: Buffer,
|
|
149
|
+
key: string,
|
|
150
|
+
value: boolean,
|
|
151
|
+
index: number,
|
|
152
|
+
isArray?: boolean
|
|
153
|
+
) {
|
|
154
|
+
// Write the type
|
|
155
|
+
buffer[index++] = constants.BSON_DATA_BOOLEAN;
|
|
156
|
+
// Number of written bytes
|
|
157
|
+
const numberOfWrittenBytes = !isArray
|
|
158
|
+
? buffer.write(key, index, undefined, 'utf8')
|
|
159
|
+
: buffer.write(key, index, undefined, 'ascii');
|
|
160
|
+
// Encode the name
|
|
161
|
+
index = index + numberOfWrittenBytes;
|
|
162
|
+
buffer[index++] = 0;
|
|
163
|
+
// Encode the boolean value
|
|
164
|
+
buffer[index++] = value ? 1 : 0;
|
|
165
|
+
return index;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function serializeDate(buffer: Buffer, key: string, value: Date, index: number, isArray?: boolean) {
|
|
169
|
+
// Write the type
|
|
170
|
+
buffer[index++] = constants.BSON_DATA_DATE;
|
|
171
|
+
// Number of written bytes
|
|
172
|
+
const numberOfWrittenBytes = !isArray
|
|
173
|
+
? buffer.write(key, index, undefined, 'utf8')
|
|
174
|
+
: buffer.write(key, index, undefined, 'ascii');
|
|
175
|
+
// Encode the name
|
|
176
|
+
index = index + numberOfWrittenBytes;
|
|
177
|
+
buffer[index++] = 0;
|
|
178
|
+
|
|
179
|
+
// Write the date
|
|
180
|
+
const dateInMilis = Long.fromNumber(value.getTime());
|
|
181
|
+
const lowBits = dateInMilis.getLowBits();
|
|
182
|
+
const highBits = dateInMilis.getHighBits();
|
|
183
|
+
// Encode low bits
|
|
184
|
+
buffer[index++] = lowBits & 0xff;
|
|
185
|
+
buffer[index++] = (lowBits >> 8) & 0xff;
|
|
186
|
+
buffer[index++] = (lowBits >> 16) & 0xff;
|
|
187
|
+
buffer[index++] = (lowBits >> 24) & 0xff;
|
|
188
|
+
// Encode high bits
|
|
189
|
+
buffer[index++] = highBits & 0xff;
|
|
190
|
+
buffer[index++] = (highBits >> 8) & 0xff;
|
|
191
|
+
buffer[index++] = (highBits >> 16) & 0xff;
|
|
192
|
+
buffer[index++] = (highBits >> 24) & 0xff;
|
|
193
|
+
return index;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function serializeRegExp(
|
|
197
|
+
buffer: Buffer,
|
|
198
|
+
key: string,
|
|
199
|
+
value: RegExp,
|
|
200
|
+
index: number,
|
|
201
|
+
isArray?: boolean
|
|
202
|
+
) {
|
|
203
|
+
// Write the type
|
|
204
|
+
buffer[index++] = constants.BSON_DATA_REGEXP;
|
|
205
|
+
// Number of written bytes
|
|
206
|
+
const numberOfWrittenBytes = !isArray
|
|
207
|
+
? buffer.write(key, index, undefined, 'utf8')
|
|
208
|
+
: buffer.write(key, index, undefined, 'ascii');
|
|
209
|
+
|
|
210
|
+
// Encode the name
|
|
211
|
+
index = index + numberOfWrittenBytes;
|
|
212
|
+
buffer[index++] = 0;
|
|
213
|
+
if (value.source && value.source.match(regexp) != null) {
|
|
214
|
+
throw Error('value ' + value.source + ' must not contain null bytes');
|
|
215
|
+
}
|
|
216
|
+
// Adjust the index
|
|
217
|
+
index = index + buffer.write(value.source, index, undefined, 'utf8');
|
|
218
|
+
// Write zero
|
|
219
|
+
buffer[index++] = 0x00;
|
|
220
|
+
// Write the parameters
|
|
221
|
+
if (value.ignoreCase) buffer[index++] = 0x69; // i
|
|
222
|
+
if (value.global) buffer[index++] = 0x73; // s
|
|
223
|
+
if (value.multiline) buffer[index++] = 0x6d; // m
|
|
224
|
+
|
|
225
|
+
// Add ending zero
|
|
226
|
+
buffer[index++] = 0x00;
|
|
227
|
+
return index;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function serializeBSONRegExp(
|
|
231
|
+
buffer: Buffer,
|
|
232
|
+
key: string,
|
|
233
|
+
value: BSONRegExp,
|
|
234
|
+
index: number,
|
|
235
|
+
isArray?: boolean
|
|
236
|
+
) {
|
|
237
|
+
// Write the type
|
|
238
|
+
buffer[index++] = constants.BSON_DATA_REGEXP;
|
|
239
|
+
// Number of written bytes
|
|
240
|
+
const numberOfWrittenBytes = !isArray
|
|
241
|
+
? buffer.write(key, index, undefined, 'utf8')
|
|
242
|
+
: buffer.write(key, index, undefined, 'ascii');
|
|
243
|
+
// Encode the name
|
|
244
|
+
index = index + numberOfWrittenBytes;
|
|
245
|
+
buffer[index++] = 0;
|
|
246
|
+
|
|
247
|
+
// Check the pattern for 0 bytes
|
|
248
|
+
if (value.pattern.match(regexp) != null) {
|
|
249
|
+
// The BSON spec doesn't allow keys with null bytes because keys are
|
|
250
|
+
// null-terminated.
|
|
251
|
+
throw Error('pattern ' + value.pattern + ' must not contain null bytes');
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Adjust the index
|
|
255
|
+
index = index + buffer.write(value.pattern, index, undefined, 'utf8');
|
|
256
|
+
// Write zero
|
|
257
|
+
buffer[index++] = 0x00;
|
|
258
|
+
// Write the options
|
|
259
|
+
index = index + buffer.write(value.options.split('').sort().join(''), index, undefined, 'utf8');
|
|
260
|
+
// Add ending zero
|
|
261
|
+
buffer[index++] = 0x00;
|
|
262
|
+
return index;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function serializeMinMax(
|
|
266
|
+
buffer: Buffer,
|
|
267
|
+
key: string,
|
|
268
|
+
value: MinKey | MaxKey,
|
|
269
|
+
index: number,
|
|
270
|
+
isArray?: boolean
|
|
271
|
+
) {
|
|
272
|
+
// Write the type of either min or max key
|
|
273
|
+
if (value === null) {
|
|
274
|
+
buffer[index++] = constants.BSON_DATA_NULL;
|
|
275
|
+
} else if (value._bsontype === 'MinKey') {
|
|
276
|
+
buffer[index++] = constants.BSON_DATA_MIN_KEY;
|
|
277
|
+
} else {
|
|
278
|
+
buffer[index++] = constants.BSON_DATA_MAX_KEY;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Number of written bytes
|
|
282
|
+
const numberOfWrittenBytes = !isArray
|
|
283
|
+
? buffer.write(key, index, undefined, 'utf8')
|
|
284
|
+
: buffer.write(key, index, undefined, 'ascii');
|
|
285
|
+
// Encode the name
|
|
286
|
+
index = index + numberOfWrittenBytes;
|
|
287
|
+
buffer[index++] = 0;
|
|
288
|
+
return index;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function serializeObjectId(
|
|
292
|
+
buffer: Buffer,
|
|
293
|
+
key: string,
|
|
294
|
+
value: ObjectId,
|
|
295
|
+
index: number,
|
|
296
|
+
isArray?: boolean
|
|
297
|
+
) {
|
|
298
|
+
// Write the type
|
|
299
|
+
buffer[index++] = constants.BSON_DATA_OID;
|
|
300
|
+
// Number of written bytes
|
|
301
|
+
const numberOfWrittenBytes = !isArray
|
|
302
|
+
? buffer.write(key, index, undefined, 'utf8')
|
|
303
|
+
: buffer.write(key, index, undefined, 'ascii');
|
|
304
|
+
|
|
305
|
+
// Encode the name
|
|
306
|
+
index = index + numberOfWrittenBytes;
|
|
307
|
+
buffer[index++] = 0;
|
|
308
|
+
|
|
309
|
+
// Write the objectId into the shared buffer
|
|
310
|
+
if (typeof value.id === 'string') {
|
|
311
|
+
buffer.write(value.id, index, undefined, 'binary');
|
|
312
|
+
} else if (value.id && value.id.copy) {
|
|
313
|
+
value.id.copy(buffer, index, 0, 12);
|
|
314
|
+
} else {
|
|
315
|
+
throw new TypeError('object [' + JSON.stringify(value) + '] is not a valid ObjectId');
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Adjust index
|
|
319
|
+
return index + 12;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function serializeBuffer(
|
|
323
|
+
buffer: Buffer,
|
|
324
|
+
key: string,
|
|
325
|
+
value: Buffer | Uint8Array,
|
|
326
|
+
index: number,
|
|
327
|
+
isArray?: boolean
|
|
328
|
+
) {
|
|
329
|
+
// Write the type
|
|
330
|
+
buffer[index++] = constants.BSON_DATA_BINARY;
|
|
331
|
+
// Number of written bytes
|
|
332
|
+
const numberOfWrittenBytes = !isArray
|
|
333
|
+
? buffer.write(key, index, undefined, 'utf8')
|
|
334
|
+
: buffer.write(key, index, undefined, 'ascii');
|
|
335
|
+
// Encode the name
|
|
336
|
+
index = index + numberOfWrittenBytes;
|
|
337
|
+
buffer[index++] = 0;
|
|
338
|
+
// Get size of the buffer (current write point)
|
|
339
|
+
const size = value.length;
|
|
340
|
+
// Write the size of the string to buffer
|
|
341
|
+
buffer[index++] = size & 0xff;
|
|
342
|
+
buffer[index++] = (size >> 8) & 0xff;
|
|
343
|
+
buffer[index++] = (size >> 16) & 0xff;
|
|
344
|
+
buffer[index++] = (size >> 24) & 0xff;
|
|
345
|
+
// Write the default subtype
|
|
346
|
+
buffer[index++] = constants.BSON_BINARY_SUBTYPE_DEFAULT;
|
|
347
|
+
// Copy the content form the binary field to the buffer
|
|
348
|
+
buffer.set(ensureBuffer(value), index);
|
|
349
|
+
// Adjust the index
|
|
350
|
+
index = index + size;
|
|
351
|
+
return index;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function serializeObject(
|
|
355
|
+
buffer: Buffer,
|
|
356
|
+
key: string,
|
|
357
|
+
value: Document,
|
|
358
|
+
index: number,
|
|
359
|
+
checkKeys = false,
|
|
360
|
+
depth = 0,
|
|
361
|
+
serializeFunctions = false,
|
|
362
|
+
ignoreUndefined = true,
|
|
363
|
+
isArray = false,
|
|
364
|
+
path: Document[] = []
|
|
365
|
+
) {
|
|
366
|
+
for (let i = 0; i < path.length; i++) {
|
|
367
|
+
if (path[i] === value) throw new Error('cyclic dependency detected');
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Push value to stack
|
|
371
|
+
path.push(value);
|
|
372
|
+
// Write the type
|
|
373
|
+
buffer[index++] = Array.isArray(value) ? constants.BSON_DATA_ARRAY : constants.BSON_DATA_OBJECT;
|
|
374
|
+
// Number of written bytes
|
|
375
|
+
const numberOfWrittenBytes = !isArray
|
|
376
|
+
? buffer.write(key, index, undefined, 'utf8')
|
|
377
|
+
: buffer.write(key, index, undefined, 'ascii');
|
|
378
|
+
// Encode the name
|
|
379
|
+
index = index + numberOfWrittenBytes;
|
|
380
|
+
buffer[index++] = 0;
|
|
381
|
+
const endIndex = serializeInto(
|
|
382
|
+
buffer,
|
|
383
|
+
value,
|
|
384
|
+
checkKeys,
|
|
385
|
+
index,
|
|
386
|
+
depth + 1,
|
|
387
|
+
serializeFunctions,
|
|
388
|
+
ignoreUndefined,
|
|
389
|
+
path
|
|
390
|
+
);
|
|
391
|
+
// Pop stack
|
|
392
|
+
path.pop();
|
|
393
|
+
return endIndex;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function serializeDecimal128(
|
|
397
|
+
buffer: Buffer,
|
|
398
|
+
key: string,
|
|
399
|
+
value: Decimal128,
|
|
400
|
+
index: number,
|
|
401
|
+
isArray?: boolean
|
|
402
|
+
) {
|
|
403
|
+
buffer[index++] = constants.BSON_DATA_DECIMAL128;
|
|
404
|
+
// Number of written bytes
|
|
405
|
+
const numberOfWrittenBytes = !isArray
|
|
406
|
+
? buffer.write(key, index, undefined, 'utf8')
|
|
407
|
+
: buffer.write(key, index, undefined, 'ascii');
|
|
408
|
+
// Encode the name
|
|
409
|
+
index = index + numberOfWrittenBytes;
|
|
410
|
+
buffer[index++] = 0;
|
|
411
|
+
// Write the data from the value
|
|
412
|
+
value.bytes.copy(buffer, index, 0, 16);
|
|
413
|
+
return index + 16;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function serializeLong(buffer: Buffer, key: string, value: Long, index: number, isArray?: boolean) {
|
|
417
|
+
// Write the type
|
|
418
|
+
buffer[index++] =
|
|
419
|
+
value._bsontype === 'Long' ? constants.BSON_DATA_LONG : constants.BSON_DATA_TIMESTAMP;
|
|
420
|
+
// Number of written bytes
|
|
421
|
+
const numberOfWrittenBytes = !isArray
|
|
422
|
+
? buffer.write(key, index, undefined, 'utf8')
|
|
423
|
+
: buffer.write(key, index, undefined, 'ascii');
|
|
424
|
+
// Encode the name
|
|
425
|
+
index = index + numberOfWrittenBytes;
|
|
426
|
+
buffer[index++] = 0;
|
|
427
|
+
// Write the date
|
|
428
|
+
const lowBits = value.getLowBits();
|
|
429
|
+
const highBits = value.getHighBits();
|
|
430
|
+
// Encode low bits
|
|
431
|
+
buffer[index++] = lowBits & 0xff;
|
|
432
|
+
buffer[index++] = (lowBits >> 8) & 0xff;
|
|
433
|
+
buffer[index++] = (lowBits >> 16) & 0xff;
|
|
434
|
+
buffer[index++] = (lowBits >> 24) & 0xff;
|
|
435
|
+
// Encode high bits
|
|
436
|
+
buffer[index++] = highBits & 0xff;
|
|
437
|
+
buffer[index++] = (highBits >> 8) & 0xff;
|
|
438
|
+
buffer[index++] = (highBits >> 16) & 0xff;
|
|
439
|
+
buffer[index++] = (highBits >> 24) & 0xff;
|
|
440
|
+
return index;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function serializeInt32(
|
|
444
|
+
buffer: Buffer,
|
|
445
|
+
key: string,
|
|
446
|
+
value: Int32 | number,
|
|
447
|
+
index: number,
|
|
448
|
+
isArray?: boolean
|
|
449
|
+
) {
|
|
450
|
+
value = value.valueOf();
|
|
451
|
+
// Set int type 32 bits or less
|
|
452
|
+
buffer[index++] = constants.BSON_DATA_INT;
|
|
453
|
+
// Number of written bytes
|
|
454
|
+
const numberOfWrittenBytes = !isArray
|
|
455
|
+
? buffer.write(key, index, undefined, 'utf8')
|
|
456
|
+
: buffer.write(key, index, undefined, 'ascii');
|
|
457
|
+
// Encode the name
|
|
458
|
+
index = index + numberOfWrittenBytes;
|
|
459
|
+
buffer[index++] = 0;
|
|
460
|
+
// Write the int value
|
|
461
|
+
buffer[index++] = value & 0xff;
|
|
462
|
+
buffer[index++] = (value >> 8) & 0xff;
|
|
463
|
+
buffer[index++] = (value >> 16) & 0xff;
|
|
464
|
+
buffer[index++] = (value >> 24) & 0xff;
|
|
465
|
+
return index;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function serializeDouble(
|
|
469
|
+
buffer: Buffer,
|
|
470
|
+
key: string,
|
|
471
|
+
value: Double,
|
|
472
|
+
index: number,
|
|
473
|
+
isArray?: boolean
|
|
474
|
+
) {
|
|
475
|
+
// Encode as double
|
|
476
|
+
buffer[index++] = constants.BSON_DATA_NUMBER;
|
|
477
|
+
|
|
478
|
+
// Number of written bytes
|
|
479
|
+
const numberOfWrittenBytes = !isArray
|
|
480
|
+
? buffer.write(key, index, undefined, 'utf8')
|
|
481
|
+
: buffer.write(key, index, undefined, 'ascii');
|
|
482
|
+
|
|
483
|
+
// Encode the name
|
|
484
|
+
index = index + numberOfWrittenBytes;
|
|
485
|
+
buffer[index++] = 0;
|
|
486
|
+
|
|
487
|
+
// Write float
|
|
488
|
+
writeIEEE754(buffer, value.value, index, 'little', 52, 8);
|
|
489
|
+
|
|
490
|
+
// Adjust index
|
|
491
|
+
index = index + 8;
|
|
492
|
+
return index;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
function serializeFunction(
|
|
496
|
+
buffer: Buffer,
|
|
497
|
+
key: string,
|
|
498
|
+
value: Function,
|
|
499
|
+
index: number,
|
|
500
|
+
_checkKeys = false,
|
|
501
|
+
_depth = 0,
|
|
502
|
+
isArray?: boolean
|
|
503
|
+
) {
|
|
504
|
+
buffer[index++] = constants.BSON_DATA_CODE;
|
|
505
|
+
// Number of written bytes
|
|
506
|
+
const numberOfWrittenBytes = !isArray
|
|
507
|
+
? buffer.write(key, index, undefined, 'utf8')
|
|
508
|
+
: buffer.write(key, index, undefined, 'ascii');
|
|
509
|
+
// Encode the name
|
|
510
|
+
index = index + numberOfWrittenBytes;
|
|
511
|
+
buffer[index++] = 0;
|
|
512
|
+
// Function string
|
|
513
|
+
const functionString = normalizedFunctionString(value);
|
|
514
|
+
|
|
515
|
+
// Write the string
|
|
516
|
+
const size = buffer.write(functionString, index + 4, undefined, 'utf8') + 1;
|
|
517
|
+
// Write the size of the string to buffer
|
|
518
|
+
buffer[index] = size & 0xff;
|
|
519
|
+
buffer[index + 1] = (size >> 8) & 0xff;
|
|
520
|
+
buffer[index + 2] = (size >> 16) & 0xff;
|
|
521
|
+
buffer[index + 3] = (size >> 24) & 0xff;
|
|
522
|
+
// Update index
|
|
523
|
+
index = index + 4 + size - 1;
|
|
524
|
+
// Write zero
|
|
525
|
+
buffer[index++] = 0;
|
|
526
|
+
return index;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
function serializeCode(
|
|
530
|
+
buffer: Buffer,
|
|
531
|
+
key: string,
|
|
532
|
+
value: Code,
|
|
533
|
+
index: number,
|
|
534
|
+
checkKeys = false,
|
|
535
|
+
depth = 0,
|
|
536
|
+
serializeFunctions = false,
|
|
537
|
+
ignoreUndefined = true,
|
|
538
|
+
isArray = false
|
|
539
|
+
) {
|
|
540
|
+
if (value.scope && typeof value.scope === 'object') {
|
|
541
|
+
// Write the type
|
|
542
|
+
buffer[index++] = constants.BSON_DATA_CODE_W_SCOPE;
|
|
543
|
+
// Number of written bytes
|
|
544
|
+
const numberOfWrittenBytes = !isArray
|
|
545
|
+
? buffer.write(key, index, undefined, 'utf8')
|
|
546
|
+
: buffer.write(key, index, undefined, 'ascii');
|
|
547
|
+
// Encode the name
|
|
548
|
+
index = index + numberOfWrittenBytes;
|
|
549
|
+
buffer[index++] = 0;
|
|
550
|
+
|
|
551
|
+
// Starting index
|
|
552
|
+
let startIndex = index;
|
|
553
|
+
|
|
554
|
+
// Serialize the function
|
|
555
|
+
// Get the function string
|
|
556
|
+
const functionString = typeof value.code === 'string' ? value.code : value.code.toString();
|
|
557
|
+
// Index adjustment
|
|
558
|
+
index = index + 4;
|
|
559
|
+
// Write string into buffer
|
|
560
|
+
const codeSize = buffer.write(functionString, index + 4, undefined, 'utf8') + 1;
|
|
561
|
+
// Write the size of the string to buffer
|
|
562
|
+
buffer[index] = codeSize & 0xff;
|
|
563
|
+
buffer[index + 1] = (codeSize >> 8) & 0xff;
|
|
564
|
+
buffer[index + 2] = (codeSize >> 16) & 0xff;
|
|
565
|
+
buffer[index + 3] = (codeSize >> 24) & 0xff;
|
|
566
|
+
// Write end 0
|
|
567
|
+
buffer[index + 4 + codeSize - 1] = 0;
|
|
568
|
+
// Write the
|
|
569
|
+
index = index + codeSize + 4;
|
|
570
|
+
|
|
571
|
+
//
|
|
572
|
+
// Serialize the scope value
|
|
573
|
+
const endIndex = serializeInto(
|
|
574
|
+
buffer,
|
|
575
|
+
value.scope,
|
|
576
|
+
checkKeys,
|
|
577
|
+
index,
|
|
578
|
+
depth + 1,
|
|
579
|
+
serializeFunctions,
|
|
580
|
+
ignoreUndefined
|
|
581
|
+
);
|
|
582
|
+
index = endIndex - 1;
|
|
583
|
+
|
|
584
|
+
// Writ the total
|
|
585
|
+
const totalSize = endIndex - startIndex;
|
|
586
|
+
|
|
587
|
+
// Write the total size of the object
|
|
588
|
+
buffer[startIndex++] = totalSize & 0xff;
|
|
589
|
+
buffer[startIndex++] = (totalSize >> 8) & 0xff;
|
|
590
|
+
buffer[startIndex++] = (totalSize >> 16) & 0xff;
|
|
591
|
+
buffer[startIndex++] = (totalSize >> 24) & 0xff;
|
|
592
|
+
// Write trailing zero
|
|
593
|
+
buffer[index++] = 0;
|
|
594
|
+
} else {
|
|
595
|
+
buffer[index++] = constants.BSON_DATA_CODE;
|
|
596
|
+
// Number of written bytes
|
|
597
|
+
const numberOfWrittenBytes = !isArray
|
|
598
|
+
? buffer.write(key, index, undefined, 'utf8')
|
|
599
|
+
: buffer.write(key, index, undefined, 'ascii');
|
|
600
|
+
// Encode the name
|
|
601
|
+
index = index + numberOfWrittenBytes;
|
|
602
|
+
buffer[index++] = 0;
|
|
603
|
+
// Function string
|
|
604
|
+
const functionString = value.code.toString();
|
|
605
|
+
// Write the string
|
|
606
|
+
const size = buffer.write(functionString, index + 4, undefined, 'utf8') + 1;
|
|
607
|
+
// Write the size of the string to buffer
|
|
608
|
+
buffer[index] = size & 0xff;
|
|
609
|
+
buffer[index + 1] = (size >> 8) & 0xff;
|
|
610
|
+
buffer[index + 2] = (size >> 16) & 0xff;
|
|
611
|
+
buffer[index + 3] = (size >> 24) & 0xff;
|
|
612
|
+
// Update index
|
|
613
|
+
index = index + 4 + size - 1;
|
|
614
|
+
// Write zero
|
|
615
|
+
buffer[index++] = 0;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
return index;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
function serializeBinary(
|
|
622
|
+
buffer: Buffer,
|
|
623
|
+
key: string,
|
|
624
|
+
value: Binary,
|
|
625
|
+
index: number,
|
|
626
|
+
isArray?: boolean
|
|
627
|
+
) {
|
|
628
|
+
// Write the type
|
|
629
|
+
buffer[index++] = constants.BSON_DATA_BINARY;
|
|
630
|
+
// Number of written bytes
|
|
631
|
+
const numberOfWrittenBytes = !isArray
|
|
632
|
+
? buffer.write(key, index, undefined, 'utf8')
|
|
633
|
+
: buffer.write(key, index, undefined, 'ascii');
|
|
634
|
+
// Encode the name
|
|
635
|
+
index = index + numberOfWrittenBytes;
|
|
636
|
+
buffer[index++] = 0;
|
|
637
|
+
// Extract the buffer
|
|
638
|
+
const data = value.value(true) as Buffer | Uint8Array;
|
|
639
|
+
// Calculate size
|
|
640
|
+
let size = value.position;
|
|
641
|
+
// Add the deprecated 02 type 4 bytes of size to total
|
|
642
|
+
if (value.sub_type === Binary.SUBTYPE_BYTE_ARRAY) size = size + 4;
|
|
643
|
+
// Write the size of the string to buffer
|
|
644
|
+
buffer[index++] = size & 0xff;
|
|
645
|
+
buffer[index++] = (size >> 8) & 0xff;
|
|
646
|
+
buffer[index++] = (size >> 16) & 0xff;
|
|
647
|
+
buffer[index++] = (size >> 24) & 0xff;
|
|
648
|
+
// Write the subtype to the buffer
|
|
649
|
+
buffer[index++] = value.sub_type;
|
|
650
|
+
|
|
651
|
+
// If we have binary type 2 the 4 first bytes are the size
|
|
652
|
+
if (value.sub_type === Binary.SUBTYPE_BYTE_ARRAY) {
|
|
653
|
+
size = size - 4;
|
|
654
|
+
buffer[index++] = size & 0xff;
|
|
655
|
+
buffer[index++] = (size >> 8) & 0xff;
|
|
656
|
+
buffer[index++] = (size >> 16) & 0xff;
|
|
657
|
+
buffer[index++] = (size >> 24) & 0xff;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// Write the data to the object
|
|
661
|
+
buffer.set(data, index);
|
|
662
|
+
// Adjust the index
|
|
663
|
+
index = index + value.position;
|
|
664
|
+
return index;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
function serializeSymbol(
|
|
668
|
+
buffer: Buffer,
|
|
669
|
+
key: string,
|
|
670
|
+
value: BSONSymbol,
|
|
671
|
+
index: number,
|
|
672
|
+
isArray?: boolean
|
|
673
|
+
) {
|
|
674
|
+
// Write the type
|
|
675
|
+
buffer[index++] = constants.BSON_DATA_SYMBOL;
|
|
676
|
+
// Number of written bytes
|
|
677
|
+
const numberOfWrittenBytes = !isArray
|
|
678
|
+
? buffer.write(key, index, undefined, 'utf8')
|
|
679
|
+
: buffer.write(key, index, undefined, 'ascii');
|
|
680
|
+
// Encode the name
|
|
681
|
+
index = index + numberOfWrittenBytes;
|
|
682
|
+
buffer[index++] = 0;
|
|
683
|
+
// Write the string
|
|
684
|
+
const size = buffer.write(value.value, index + 4, undefined, 'utf8') + 1;
|
|
685
|
+
// Write the size of the string to buffer
|
|
686
|
+
buffer[index] = size & 0xff;
|
|
687
|
+
buffer[index + 1] = (size >> 8) & 0xff;
|
|
688
|
+
buffer[index + 2] = (size >> 16) & 0xff;
|
|
689
|
+
buffer[index + 3] = (size >> 24) & 0xff;
|
|
690
|
+
// Update index
|
|
691
|
+
index = index + 4 + size - 1;
|
|
692
|
+
// Write zero
|
|
693
|
+
buffer[index++] = 0x00;
|
|
694
|
+
return index;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
function serializeDBRef(
|
|
698
|
+
buffer: Buffer,
|
|
699
|
+
key: string,
|
|
700
|
+
value: DBRef,
|
|
701
|
+
index: number,
|
|
702
|
+
depth: number,
|
|
703
|
+
serializeFunctions: boolean,
|
|
704
|
+
isArray?: boolean
|
|
705
|
+
) {
|
|
706
|
+
// Write the type
|
|
707
|
+
buffer[index++] = constants.BSON_DATA_OBJECT;
|
|
708
|
+
// Number of written bytes
|
|
709
|
+
const numberOfWrittenBytes = !isArray
|
|
710
|
+
? buffer.write(key, index, undefined, 'utf8')
|
|
711
|
+
: buffer.write(key, index, undefined, 'ascii');
|
|
712
|
+
|
|
713
|
+
// Encode the name
|
|
714
|
+
index = index + numberOfWrittenBytes;
|
|
715
|
+
buffer[index++] = 0;
|
|
716
|
+
|
|
717
|
+
let startIndex = index;
|
|
718
|
+
let output: DBRefLike = {
|
|
719
|
+
$ref: value.collection || value.namespace, // "namespace" was what library 1.x called "collection"
|
|
720
|
+
$id: value.oid
|
|
721
|
+
};
|
|
722
|
+
|
|
723
|
+
if (value.db != null) {
|
|
724
|
+
output.$db = value.db;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
output = Object.assign(output, value.fields);
|
|
728
|
+
const endIndex = serializeInto(buffer, output, false, index, depth + 1, serializeFunctions);
|
|
729
|
+
|
|
730
|
+
// Calculate object size
|
|
731
|
+
const size = endIndex - startIndex;
|
|
732
|
+
// Write the size
|
|
733
|
+
buffer[startIndex++] = size & 0xff;
|
|
734
|
+
buffer[startIndex++] = (size >> 8) & 0xff;
|
|
735
|
+
buffer[startIndex++] = (size >> 16) & 0xff;
|
|
736
|
+
buffer[startIndex++] = (size >> 24) & 0xff;
|
|
737
|
+
// Set index
|
|
738
|
+
return endIndex;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
export function serializeInto(
|
|
742
|
+
buffer: Buffer,
|
|
743
|
+
object: Document,
|
|
744
|
+
checkKeys = false,
|
|
745
|
+
startingIndex = 0,
|
|
746
|
+
depth = 0,
|
|
747
|
+
serializeFunctions = false,
|
|
748
|
+
ignoreUndefined = true,
|
|
749
|
+
path: Document[] = []
|
|
750
|
+
): number {
|
|
751
|
+
startingIndex = startingIndex || 0;
|
|
752
|
+
path = path || [];
|
|
753
|
+
|
|
754
|
+
// Push the object to the path
|
|
755
|
+
path.push(object);
|
|
756
|
+
|
|
757
|
+
// Start place to serialize into
|
|
758
|
+
let index = startingIndex + 4;
|
|
759
|
+
|
|
760
|
+
// Special case isArray
|
|
761
|
+
if (Array.isArray(object)) {
|
|
762
|
+
// Get object keys
|
|
763
|
+
for (let i = 0; i < object.length; i++) {
|
|
764
|
+
const key = '' + i;
|
|
765
|
+
let value = object[i];
|
|
766
|
+
|
|
767
|
+
// Is there an override value
|
|
768
|
+
if (value && value.toBSON) {
|
|
769
|
+
if (typeof value.toBSON !== 'function') throw new TypeError('toBSON is not a function');
|
|
770
|
+
value = value.toBSON();
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
if (typeof value === 'string') {
|
|
774
|
+
index = serializeString(buffer, key, value, index, true);
|
|
775
|
+
} else if (typeof value === 'number') {
|
|
776
|
+
index = serializeNumber(buffer, key, value, index, true);
|
|
777
|
+
} else if (typeof value === 'bigint') {
|
|
778
|
+
throw new TypeError('Unsupported type BigInt, please use Decimal128');
|
|
779
|
+
} else if (typeof value === 'boolean') {
|
|
780
|
+
index = serializeBoolean(buffer, key, value, index, true);
|
|
781
|
+
} else if (value instanceof Date || isDate(value)) {
|
|
782
|
+
index = serializeDate(buffer, key, value, index, true);
|
|
783
|
+
} else if (value === undefined) {
|
|
784
|
+
index = serializeNull(buffer, key, value, index, true);
|
|
785
|
+
} else if (value === null) {
|
|
786
|
+
index = serializeNull(buffer, key, value, index, true);
|
|
787
|
+
} else if (value['_bsontype'] === 'ObjectId' || value['_bsontype'] === 'ObjectID') {
|
|
788
|
+
index = serializeObjectId(buffer, key, value, index, true);
|
|
789
|
+
} else if (isBuffer(value) || isUint8Array(value)) {
|
|
790
|
+
index = serializeBuffer(buffer, key, value, index, true);
|
|
791
|
+
} else if (value instanceof RegExp || isRegExp(value)) {
|
|
792
|
+
index = serializeRegExp(buffer, key, value, index, true);
|
|
793
|
+
} else if (typeof value === 'object' && value['_bsontype'] == null) {
|
|
794
|
+
index = serializeObject(
|
|
795
|
+
buffer,
|
|
796
|
+
key,
|
|
797
|
+
value,
|
|
798
|
+
index,
|
|
799
|
+
checkKeys,
|
|
800
|
+
depth,
|
|
801
|
+
serializeFunctions,
|
|
802
|
+
ignoreUndefined,
|
|
803
|
+
true,
|
|
804
|
+
path
|
|
805
|
+
);
|
|
806
|
+
} else if (
|
|
807
|
+
typeof value === 'object' &&
|
|
808
|
+
isBSONType(value) &&
|
|
809
|
+
value._bsontype === 'Decimal128'
|
|
810
|
+
) {
|
|
811
|
+
index = serializeDecimal128(buffer, key, value, index, true);
|
|
812
|
+
} else if (value['_bsontype'] === 'Long' || value['_bsontype'] === 'Timestamp') {
|
|
813
|
+
index = serializeLong(buffer, key, value, index, true);
|
|
814
|
+
} else if (value['_bsontype'] === 'Double') {
|
|
815
|
+
index = serializeDouble(buffer, key, value, index, true);
|
|
816
|
+
} else if (typeof value === 'function' && serializeFunctions) {
|
|
817
|
+
index = serializeFunction(buffer, key, value, index, checkKeys, depth, true);
|
|
818
|
+
} else if (value['_bsontype'] === 'Code') {
|
|
819
|
+
index = serializeCode(
|
|
820
|
+
buffer,
|
|
821
|
+
key,
|
|
822
|
+
value,
|
|
823
|
+
index,
|
|
824
|
+
checkKeys,
|
|
825
|
+
depth,
|
|
826
|
+
serializeFunctions,
|
|
827
|
+
ignoreUndefined,
|
|
828
|
+
true
|
|
829
|
+
);
|
|
830
|
+
} else if (value['_bsontype'] === 'Binary') {
|
|
831
|
+
index = serializeBinary(buffer, key, value, index, true);
|
|
832
|
+
} else if (value['_bsontype'] === 'Symbol') {
|
|
833
|
+
index = serializeSymbol(buffer, key, value, index, true);
|
|
834
|
+
} else if (value['_bsontype'] === 'DBRef') {
|
|
835
|
+
index = serializeDBRef(buffer, key, value, index, depth, serializeFunctions, true);
|
|
836
|
+
} else if (value['_bsontype'] === 'BSONRegExp') {
|
|
837
|
+
index = serializeBSONRegExp(buffer, key, value, index, true);
|
|
838
|
+
} else if (value['_bsontype'] === 'Int32') {
|
|
839
|
+
index = serializeInt32(buffer, key, value, index, true);
|
|
840
|
+
} else if (value['_bsontype'] === 'MinKey' || value['_bsontype'] === 'MaxKey') {
|
|
841
|
+
index = serializeMinMax(buffer, key, value, index, true);
|
|
842
|
+
} else if (typeof value['_bsontype'] !== 'undefined') {
|
|
843
|
+
throw new TypeError('Unrecognized or invalid _bsontype: ' + value['_bsontype']);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
} else if (object instanceof Map) {
|
|
847
|
+
const iterator = object.entries();
|
|
848
|
+
let done = false;
|
|
849
|
+
|
|
850
|
+
while (!done) {
|
|
851
|
+
// Unpack the next entry
|
|
852
|
+
const entry = iterator.next();
|
|
853
|
+
done = !!entry.done;
|
|
854
|
+
// Are we done, then skip and terminate
|
|
855
|
+
if (done) continue;
|
|
856
|
+
|
|
857
|
+
// Get the entry values
|
|
858
|
+
const key = entry.value[0];
|
|
859
|
+
const value = entry.value[1];
|
|
860
|
+
|
|
861
|
+
// Check the type of the value
|
|
862
|
+
const type = typeof value;
|
|
863
|
+
|
|
864
|
+
// Check the key and throw error if it's illegal
|
|
865
|
+
if (typeof key === 'string' && !ignoreKeys.has(key)) {
|
|
866
|
+
if (key.match(regexp) != null) {
|
|
867
|
+
// The BSON spec doesn't allow keys with null bytes because keys are
|
|
868
|
+
// null-terminated.
|
|
869
|
+
throw Error('key ' + key + ' must not contain null bytes');
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
if (checkKeys) {
|
|
873
|
+
if ('$' === key[0]) {
|
|
874
|
+
throw Error('key ' + key + " must not start with '$'");
|
|
875
|
+
} else if (~key.indexOf('.')) {
|
|
876
|
+
throw Error('key ' + key + " must not contain '.'");
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
if (type === 'string') {
|
|
882
|
+
index = serializeString(buffer, key, value, index);
|
|
883
|
+
} else if (type === 'number') {
|
|
884
|
+
index = serializeNumber(buffer, key, value, index);
|
|
885
|
+
} else if (type === 'bigint' || isBigInt64Array(value) || isBigUInt64Array(value)) {
|
|
886
|
+
throw new TypeError('Unsupported type BigInt, please use Decimal128');
|
|
887
|
+
} else if (type === 'boolean') {
|
|
888
|
+
index = serializeBoolean(buffer, key, value, index);
|
|
889
|
+
} else if (value instanceof Date || isDate(value)) {
|
|
890
|
+
index = serializeDate(buffer, key, value, index);
|
|
891
|
+
} else if (value === null || (value === undefined && ignoreUndefined === false)) {
|
|
892
|
+
index = serializeNull(buffer, key, value, index);
|
|
893
|
+
} else if (value['_bsontype'] === 'ObjectId' || value['_bsontype'] === 'ObjectID') {
|
|
894
|
+
index = serializeObjectId(buffer, key, value, index);
|
|
895
|
+
} else if (isBuffer(value) || isUint8Array(value)) {
|
|
896
|
+
index = serializeBuffer(buffer, key, value, index);
|
|
897
|
+
} else if (value instanceof RegExp || isRegExp(value)) {
|
|
898
|
+
index = serializeRegExp(buffer, key, value, index);
|
|
899
|
+
} else if (type === 'object' && value['_bsontype'] == null) {
|
|
900
|
+
index = serializeObject(
|
|
901
|
+
buffer,
|
|
902
|
+
key,
|
|
903
|
+
value,
|
|
904
|
+
index,
|
|
905
|
+
checkKeys,
|
|
906
|
+
depth,
|
|
907
|
+
serializeFunctions,
|
|
908
|
+
ignoreUndefined,
|
|
909
|
+
false,
|
|
910
|
+
path
|
|
911
|
+
);
|
|
912
|
+
} else if (type === 'object' && value['_bsontype'] === 'Decimal128') {
|
|
913
|
+
index = serializeDecimal128(buffer, key, value, index);
|
|
914
|
+
} else if (value['_bsontype'] === 'Long' || value['_bsontype'] === 'Timestamp') {
|
|
915
|
+
index = serializeLong(buffer, key, value, index);
|
|
916
|
+
} else if (value['_bsontype'] === 'Double') {
|
|
917
|
+
index = serializeDouble(buffer, key, value, index);
|
|
918
|
+
} else if (value['_bsontype'] === 'Code') {
|
|
919
|
+
index = serializeCode(
|
|
920
|
+
buffer,
|
|
921
|
+
key,
|
|
922
|
+
value,
|
|
923
|
+
index,
|
|
924
|
+
checkKeys,
|
|
925
|
+
depth,
|
|
926
|
+
serializeFunctions,
|
|
927
|
+
ignoreUndefined
|
|
928
|
+
);
|
|
929
|
+
} else if (typeof value === 'function' && serializeFunctions) {
|
|
930
|
+
index = serializeFunction(buffer, key, value, index, checkKeys, depth, serializeFunctions);
|
|
931
|
+
} else if (value['_bsontype'] === 'Binary') {
|
|
932
|
+
index = serializeBinary(buffer, key, value, index);
|
|
933
|
+
} else if (value['_bsontype'] === 'Symbol') {
|
|
934
|
+
index = serializeSymbol(buffer, key, value, index);
|
|
935
|
+
} else if (value['_bsontype'] === 'DBRef') {
|
|
936
|
+
index = serializeDBRef(buffer, key, value, index, depth, serializeFunctions);
|
|
937
|
+
} else if (value['_bsontype'] === 'BSONRegExp') {
|
|
938
|
+
index = serializeBSONRegExp(buffer, key, value, index);
|
|
939
|
+
} else if (value['_bsontype'] === 'Int32') {
|
|
940
|
+
index = serializeInt32(buffer, key, value, index);
|
|
941
|
+
} else if (value['_bsontype'] === 'MinKey' || value['_bsontype'] === 'MaxKey') {
|
|
942
|
+
index = serializeMinMax(buffer, key, value, index);
|
|
943
|
+
} else if (typeof value['_bsontype'] !== 'undefined') {
|
|
944
|
+
throw new TypeError('Unrecognized or invalid _bsontype: ' + value['_bsontype']);
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
} else {
|
|
948
|
+
// Did we provide a custom serialization method
|
|
949
|
+
if (object.toBSON) {
|
|
950
|
+
if (typeof object.toBSON !== 'function') throw new TypeError('toBSON is not a function');
|
|
951
|
+
object = object.toBSON();
|
|
952
|
+
if (object != null && typeof object !== 'object')
|
|
953
|
+
throw new TypeError('toBSON function did not return an object');
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
// Iterate over all the keys
|
|
957
|
+
for (const key in object) {
|
|
958
|
+
let value = object[key];
|
|
959
|
+
// Is there an override value
|
|
960
|
+
if (value && value.toBSON) {
|
|
961
|
+
if (typeof value.toBSON !== 'function') throw new TypeError('toBSON is not a function');
|
|
962
|
+
value = value.toBSON();
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
// Check the type of the value
|
|
966
|
+
const type = typeof value;
|
|
967
|
+
|
|
968
|
+
// Check the key and throw error if it's illegal
|
|
969
|
+
if (typeof key === 'string' && !ignoreKeys.has(key)) {
|
|
970
|
+
if (key.match(regexp) != null) {
|
|
971
|
+
// The BSON spec doesn't allow keys with null bytes because keys are
|
|
972
|
+
// null-terminated.
|
|
973
|
+
throw Error('key ' + key + ' must not contain null bytes');
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
if (checkKeys) {
|
|
977
|
+
if ('$' === key[0]) {
|
|
978
|
+
throw Error('key ' + key + " must not start with '$'");
|
|
979
|
+
} else if (~key.indexOf('.')) {
|
|
980
|
+
throw Error('key ' + key + " must not contain '.'");
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
if (type === 'string') {
|
|
986
|
+
index = serializeString(buffer, key, value, index);
|
|
987
|
+
} else if (type === 'number') {
|
|
988
|
+
index = serializeNumber(buffer, key, value, index);
|
|
989
|
+
} else if (type === 'bigint') {
|
|
990
|
+
throw new TypeError('Unsupported type BigInt, please use Decimal128');
|
|
991
|
+
} else if (type === 'boolean') {
|
|
992
|
+
index = serializeBoolean(buffer, key, value, index);
|
|
993
|
+
} else if (value instanceof Date || isDate(value)) {
|
|
994
|
+
index = serializeDate(buffer, key, value, index);
|
|
995
|
+
} else if (value === undefined) {
|
|
996
|
+
if (ignoreUndefined === false) index = serializeNull(buffer, key, value, index);
|
|
997
|
+
} else if (value === null) {
|
|
998
|
+
index = serializeNull(buffer, key, value, index);
|
|
999
|
+
} else if (value['_bsontype'] === 'ObjectId' || value['_bsontype'] === 'ObjectID') {
|
|
1000
|
+
index = serializeObjectId(buffer, key, value, index);
|
|
1001
|
+
} else if (isBuffer(value) || isUint8Array(value)) {
|
|
1002
|
+
index = serializeBuffer(buffer, key, value, index);
|
|
1003
|
+
} else if (value instanceof RegExp || isRegExp(value)) {
|
|
1004
|
+
index = serializeRegExp(buffer, key, value, index);
|
|
1005
|
+
} else if (type === 'object' && value['_bsontype'] == null) {
|
|
1006
|
+
index = serializeObject(
|
|
1007
|
+
buffer,
|
|
1008
|
+
key,
|
|
1009
|
+
value,
|
|
1010
|
+
index,
|
|
1011
|
+
checkKeys,
|
|
1012
|
+
depth,
|
|
1013
|
+
serializeFunctions,
|
|
1014
|
+
ignoreUndefined,
|
|
1015
|
+
false,
|
|
1016
|
+
path
|
|
1017
|
+
);
|
|
1018
|
+
} else if (type === 'object' && value['_bsontype'] === 'Decimal128') {
|
|
1019
|
+
index = serializeDecimal128(buffer, key, value, index);
|
|
1020
|
+
} else if (value['_bsontype'] === 'Long' || value['_bsontype'] === 'Timestamp') {
|
|
1021
|
+
index = serializeLong(buffer, key, value, index);
|
|
1022
|
+
} else if (value['_bsontype'] === 'Double') {
|
|
1023
|
+
index = serializeDouble(buffer, key, value, index);
|
|
1024
|
+
} else if (value['_bsontype'] === 'Code') {
|
|
1025
|
+
index = serializeCode(
|
|
1026
|
+
buffer,
|
|
1027
|
+
key,
|
|
1028
|
+
value,
|
|
1029
|
+
index,
|
|
1030
|
+
checkKeys,
|
|
1031
|
+
depth,
|
|
1032
|
+
serializeFunctions,
|
|
1033
|
+
ignoreUndefined
|
|
1034
|
+
);
|
|
1035
|
+
} else if (typeof value === 'function' && serializeFunctions) {
|
|
1036
|
+
index = serializeFunction(buffer, key, value, index, checkKeys, depth, serializeFunctions);
|
|
1037
|
+
} else if (value['_bsontype'] === 'Binary') {
|
|
1038
|
+
index = serializeBinary(buffer, key, value, index);
|
|
1039
|
+
} else if (value['_bsontype'] === 'Symbol') {
|
|
1040
|
+
index = serializeSymbol(buffer, key, value, index);
|
|
1041
|
+
} else if (value['_bsontype'] === 'DBRef') {
|
|
1042
|
+
index = serializeDBRef(buffer, key, value, index, depth, serializeFunctions);
|
|
1043
|
+
} else if (value['_bsontype'] === 'BSONRegExp') {
|
|
1044
|
+
index = serializeBSONRegExp(buffer, key, value, index);
|
|
1045
|
+
} else if (value['_bsontype'] === 'Int32') {
|
|
1046
|
+
index = serializeInt32(buffer, key, value, index);
|
|
1047
|
+
} else if (value['_bsontype'] === 'MinKey' || value['_bsontype'] === 'MaxKey') {
|
|
1048
|
+
index = serializeMinMax(buffer, key, value, index);
|
|
1049
|
+
} else if (typeof value['_bsontype'] !== 'undefined') {
|
|
1050
|
+
throw new TypeError('Unrecognized or invalid _bsontype: ' + value['_bsontype']);
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
// Remove the path
|
|
1056
|
+
path.pop();
|
|
1057
|
+
|
|
1058
|
+
// Final padding byte for object
|
|
1059
|
+
buffer[index++] = 0x00;
|
|
1060
|
+
|
|
1061
|
+
// Final size
|
|
1062
|
+
const size = index - startingIndex;
|
|
1063
|
+
// Write the size of the object
|
|
1064
|
+
buffer[startingIndex++] = size & 0xff;
|
|
1065
|
+
buffer[startingIndex++] = (size >> 8) & 0xff;
|
|
1066
|
+
buffer[startingIndex++] = (size >> 16) & 0xff;
|
|
1067
|
+
buffer[startingIndex++] = (size >> 24) & 0xff;
|
|
1068
|
+
return index;
|
|
1069
|
+
}
|