Skip to content

Commit 067a7ba

Browse files
committed
fix: only upgrade symbol to string if promoteValues is true
We currently automatically promote BSONSymbol to a JavaScript string, which loses type information when roundtripping the value. Since we already have a setting to signal when a user doesn't mind the loss of type information (`promoteValues`), this behavior is now gated by that option. NODE-2518
1 parent 30f5a8f commit 067a7ba

File tree

3 files changed

+33
-57
lines changed

3 files changed

+33
-57
lines changed

Diff for: lib/double.js

+2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ class Double {
4343
return this.value;
4444
}
4545

46+
// NOTE: JavaScript has +0 and -0, apparently to model limit calculations. If a user
47+
// explicitly provided `-0` then we need to ensure the sign makes it into the output
4648
if (Object.is(Math.sign(this.value), -0)) {
4749
return { $numberDouble: `-${this.value.toFixed(1)}` };
4850
}

Diff for: lib/parser/deserializer.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const Decimal128 = require('../decimal128');
1212
const Int32 = require('../int_32');
1313
const DBRef = require('../db_ref');
1414
const BSONRegExp = require('../regexp');
15+
const BSONSymbol = require('../symbol');
1516
const Binary = require('../binary');
1617
const constants = require('../constants');
1718
const validateUtf8 = require('../validate_utf8').validateUtf8;
@@ -414,8 +415,8 @@ function deserializeObject(buffer, index, options, isArray) {
414415
buffer[index + stringSize - 1] !== 0
415416
)
416417
throw new Error('bad string length in bson');
417-
// symbol is deprecated - upgrade to string.
418-
object[name] = buffer.toString('utf8', index, index + stringSize - 1);
418+
const symbol = buffer.toString('utf8', index, index + stringSize - 1);
419+
object[name] = promoteValues ? symbol : new BSONSymbol(symbol);
419420
index = index + stringSize;
420421
} else if (elementType === constants.BSON_DATA_TIMESTAMP) {
421422
const lowBits =

Diff for: test/node/bson_corpus_tests.js

+28-55
Original file line numberDiff line numberDiff line change
@@ -58,35 +58,9 @@ const skipBSON = {
5858

5959
const skipExtendedJSON = {
6060
'Timestamp with high-order bit set on both seconds and increment':
61-
'Current BSON implementation of timestamp/long cannot hold these values - 1 too large.'
62-
};
63-
64-
// test modifications for JavaScript
65-
const modifiedDoubles = {
66-
'+1.0': { canonical_extjson: '{"d":{"$numberDouble":"1"}}' },
67-
'-1.0': { canonical_extjson: '{"d":{"$numberDouble":"-1"}}' },
68-
'1.23456789012345677E+18': { canonical_extjson: '{"d":{"$numberDouble":"1234567890123456800"}}' },
69-
'-1.23456789012345677E+18': {
70-
canonical_extjson: '{"d":{"$numberDouble":"-1234567890123456800"}}'
71-
},
72-
'0.0': { canonical_extjson: '{"d":{"$numberDouble":"0"}}' },
73-
'-0.0': {
74-
canonical_extjson: '{"d":{"$numberDouble":"0"}}',
75-
canonical_bson: '10000000016400000000000000000000'
76-
}
77-
};
78-
79-
const modifiedMultitype = {
80-
'All BSON types': {
81-
canonical_extjson:
82-
'{"_id":{"$oid":"57e193d7a9cc81b4027498b5"},"Symbol":"symbol","String":"string","Int32":{"$numberInt":"42"},"Int64":{"$numberLong":"42"},"Double":{"$numberDouble":"-1"},"Binary":{"$binary":{"base64":"o0w498Or7cijeBSpkquNtg==","subType":"03"}},"BinaryUserDefined":{"$binary":{"base64":"AQIDBAU=","subType":"80"}},"Code":{"$code":"function() {}"},"CodeWithScope":{"$code":"function() {}","$scope":{}},"Subdocument":{"foo":"bar"},"Array":[{"$numberInt":"1"},{"$numberInt":"2"},{"$numberInt":"3"},{"$numberInt":"4"},{"$numberInt":"5"}],"Timestamp":{"$timestamp":{"t":42,"i":1}},"Regex":{"$regularExpression":{"pattern":"pattern","options":""}},"DatetimeEpoch":{"$date":{"$numberLong":"0"}},"DatetimePositive":{"$date":{"$numberLong":"2147483647"}},"DatetimeNegative":{"$date":{"$numberLong":"-2147483648"}},"True":true,"False":false,"DBPointer":{"$ref":"collection","$id":{"$oid":"57e193d7a9cc81b4027498b1"}},"DBRef":{"$ref":"collection","$id":{"$oid":"57fd71e96e32ab4225b723fb"},"$db":"database"},"Minkey":{"$minKey":1},"Maxkey":{"$maxKey":1},"Null":null,"Undefined":null}',
83-
canonical_bson:
84-
'48020000075f69640057e193d7a9cc81b4027498b50253796d626f6c000700000073796d626f6c0002537472696e670007000000737472696e670010496e743332002a00000012496e743634002a0000000000000001446f75626c6500000000000000f0bf0542696e617279001000000003a34c38f7c3abedc8a37814a992ab8db60542696e61727955736572446566696e656400050000008001020304050d436f6465000e00000066756e6374696f6e2829207b7d000f436f64655769746853636f7065001b0000000e00000066756e6374696f6e2829207b7d00050000000003537562646f63756d656e74001200000002666f6f0004000000626172000004417272617900280000001030000100000010310002000000103200030000001033000400000010340005000000001154696d657374616d7000010000002a0000000b5265676578007061747465726e0000094461746574696d6545706f6368000000000000000000094461746574696d65506f73697469766500ffffff7f00000000094461746574696d654e656761746976650000000080ffffffff085472756500010846616c73650000034442506f696e746572002b0000000224726566000b000000636f6c6c656374696f6e00072469640057e193d7a9cc81b4027498b100034442526566003d0000000224726566000b000000636f6c6c656374696f6e00072469640057fd71e96e32ab4225b723fb02246462000900000064617461626173650000ff4d696e6b6579007f4d61786b6579000a4e756c6c000a556e646566696e65640000',
85-
converted_extjson:
86-
'{"_id":{"$oid":"57e193d7a9cc81b4027498b5"},"Symbol":"symbol","String":"string","Int32":{"$numberInt":"42"},"Int64":{"$numberLong":"42"},"Double":{"$numberDouble":"-1"},"Binary":{"$binary":{"base64":"o0w498Or7cijeBSpkquNtg==","subType":"03"}},"BinaryUserDefined":{"$binary":{"base64":"AQIDBAU=","subType":"80"}},"Code":{"$code":"function() {}"},"CodeWithScope":{"$code":"function() {}","$scope":{}},"Subdocument":{"foo":"bar"},"Array":[{"$numberInt":"1"},{"$numberInt":"2"},{"$numberInt":"3"},{"$numberInt":"4"},{"$numberInt":"5"}],"Timestamp":{"$timestamp":{"t":42,"i":1}},"Regex":{"$regularExpression":{"pattern":"pattern","options":""}},"DatetimeEpoch":{"$date":{"$numberLong":"0"}},"DatetimePositive":{"$date":{"$numberLong":"2147483647"}},"DatetimeNegative":{"$date":{"$numberLong":"-2147483648"}},"True":true,"False":false,"DBPointer":{"$ref":"collection","$id":{"$oid":"57e193d7a9cc81b4027498b1"}},"DBRef":{"$ref":"collection","$id":{"$oid":"57fd71e96e32ab4225b723fb"},"$db":"database"},"Minkey":{"$minKey":1},"Maxkey":{"$maxKey":1},"Null":null,"Undefined":null}',
87-
converted_bson:
88-
'48020000075f69640057e193d7a9cc81b4027498b50253796d626f6c000700000073796d626f6c0002537472696e670007000000737472696e670010496e743332002a00000012496e743634002a0000000000000001446f75626c6500000000000000f0bf0542696e617279001000000003a34c38f7c3abedc8a37814a992ab8db60542696e61727955736572446566696e656400050000008001020304050d436f6465000e00000066756e6374696f6e2829207b7d000f436f64655769746853636f7065001b0000000e00000066756e6374696f6e2829207b7d00050000000003537562646f63756d656e74001200000002666f6f0004000000626172000004417272617900280000001030000100000010310002000000103200030000001033000400000010340005000000001154696d657374616d7000010000002a0000000b5265676578007061747465726e0000094461746574696d6545706f6368000000000000000000094461746574696d65506f73697469766500ffffff7f00000000094461746574696d654e656761746976650000000080ffffffff085472756500010846616c73650000034442506f696e746572002b0000000224726566000b000000636f6c6c656374696f6e00072469640057e193d7a9cc81b4027498b100034442526566003d0000000224726566000b000000636f6c6c656374696f6e00072469640057fd71e96e32ab4225b723fb02246462000900000064617461626173650000ff4d696e6b6579007f4d61786b6579000a4e756c6c000a556e646566696e65640000'
89-
}
61+
'Current BSON implementation of timestamp/long cannot hold these values - 1 too large.',
62+
'1.23456789012345677E+18': 'NODE-2519',
63+
'-1.23456789012345677E+18': 'NODE-2519'
9064
};
9165

9266
const corpus = require('./tools/bson_corpus_test_loader');
@@ -96,22 +70,6 @@ describe('BSON Corpus', function() {
9670
const description = scenario.description;
9771
const valid = scenario.valid || [];
9872

99-
// since doubles are formatted differently in JS than in corpus, overwrite expected results
100-
if (description === 'Double type') {
101-
valid.forEach(v => {
102-
if (modifiedDoubles[v.description]) {
103-
Object.assign(v, modifiedDoubles[v.description]);
104-
}
105-
});
106-
// multitype test has a double nested in object, so change those expected values too
107-
} else if (description === 'Multiple types within the same document') {
108-
valid.forEach(v => {
109-
if (modifiedMultitype[v.description]) {
110-
Object.assign(v, modifiedMultitype[v.description]);
111-
}
112-
});
113-
}
114-
11573
describe(description, function() {
11674
if (valid) {
11775
describe('valid-bson', function() {
@@ -122,20 +80,35 @@ describe('BSON Corpus', function() {
12280
}
12381

12482
it(v.description, function() {
83+
if (v.description === 'All BSON types' && deprecated) {
84+
// there is just too much variation in the specified expectation to make this work
85+
this.skip();
86+
return;
87+
}
88+
12589
const cB = Buffer.from(v.canonical_bson, 'hex');
126-
let dB, convB;
127-
if (v.degenerate_bson) dB = Buffer.from(v.degenerate_bson, 'hex');
128-
if (v.converted_bson) convB = Buffer.from(v.converted_bson, 'hex');
90+
if (deprecated) {
91+
const roundTripped = BSON.serialize(
92+
BSON.deserialize(
93+
cB,
94+
Object.assign({}, deserializeOptions, { promoteValues: true })
95+
),
96+
serializeOptions
97+
);
12998

130-
const roundTripped = BSON.serialize(
131-
BSON.deserialize(cB, deserializeOptions),
132-
serializeOptions
133-
);
99+
const convB = Buffer.from(v.converted_bson, 'hex');
100+
expect(convB).to.deep.equal(roundTripped);
101+
} else {
102+
const roundTripped = BSON.serialize(
103+
BSON.deserialize(cB, deserializeOptions),
104+
serializeOptions
105+
);
134106

135-
if (deprecated) expect(convB).to.deep.equal(roundTripped);
136-
else expect(cB).to.deep.equal(roundTripped);
107+
expect(cB).to.deep.equal(roundTripped);
108+
}
137109

138-
if (dB) {
110+
if (v.degenerate_bson) {
111+
const dB = Buffer.from(v.degenerate_bson, 'hex');
139112
expect(cB).to.deep.equal(
140113
BSON.serialize(BSON.deserialize(dB, deserializeOptions), serializeOptions)
141114
);

0 commit comments

Comments
 (0)