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
package/src/binary.ts
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
import { ensureBuffer } from './ensure_buffer';
|
|
3
|
+
import type { EJSONOptions } from './extended_json';
|
|
4
|
+
import { parseUUID, UUIDExtended } from './uuid';
|
|
5
|
+
|
|
6
|
+
/** @public */
|
|
7
|
+
export type BinarySequence = Uint8Array | Buffer | number[];
|
|
8
|
+
|
|
9
|
+
/** @public */
|
|
10
|
+
export interface BinaryExtendedLegacy {
|
|
11
|
+
$type: string;
|
|
12
|
+
$binary: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** @public */
|
|
16
|
+
export interface BinaryExtended {
|
|
17
|
+
$binary: {
|
|
18
|
+
subType: string;
|
|
19
|
+
base64: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* A class representation of the BSON Binary type.
|
|
25
|
+
* @public
|
|
26
|
+
*/
|
|
27
|
+
export class Binary {
|
|
28
|
+
_bsontype!: 'Binary';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Binary default subtype
|
|
32
|
+
* @internal
|
|
33
|
+
*/
|
|
34
|
+
private static readonly BSON_BINARY_SUBTYPE_DEFAULT = 0;
|
|
35
|
+
|
|
36
|
+
/** Initial buffer default size */
|
|
37
|
+
static readonly BUFFER_SIZE = 256;
|
|
38
|
+
/** Default BSON type */
|
|
39
|
+
static readonly SUBTYPE_DEFAULT = 0;
|
|
40
|
+
/** Function BSON type */
|
|
41
|
+
static readonly SUBTYPE_FUNCTION = 1;
|
|
42
|
+
/** Byte Array BSON type */
|
|
43
|
+
static readonly SUBTYPE_BYTE_ARRAY = 2;
|
|
44
|
+
/** Deprecated UUID BSON type @deprecated Please use SUBTYPE_UUID */
|
|
45
|
+
static readonly SUBTYPE_UUID_OLD = 3;
|
|
46
|
+
/** UUID BSON type */
|
|
47
|
+
static readonly SUBTYPE_UUID = 4;
|
|
48
|
+
/** MD5 BSON type */
|
|
49
|
+
static readonly SUBTYPE_MD5 = 5;
|
|
50
|
+
/** User BSON type */
|
|
51
|
+
static readonly SUBTYPE_USER_DEFINED = 128;
|
|
52
|
+
|
|
53
|
+
buffer!: Buffer;
|
|
54
|
+
sub_type!: number;
|
|
55
|
+
position!: number;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @param buffer - a buffer object containing the binary data.
|
|
59
|
+
* @param subType - the option binary type.
|
|
60
|
+
*/
|
|
61
|
+
constructor(buffer?: string | BinarySequence, subType?: number) {
|
|
62
|
+
if (!(this instanceof Binary)) return new Binary(buffer, subType);
|
|
63
|
+
|
|
64
|
+
if (
|
|
65
|
+
!(buffer == null) &&
|
|
66
|
+
!(typeof buffer === 'string') &&
|
|
67
|
+
!ArrayBuffer.isView(buffer) &&
|
|
68
|
+
!(buffer instanceof ArrayBuffer) &&
|
|
69
|
+
!Array.isArray(buffer)
|
|
70
|
+
) {
|
|
71
|
+
throw new TypeError(
|
|
72
|
+
'Binary can only be constructed from string, Buffer, TypedArray, or Array<number>'
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
this.sub_type = subType ?? Binary.BSON_BINARY_SUBTYPE_DEFAULT;
|
|
77
|
+
|
|
78
|
+
if (buffer == null) {
|
|
79
|
+
// create an empty binary buffer
|
|
80
|
+
this.buffer = Buffer.alloc(Binary.BUFFER_SIZE);
|
|
81
|
+
this.position = 0;
|
|
82
|
+
} else {
|
|
83
|
+
if (typeof buffer === 'string') {
|
|
84
|
+
// string
|
|
85
|
+
this.buffer = Buffer.from(buffer, 'binary');
|
|
86
|
+
} else if (Array.isArray(buffer)) {
|
|
87
|
+
// number[]
|
|
88
|
+
this.buffer = Buffer.from(buffer);
|
|
89
|
+
} else {
|
|
90
|
+
// Buffer | TypedArray | ArrayBuffer
|
|
91
|
+
this.buffer = ensureBuffer(buffer);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
this.position = this.buffer.byteLength;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Updates this binary with byte_value.
|
|
100
|
+
*
|
|
101
|
+
* @param byteValue - a single byte we wish to write.
|
|
102
|
+
*/
|
|
103
|
+
put(byteValue: string | number | Uint8Array | Buffer | number[]): void {
|
|
104
|
+
// If it's a string and a has more than one character throw an error
|
|
105
|
+
if (typeof byteValue === 'string' && byteValue.length !== 1) {
|
|
106
|
+
throw new TypeError('only accepts single character String');
|
|
107
|
+
} else if (typeof byteValue !== 'number' && byteValue.length !== 1)
|
|
108
|
+
throw new TypeError('only accepts single character Uint8Array or Array');
|
|
109
|
+
|
|
110
|
+
// Decode the byte value once
|
|
111
|
+
let decodedByte: number;
|
|
112
|
+
if (typeof byteValue === 'string') {
|
|
113
|
+
decodedByte = byteValue.charCodeAt(0);
|
|
114
|
+
} else if (typeof byteValue === 'number') {
|
|
115
|
+
decodedByte = byteValue;
|
|
116
|
+
} else {
|
|
117
|
+
decodedByte = byteValue[0];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (decodedByte < 0 || decodedByte > 255) {
|
|
121
|
+
throw new TypeError('only accepts number in a valid unsigned byte range 0-255');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (this.buffer.length > this.position) {
|
|
125
|
+
this.buffer[this.position++] = decodedByte;
|
|
126
|
+
} else {
|
|
127
|
+
const buffer = Buffer.alloc(Binary.BUFFER_SIZE + this.buffer.length);
|
|
128
|
+
// Combine the two buffers together
|
|
129
|
+
this.buffer.copy(buffer, 0, 0, this.buffer.length);
|
|
130
|
+
this.buffer = buffer;
|
|
131
|
+
this.buffer[this.position++] = decodedByte;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Writes a buffer or string to the binary.
|
|
137
|
+
*
|
|
138
|
+
* @param sequence - a string or buffer to be written to the Binary BSON object.
|
|
139
|
+
* @param offset - specify the binary of where to write the content.
|
|
140
|
+
*/
|
|
141
|
+
write(sequence: string | BinarySequence, offset: number): void {
|
|
142
|
+
offset = typeof offset === 'number' ? offset : this.position;
|
|
143
|
+
|
|
144
|
+
// If the buffer is to small let's extend the buffer
|
|
145
|
+
if (this.buffer.length < offset + sequence.length) {
|
|
146
|
+
const buffer = Buffer.alloc(this.buffer.length + sequence.length);
|
|
147
|
+
this.buffer.copy(buffer, 0, 0, this.buffer.length);
|
|
148
|
+
|
|
149
|
+
// Assign the new buffer
|
|
150
|
+
this.buffer = buffer;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (ArrayBuffer.isView(sequence)) {
|
|
154
|
+
this.buffer.set(ensureBuffer(sequence), offset);
|
|
155
|
+
this.position =
|
|
156
|
+
offset + sequence.byteLength > this.position ? offset + sequence.length : this.position;
|
|
157
|
+
} else if (typeof sequence === 'string') {
|
|
158
|
+
this.buffer.write(sequence, offset, sequence.length, 'binary');
|
|
159
|
+
this.position =
|
|
160
|
+
offset + sequence.length > this.position ? offset + sequence.length : this.position;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Reads **length** bytes starting at **position**.
|
|
166
|
+
*
|
|
167
|
+
* @param position - read from the given position in the Binary.
|
|
168
|
+
* @param length - the number of bytes to read.
|
|
169
|
+
*/
|
|
170
|
+
read(position: number, length: number): BinarySequence {
|
|
171
|
+
length = length && length > 0 ? length : this.position;
|
|
172
|
+
|
|
173
|
+
// Let's return the data based on the type we have
|
|
174
|
+
return this.buffer.slice(position, position + length);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Returns the value of this binary as a string.
|
|
179
|
+
* @param asRaw - Will skip converting to a string
|
|
180
|
+
* @remarks
|
|
181
|
+
* This is handy when calling this function conditionally for some key value pairs and not others
|
|
182
|
+
*/
|
|
183
|
+
value(asRaw?: boolean): string | BinarySequence {
|
|
184
|
+
asRaw = !!asRaw;
|
|
185
|
+
|
|
186
|
+
// Optimize to serialize for the situation where the data == size of buffer
|
|
187
|
+
if (asRaw && this.buffer.length === this.position) {
|
|
188
|
+
return this.buffer;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// If it's a node.js buffer object
|
|
192
|
+
if (asRaw) {
|
|
193
|
+
return this.buffer.slice(0, this.position);
|
|
194
|
+
}
|
|
195
|
+
return this.buffer.toString('binary', 0, this.position);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** the length of the binary sequence */
|
|
199
|
+
length(): number {
|
|
200
|
+
return this.position;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** @internal */
|
|
204
|
+
toJSON(): string {
|
|
205
|
+
return this.buffer.toString('base64');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** @internal */
|
|
209
|
+
toString(format: string): string {
|
|
210
|
+
return this.buffer.toString(format);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/** @internal */
|
|
214
|
+
toExtendedJSON(options?: EJSONOptions): BinaryExtendedLegacy | BinaryExtended {
|
|
215
|
+
options = options || {};
|
|
216
|
+
const base64String = this.buffer.toString('base64');
|
|
217
|
+
|
|
218
|
+
const subType = Number(this.sub_type).toString(16);
|
|
219
|
+
if (options.legacy) {
|
|
220
|
+
return {
|
|
221
|
+
$binary: base64String,
|
|
222
|
+
$type: subType.length === 1 ? '0' + subType : subType
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
$binary: {
|
|
227
|
+
base64: base64String,
|
|
228
|
+
subType: subType.length === 1 ? '0' + subType : subType
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** @internal */
|
|
234
|
+
static fromExtendedJSON(
|
|
235
|
+
doc: BinaryExtendedLegacy | BinaryExtended | UUIDExtended,
|
|
236
|
+
options?: EJSONOptions
|
|
237
|
+
): Binary {
|
|
238
|
+
options = options || {};
|
|
239
|
+
let data: Buffer | undefined;
|
|
240
|
+
let type;
|
|
241
|
+
if ('$binary' in doc) {
|
|
242
|
+
if (options.legacy && typeof doc.$binary === 'string' && '$type' in doc) {
|
|
243
|
+
type = doc.$type ? parseInt(doc.$type, 16) : 0;
|
|
244
|
+
data = Buffer.from(doc.$binary, 'base64');
|
|
245
|
+
} else {
|
|
246
|
+
if (typeof doc.$binary !== 'string') {
|
|
247
|
+
type = doc.$binary.subType ? parseInt(doc.$binary.subType, 16) : 0;
|
|
248
|
+
data = Buffer.from(doc.$binary.base64, 'base64');
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
} else if ('$uuid' in doc) {
|
|
252
|
+
type = 4;
|
|
253
|
+
data = Buffer.from(parseUUID(doc.$uuid));
|
|
254
|
+
}
|
|
255
|
+
if (!data) {
|
|
256
|
+
throw new TypeError(`Unexpected Binary Extended JSON format ${JSON.stringify(doc)}`);
|
|
257
|
+
}
|
|
258
|
+
return new Binary(data, type);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/** @internal */
|
|
262
|
+
[Symbol.for('nodejs.util.inspect.custom')](): string {
|
|
263
|
+
return this.inspect();
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
inspect(): string {
|
|
267
|
+
const asBuffer = this.value(true);
|
|
268
|
+
return `new Binary(Buffer.from("${asBuffer.toString('hex')}", "hex"), ${this.sub_type})`;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
Object.defineProperty(Binary.prototype, '_bsontype', { value: 'Binary' });
|
package/src/bson.ts
ADDED
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
import { Binary } from './binary';
|
|
3
|
+
import { Code } from './code';
|
|
4
|
+
import { DBRef } from './db_ref';
|
|
5
|
+
import { Decimal128 } from './decimal128';
|
|
6
|
+
import { Double } from './double';
|
|
7
|
+
import { ensureBuffer } from './ensure_buffer';
|
|
8
|
+
import { EJSON } from './extended_json';
|
|
9
|
+
import { Int32 } from './int_32';
|
|
10
|
+
import { Long } from './long';
|
|
11
|
+
import { Map } from './map';
|
|
12
|
+
import { MaxKey } from './max_key';
|
|
13
|
+
import { MinKey } from './min_key';
|
|
14
|
+
import { ObjectId } from './objectid';
|
|
15
|
+
import { calculateObjectSize as internalCalculateObjectSize } from './parser/calculate_size';
|
|
16
|
+
// Parts of the parser
|
|
17
|
+
import { deserialize as internalDeserialize, DeserializeOptions } from './parser/deserializer';
|
|
18
|
+
import { serializeInto as internalSerialize, SerializeOptions } from './parser/serializer';
|
|
19
|
+
import { BSONRegExp } from './regexp';
|
|
20
|
+
import { BSONSymbol } from './symbol';
|
|
21
|
+
import { Timestamp } from './timestamp';
|
|
22
|
+
export { BinaryExtended, BinaryExtendedLegacy, BinarySequence } from './binary';
|
|
23
|
+
export { CodeExtended } from './code';
|
|
24
|
+
export {
|
|
25
|
+
BSON_BINARY_SUBTYPE_BYTE_ARRAY,
|
|
26
|
+
BSON_BINARY_SUBTYPE_DEFAULT,
|
|
27
|
+
BSON_BINARY_SUBTYPE_FUNCTION,
|
|
28
|
+
BSON_BINARY_SUBTYPE_MD5,
|
|
29
|
+
BSON_BINARY_SUBTYPE_USER_DEFINED,
|
|
30
|
+
BSON_BINARY_SUBTYPE_UUID,
|
|
31
|
+
BSON_BINARY_SUBTYPE_UUID_NEW,
|
|
32
|
+
BSON_DATA_ARRAY,
|
|
33
|
+
BSON_DATA_BINARY,
|
|
34
|
+
BSON_DATA_BOOLEAN,
|
|
35
|
+
BSON_DATA_CODE,
|
|
36
|
+
BSON_DATA_CODE_W_SCOPE,
|
|
37
|
+
BSON_DATA_DATE,
|
|
38
|
+
BSON_DATA_DBPOINTER,
|
|
39
|
+
BSON_DATA_DECIMAL128,
|
|
40
|
+
BSON_DATA_INT,
|
|
41
|
+
BSON_DATA_LONG,
|
|
42
|
+
BSON_DATA_MAX_KEY,
|
|
43
|
+
BSON_DATA_MIN_KEY,
|
|
44
|
+
BSON_DATA_NULL,
|
|
45
|
+
BSON_DATA_NUMBER,
|
|
46
|
+
BSON_DATA_OBJECT,
|
|
47
|
+
BSON_DATA_OID,
|
|
48
|
+
BSON_DATA_REGEXP,
|
|
49
|
+
BSON_DATA_STRING,
|
|
50
|
+
BSON_DATA_SYMBOL,
|
|
51
|
+
BSON_DATA_TIMESTAMP,
|
|
52
|
+
BSON_DATA_UNDEFINED,
|
|
53
|
+
BSON_INT32_MAX,
|
|
54
|
+
BSON_INT32_MIN,
|
|
55
|
+
BSON_INT64_MAX,
|
|
56
|
+
BSON_INT64_MIN
|
|
57
|
+
} from './constants';
|
|
58
|
+
export { DBRefLike } from './db_ref';
|
|
59
|
+
export { Decimal128Extended } from './decimal128';
|
|
60
|
+
export { DoubleExtended } from './double';
|
|
61
|
+
export { EJSON, EJSONOptions } from './extended_json';
|
|
62
|
+
export { Int32Extended } from './int_32';
|
|
63
|
+
export { LongExtended } from './long';
|
|
64
|
+
export { MaxKeyExtended } from './max_key';
|
|
65
|
+
export { MinKeyExtended } from './min_key';
|
|
66
|
+
export { ObjectIdExtended, ObjectIdLike } from './objectid';
|
|
67
|
+
export { BSONRegExpExtended, BSONRegExpExtendedLegacy } from './regexp';
|
|
68
|
+
export { BSONSymbolExtended } from './symbol';
|
|
69
|
+
export {
|
|
70
|
+
LongWithoutOverrides,
|
|
71
|
+
LongWithoutOverridesClass,
|
|
72
|
+
TimestampExtended,
|
|
73
|
+
TimestampOverrides
|
|
74
|
+
} from './timestamp';
|
|
75
|
+
export { UUIDExtended } from './uuid';
|
|
76
|
+
export { SerializeOptions, DeserializeOptions };
|
|
77
|
+
export {
|
|
78
|
+
Code,
|
|
79
|
+
Map,
|
|
80
|
+
BSONSymbol,
|
|
81
|
+
DBRef,
|
|
82
|
+
Binary,
|
|
83
|
+
ObjectId,
|
|
84
|
+
Long,
|
|
85
|
+
Timestamp,
|
|
86
|
+
Double,
|
|
87
|
+
Int32,
|
|
88
|
+
MinKey,
|
|
89
|
+
MaxKey,
|
|
90
|
+
BSONRegExp,
|
|
91
|
+
Decimal128,
|
|
92
|
+
// In 4.0.0 and 4.0.1, this property name was changed to ObjectId to match the class name.
|
|
93
|
+
// This caused interoperability problems with previous versions of the library, so in
|
|
94
|
+
// later builds we changed it back to ObjectID (capital D) to match legacy implementations.
|
|
95
|
+
ObjectId as ObjectID
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/** @public */
|
|
99
|
+
export interface Document {
|
|
100
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
101
|
+
[key: string]: any;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** @internal */
|
|
105
|
+
// Default Max Size
|
|
106
|
+
const MAXSIZE = 1024 * 1024 * 17;
|
|
107
|
+
|
|
108
|
+
// Current Internal Temporary Serialization Buffer
|
|
109
|
+
let buffer = Buffer.alloc(MAXSIZE);
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Sets the size of the internal serialization buffer.
|
|
113
|
+
*
|
|
114
|
+
* @param size - The desired size for the internal serialization buffer
|
|
115
|
+
* @public
|
|
116
|
+
*/
|
|
117
|
+
export function setInternalBufferSize(size: number): void {
|
|
118
|
+
// Resize the internal serialization buffer if needed
|
|
119
|
+
if (buffer.length < size) {
|
|
120
|
+
buffer = Buffer.alloc(size);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Serialize a Javascript object.
|
|
126
|
+
*
|
|
127
|
+
* @param object - the Javascript object to serialize.
|
|
128
|
+
* @returns Buffer object containing the serialized object.
|
|
129
|
+
* @public
|
|
130
|
+
*/
|
|
131
|
+
export function serialize(object: Document, options: SerializeOptions = {}): Buffer {
|
|
132
|
+
// Unpack the options
|
|
133
|
+
const checkKeys = typeof options.checkKeys === 'boolean' ? options.checkKeys : false;
|
|
134
|
+
const serializeFunctions =
|
|
135
|
+
typeof options.serializeFunctions === 'boolean' ? options.serializeFunctions : false;
|
|
136
|
+
const ignoreUndefined =
|
|
137
|
+
typeof options.ignoreUndefined === 'boolean' ? options.ignoreUndefined : true;
|
|
138
|
+
const minInternalBufferSize =
|
|
139
|
+
typeof options.minInternalBufferSize === 'number' ? options.minInternalBufferSize : MAXSIZE;
|
|
140
|
+
|
|
141
|
+
// Resize the internal serialization buffer if needed
|
|
142
|
+
if (buffer.length < minInternalBufferSize) {
|
|
143
|
+
buffer = Buffer.alloc(minInternalBufferSize);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Attempt to serialize
|
|
147
|
+
const serializationIndex = internalSerialize(
|
|
148
|
+
buffer,
|
|
149
|
+
object,
|
|
150
|
+
checkKeys,
|
|
151
|
+
0,
|
|
152
|
+
0,
|
|
153
|
+
serializeFunctions,
|
|
154
|
+
ignoreUndefined,
|
|
155
|
+
[]
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
// Create the final buffer
|
|
159
|
+
const finishedBuffer = Buffer.alloc(serializationIndex);
|
|
160
|
+
|
|
161
|
+
// Copy into the finished buffer
|
|
162
|
+
buffer.copy(finishedBuffer, 0, 0, finishedBuffer.length);
|
|
163
|
+
|
|
164
|
+
// Return the buffer
|
|
165
|
+
return finishedBuffer;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Serialize a Javascript object using a predefined Buffer and index into the buffer,
|
|
170
|
+
* useful when pre-allocating the space for serialization.
|
|
171
|
+
*
|
|
172
|
+
* @param object - the Javascript object to serialize.
|
|
173
|
+
* @param finalBuffer - the Buffer you pre-allocated to store the serialized BSON object.
|
|
174
|
+
* @returns the index pointing to the last written byte in the buffer.
|
|
175
|
+
* @public
|
|
176
|
+
*/
|
|
177
|
+
export function serializeWithBufferAndIndex(
|
|
178
|
+
object: Document,
|
|
179
|
+
finalBuffer: Buffer,
|
|
180
|
+
options: SerializeOptions = {}
|
|
181
|
+
): number {
|
|
182
|
+
// Unpack the options
|
|
183
|
+
const checkKeys = typeof options.checkKeys === 'boolean' ? options.checkKeys : false;
|
|
184
|
+
const serializeFunctions =
|
|
185
|
+
typeof options.serializeFunctions === 'boolean' ? options.serializeFunctions : false;
|
|
186
|
+
const ignoreUndefined =
|
|
187
|
+
typeof options.ignoreUndefined === 'boolean' ? options.ignoreUndefined : true;
|
|
188
|
+
const startIndex = typeof options.index === 'number' ? options.index : 0;
|
|
189
|
+
|
|
190
|
+
// Attempt to serialize
|
|
191
|
+
const serializationIndex = internalSerialize(
|
|
192
|
+
buffer,
|
|
193
|
+
object,
|
|
194
|
+
checkKeys,
|
|
195
|
+
0,
|
|
196
|
+
0,
|
|
197
|
+
serializeFunctions,
|
|
198
|
+
ignoreUndefined
|
|
199
|
+
);
|
|
200
|
+
buffer.copy(finalBuffer, startIndex, 0, serializationIndex);
|
|
201
|
+
|
|
202
|
+
// Return the index
|
|
203
|
+
return startIndex + serializationIndex - 1;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Deserialize data as BSON.
|
|
208
|
+
*
|
|
209
|
+
* @param buffer - the buffer containing the serialized set of BSON documents.
|
|
210
|
+
* @returns returns the deserialized Javascript Object.
|
|
211
|
+
* @public
|
|
212
|
+
*/
|
|
213
|
+
export function deserialize(
|
|
214
|
+
buffer: Buffer | ArrayBufferView | ArrayBuffer,
|
|
215
|
+
options: DeserializeOptions = {}
|
|
216
|
+
): Document {
|
|
217
|
+
return internalDeserialize(ensureBuffer(buffer), options);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** @public */
|
|
221
|
+
export type CalculateObjectSizeOptions = Pick<
|
|
222
|
+
SerializeOptions,
|
|
223
|
+
'serializeFunctions' | 'ignoreUndefined'
|
|
224
|
+
>;
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Calculate the bson size for a passed in Javascript object.
|
|
228
|
+
*
|
|
229
|
+
* @param object - the Javascript object to calculate the BSON byte size for
|
|
230
|
+
* @returns size of BSON object in bytes
|
|
231
|
+
* @public
|
|
232
|
+
*/
|
|
233
|
+
export function calculateObjectSize(
|
|
234
|
+
object: Document,
|
|
235
|
+
options: CalculateObjectSizeOptions = {}
|
|
236
|
+
): number {
|
|
237
|
+
options = options || {};
|
|
238
|
+
|
|
239
|
+
const serializeFunctions =
|
|
240
|
+
typeof options.serializeFunctions === 'boolean' ? options.serializeFunctions : false;
|
|
241
|
+
const ignoreUndefined =
|
|
242
|
+
typeof options.ignoreUndefined === 'boolean' ? options.ignoreUndefined : true;
|
|
243
|
+
|
|
244
|
+
return internalCalculateObjectSize(object, serializeFunctions, ignoreUndefined);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Deserialize stream data as BSON documents.
|
|
249
|
+
*
|
|
250
|
+
* @param data - the buffer containing the serialized set of BSON documents.
|
|
251
|
+
* @param startIndex - the start index in the data Buffer where the deserialization is to start.
|
|
252
|
+
* @param numberOfDocuments - number of documents to deserialize.
|
|
253
|
+
* @param documents - an array where to store the deserialized documents.
|
|
254
|
+
* @param docStartIndex - the index in the documents array from where to start inserting documents.
|
|
255
|
+
* @param options - additional options used for the deserialization.
|
|
256
|
+
* @returns next index in the buffer after deserialization **x** numbers of documents.
|
|
257
|
+
* @public
|
|
258
|
+
*/
|
|
259
|
+
export function deserializeStream(
|
|
260
|
+
data: Buffer | ArrayBufferView | ArrayBuffer,
|
|
261
|
+
startIndex: number,
|
|
262
|
+
numberOfDocuments: number,
|
|
263
|
+
documents: Document[],
|
|
264
|
+
docStartIndex: number,
|
|
265
|
+
options: DeserializeOptions
|
|
266
|
+
): number {
|
|
267
|
+
const internalOptions = Object.assign(
|
|
268
|
+
{ allowObjectSmallerThanBufferSize: true, index: 0 },
|
|
269
|
+
options
|
|
270
|
+
);
|
|
271
|
+
const bufferData = ensureBuffer(data);
|
|
272
|
+
|
|
273
|
+
let index = startIndex;
|
|
274
|
+
// Loop over all documents
|
|
275
|
+
for (let i = 0; i < numberOfDocuments; i++) {
|
|
276
|
+
// Find size of the document
|
|
277
|
+
const size =
|
|
278
|
+
bufferData[index] |
|
|
279
|
+
(bufferData[index + 1] << 8) |
|
|
280
|
+
(bufferData[index + 2] << 16) |
|
|
281
|
+
(bufferData[index + 3] << 24);
|
|
282
|
+
// Update options with index
|
|
283
|
+
internalOptions.index = index;
|
|
284
|
+
// Parse the document at this point
|
|
285
|
+
documents[docStartIndex + i] = internalDeserialize(bufferData, internalOptions);
|
|
286
|
+
// Adjust index by the document size
|
|
287
|
+
index = index + size;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Return object containing end index of parsing and list of documents
|
|
291
|
+
return index;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* BSON default export
|
|
296
|
+
* @deprecated Please use named exports
|
|
297
|
+
* @privateRemarks
|
|
298
|
+
* We want to someday deprecate the default export,
|
|
299
|
+
* so none of the new TS types are being exported on the default
|
|
300
|
+
* @public
|
|
301
|
+
*/
|
|
302
|
+
const BSON = {
|
|
303
|
+
Binary,
|
|
304
|
+
Code,
|
|
305
|
+
DBRef,
|
|
306
|
+
Decimal128,
|
|
307
|
+
Double,
|
|
308
|
+
Int32,
|
|
309
|
+
Long,
|
|
310
|
+
Map,
|
|
311
|
+
MaxKey,
|
|
312
|
+
MinKey,
|
|
313
|
+
ObjectId,
|
|
314
|
+
ObjectID: ObjectId,
|
|
315
|
+
BSONRegExp,
|
|
316
|
+
BSONSymbol,
|
|
317
|
+
Timestamp,
|
|
318
|
+
EJSON,
|
|
319
|
+
setInternalBufferSize,
|
|
320
|
+
serialize,
|
|
321
|
+
serializeWithBufferAndIndex,
|
|
322
|
+
deserialize,
|
|
323
|
+
calculateObjectSize,
|
|
324
|
+
deserializeStream
|
|
325
|
+
};
|
|
326
|
+
export default BSON;
|
package/src/code.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { Document } from './bson';
|
|
2
|
+
|
|
3
|
+
/** @public */
|
|
4
|
+
export interface CodeExtended {
|
|
5
|
+
$code: string | Function;
|
|
6
|
+
$scope?: Document;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A class representation of the BSON Code type.
|
|
11
|
+
* @public
|
|
12
|
+
*/
|
|
13
|
+
export class Code {
|
|
14
|
+
_bsontype!: 'Code';
|
|
15
|
+
|
|
16
|
+
code!: string | Function;
|
|
17
|
+
scope?: Document;
|
|
18
|
+
/**
|
|
19
|
+
* @param code - a string or function.
|
|
20
|
+
* @param scope - an optional scope for the function.
|
|
21
|
+
*/
|
|
22
|
+
constructor(code: string | Function, scope?: Document) {
|
|
23
|
+
if (!(this instanceof Code)) return new Code(code, scope);
|
|
24
|
+
|
|
25
|
+
this.code = code;
|
|
26
|
+
this.scope = scope;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** @internal */
|
|
30
|
+
toJSON(): { code: string | Function; scope?: Document } {
|
|
31
|
+
return { code: this.code, scope: this.scope };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** @internal */
|
|
35
|
+
toExtendedJSON(): CodeExtended {
|
|
36
|
+
if (this.scope) {
|
|
37
|
+
return { $code: this.code, $scope: this.scope };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return { $code: this.code };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** @internal */
|
|
44
|
+
static fromExtendedJSON(doc: CodeExtended): Code {
|
|
45
|
+
return new Code(doc.$code, doc.$scope);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** @internal */
|
|
49
|
+
[Symbol.for('nodejs.util.inspect.custom')](): string {
|
|
50
|
+
return this.inspect();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
inspect(): string {
|
|
54
|
+
const codeJson = this.toJSON();
|
|
55
|
+
return `new Code("${codeJson.code}"${
|
|
56
|
+
codeJson.scope ? `, ${JSON.stringify(codeJson.scope)}` : ''
|
|
57
|
+
})`;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
Object.defineProperty(Code.prototype, '_bsontype', { value: 'Code' });
|