Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(NODE-4419): UUID class deserialization #509

Merged
merged 8 commits into from
Aug 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"@typescript-eslint/eslint-plugin": "^5.30.0",
"@typescript-eslint/parser": "^5.30.0",
"array-includes": "^3.1.3",
"array.prototype.flatmap": "^1.3.0",
"benchmark": "^2.1.4",
"chai": "^4.2.0",
"eslint": "^8.18.0",
Expand Down
11 changes: 9 additions & 2 deletions src/parser/deserializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ export interface DeserializeOptions {
promoteBuffers?: boolean;
/** when deserializing will promote BSON values to their Node.js closest equivalent types. */
promoteValues?: boolean;
/** when deserializing will return UUID type, if promoteBuffers is also true then promoteUUIDs will take precedence and a buffer will not be returned */
promoteUUIDs?: boolean;
/** allow to specify if there what fields we wish to return as unserialized raw buffer. */
fieldsAsRaw?: Document;
/** return BSON regular expressions as BSONRegExp instances. */
Expand Down Expand Up @@ -135,6 +137,7 @@ function deserializeObject(
const promoteBuffers = options['promoteBuffers'] == null ? false : options['promoteBuffers'];
const promoteLongs = options['promoteLongs'] == null ? true : options['promoteLongs'];
const promoteValues = options['promoteValues'] == null ? true : options['promoteValues'];
const promoteUUIDs = options.promoteUUIDs == null ? false : options.promoteUUIDs;

// Ensures default validation option if none given
const validation = options.validation == null ? { utf8: true } : options.validation;
Expand Down Expand Up @@ -413,7 +416,9 @@ function deserializeObject(
throw new BSONError('Binary type with subtype 0x02 contains too short binary size');
}

if (promoteBuffers && promoteValues) {
if (promoteUUIDs && subType === 4) {
value = new Binary(buffer.slice(index, index + binarySize), subType).toUUID();
} else if (promoteBuffers && promoteValues) {
value = buffer.slice(index, index + binarySize);
} else {
value = new Binary(buffer.slice(index, index + binarySize), subType);
Expand All @@ -440,7 +445,9 @@ function deserializeObject(
_buffer[i] = buffer[index + i];
}

if (promoteBuffers && promoteValues) {
if (promoteUUIDs && subType === 4) {
value = new Binary(_buffer, subType).toUUID();
} else if (promoteBuffers && promoteValues) {
value = _buffer;
nbbeeken marked this conversation as resolved.
Show resolved Hide resolved
} else {
value = new Binary(_buffer, subType);
Expand Down
61 changes: 61 additions & 0 deletions test/node/uuid_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,65 @@ describe('UUID', () => {
expect(plainUUIDSerialization).to.deep.equal(toBinarySerialization);
});
});

describe('deserialize', () => {
const originalUUID = new BSON.UUID();
const binaryUUID = originalUUID.toBinary();
const serializedUUID = BSON.serialize({ uuid: originalUUID.toBinary() });

it('should promoteUUIDs when flag is true', () => {
const { uuid: promotedUUID } = BSON.deserialize(serializedUUID, { promoteUUIDs: true });
expect(promotedUUID._bsontype).to.equal('UUID');
expect(promotedUUID).to.deep.equal(originalUUID);
});

it('should not promoteUUIDs when flag is false', () => {
const { uuid: unpromotedUUID } = BSON.deserialize(serializedUUID, { promoteUUIDs: false });
expect(unpromotedUUID._bsontype).to.equal('Binary');
expect(unpromotedUUID).to.deep.equal(binaryUUID);
});

it('should not promoteUUIDs when flag is omitted', () => {
const { uuid: omittedFlagUUID } = BSON.deserialize(serializedUUID);
expect(omittedFlagUUID._bsontype).to.equal('Binary');
expect(omittedFlagUUID).to.deep.equal(binaryUUID);
});

it('should throw BSONTypeError if _bsontype is not UUID and promoteUUIDs is true', () => {
const binaryVar = new Binary(Buffer.from('abc'), BSON_BINARY_SUBTYPE_UUID_NEW);
const serializedBinary = BSON.serialize({ d: binaryVar });
expect(() => {
BSON.deserialize(serializedBinary, { promoteUUIDs: true });
}).to.throw(BSONTypeError);
});
nbbeeken marked this conversation as resolved.
Show resolved Hide resolved

describe('promoteBuffers', () => {
const promoteUUIDValues = [true, false, undefined];
const promoteBufferValues = [true, false, undefined];

const testCases = promoteUUIDValues.flatMap(promoteUUIDs =>
promoteBufferValues.flatMap(promoteBuffers => ({
options: { promoteUUIDs, promoteBuffers },
// promoteBuffers: true returns a Buffer so _bsontype does not exist
outcome: promoteUUIDs ? 'UUID' : promoteBuffers ? undefined : 'Binary'
}))
);

for (const { options, outcome } of testCases) {
it(`should deserialize to ${outcome} type when promoteUUIDs is ${options.promoteUUIDs} and promoteBuffers is ${options.promoteBuffers}`, () => {
const { uuid } = BSON.deserialize(serializedUUID, options);
expect(uuid._bsontype).to.equal(outcome);
if (uuid._bsontype === 'UUID') {
expect(uuid.id).to.deep.equal(originalUUID.id);
} else if (uuid._bsontype === 'Binary') {
expect(uuid.buffer).to.deep.equal(originalUUID.id);
} else if (uuid._bsontype === undefined) {
expect(uuid).to.deep.equal(originalUUID.id);
} else {
expect.fail('Unexpected _bsontype');
}
});
}
});
});
});
1 change: 1 addition & 0 deletions test/register-bson.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
require('chai/register-expect');
require('array-includes/auto');
require('object.entries/auto');
require('array.prototype.flatmap/auto');

const BSON = require('../lib/bson');
const { ensureBuffer } = require('../lib/ensure_buffer');
Expand Down