Skip to content

Commit 9ff60ba

Browse files
authored
feat(NODE-4871): Add support for int64 deserialization to BigInt (#542)
1 parent e9e40a2 commit 9ff60ba

File tree

3 files changed

+273
-157
lines changed

3 files changed

+273
-157
lines changed

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -238,12 +238,13 @@ Serialize a Javascript object using a predefined Buffer and index into the buffe
238238
| buffer | <code>Buffer</code> | | the buffer containing the serialized set of BSON documents. |
239239
| [options.evalFunctions] | <code>Object</code> | <code>false</code> | evaluate functions in the BSON document scoped to the object deserialized. |
240240
| [options.cacheFunctions] | <code>Object</code> | <code>false</code> | cache evaluated functions for reuse. |
241+
| [options.useBigInt64] | <code>Object</code> | <code>false</code> | when deserializing a Long will return a BigInt. |
241242
| [options.promoteLongs] | <code>Object</code> | <code>true</code> | when deserializing a Long will fit it into a Number if it's smaller than 53 bits |
242243
| [options.promoteBuffers] | <code>Object</code> | <code>false</code> | when deserializing a Binary will return it as a node.js Buffer instance. |
243244
| [options.promoteValues] | <code>Object</code> | <code>false</code> | when deserializing will promote BSON values to their Node.js closest equivalent types. |
244245
| [options.fieldsAsRaw] | <code>Object</code> | <code></code> | allow to specify if there what fields we wish to return as unserialized raw buffer. |
245246
| [options.bsonRegExp] | <code>Object</code> | <code>false</code> | return BSON regular expressions as BSONRegExp instances. |
246-
| [options.allowObjectSmallerThanBufferSize] | <code>boolean</code> | <code>false</code> | allows the buffer to be larger than the parsed BSON object |
247+
| [options.allowObjectSmallerThanBufferSize] | <code>boolean</code> | <code>false</code> | allows the buffer to be larger than the parsed BSON object. |
247248

248249
Deserialize data as BSON.
249250

src/parser/deserializer.ts

+24-9
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ import { ObjectId } from '../objectid';
1414
import { BSONRegExp } from '../regexp';
1515
import { BSONSymbol } from '../symbol';
1616
import { Timestamp } from '../timestamp';
17-
import { ByteUtils } from '../utils/byte_utils';
17+
import { BSONDataView, ByteUtils } from '../utils/byte_utils';
1818
import { validateUtf8 } from '../validate_utf8';
1919

2020
/** @public */
2121
export interface DeserializeOptions {
22-
/** when deserializing a Long will fit it into a Number if it's smaller than 53 bits */
22+
/** when deserializing a Long will return as a BigInt. */
23+
useBigInt64?: boolean;
24+
/** when deserializing a Long will fit it into a Number if it's smaller than 53 bits. */
2325
promoteLongs?: boolean;
2426
/** when deserializing a Binary will return it as a node.js Buffer instance. */
2527
promoteBuffers?: boolean;
@@ -29,7 +31,7 @@ export interface DeserializeOptions {
2931
fieldsAsRaw?: Document;
3032
/** return BSON regular expressions as BSONRegExp instances. */
3133
bsonRegExp?: boolean;
32-
/** allows the buffer to be larger than the parsed BSON object */
34+
/** allows the buffer to be larger than the parsed BSON object. */
3335
allowObjectSmallerThanBufferSize?: boolean;
3436
/** Offset into buffer to begin reading document from */
3537
index?: number;
@@ -96,7 +98,7 @@ export function internalDeserialize(
9698
);
9799
}
98100

99-
// Start deserializtion
101+
// Start deserialization
100102
return deserializeObject(buffer, index, options, isArray);
101103
}
102104

@@ -117,9 +119,18 @@ function deserializeObject(
117119
const bsonRegExp = typeof options['bsonRegExp'] === 'boolean' ? options['bsonRegExp'] : false;
118120

119121
// Controls the promotion of values vs wrapper classes
120-
const promoteBuffers = options['promoteBuffers'] == null ? false : options['promoteBuffers'];
121-
const promoteLongs = options['promoteLongs'] == null ? true : options['promoteLongs'];
122-
const promoteValues = options['promoteValues'] == null ? true : options['promoteValues'];
122+
const promoteBuffers = options.promoteBuffers ?? false;
123+
const promoteLongs = options.promoteLongs ?? true;
124+
const promoteValues = options.promoteValues ?? true;
125+
const useBigInt64 = options.useBigInt64 ?? false;
126+
127+
if (useBigInt64 && !promoteValues) {
128+
throw new BSONError('Must either request bigint or Long for int64 deserialization');
129+
}
130+
131+
if (useBigInt64 && !promoteLongs) {
132+
throw new BSONError('Must either request bigint or Long for int64 deserialization');
133+
}
123134

124135
// Ensures default validation option if none given
125136
const validation = options.validation == null ? { utf8: true } : options.validation;
@@ -323,6 +334,8 @@ function deserializeObject(
323334
value = null;
324335
} else if (elementType === constants.BSON_DATA_LONG) {
325336
// Unpack the low and high bits
337+
const dataview = BSONDataView.fromUint8Array(buffer.subarray(index, index + 8));
338+
326339
const lowBits =
327340
buffer[index++] |
328341
(buffer[index++] << 8) |
@@ -334,8 +347,10 @@ function deserializeObject(
334347
(buffer[index++] << 16) |
335348
(buffer[index++] << 24);
336349
const long = new Long(lowBits, highBits);
337-
// Promote the long if possible
338-
if (promoteLongs && promoteValues === true) {
350+
if (useBigInt64) {
351+
value = dataview.getBigInt64(0, true);
352+
} else if (promoteLongs && promoteValues === true) {
353+
// Promote the long if possible
339354
value =
340355
long.lessThanOrEqual(JS_INT_MAX_LONG) && long.greaterThanOrEqual(JS_INT_MIN_LONG)
341356
? long.toNumber()

0 commit comments

Comments
 (0)