UNPKG

@deepkit/bson

Version:
1,069 lines 50.8 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const globals_1 = require("@jest/globals"); require("reflect-metadata"); const bson_serialize_1 = require("../src/bson-serialize"); const type_1 = require("@deepkit/type"); const bson_1 = __importDefault(require("bson")); const bson_jit_parser_1 = require("../src/bson-jit-parser"); const crypto_1 = require("crypto"); const bson_parser_1 = require("../src/bson-parser"); const model_1 = require("../src/model"); const utils_1 = require("../src/utils"); const { Binary, calculateObjectSize, deserialize, Long, ObjectId: OfficialObjectId, serialize } = bson_1.default; globals_1.test('hexToByte', () => { globals_1.expect(bson_serialize_1.hexToByte('00')).toBe(0); globals_1.expect(bson_serialize_1.hexToByte('01')).toBe(1); globals_1.expect(bson_serialize_1.hexToByte('0f')).toBe(15); globals_1.expect(bson_serialize_1.hexToByte('10')).toBe(16); globals_1.expect(bson_serialize_1.hexToByte('ff')).toBe(255); globals_1.expect(bson_serialize_1.hexToByte('f0')).toBe(240); globals_1.expect(bson_serialize_1.hexToByte('50')).toBe(80); globals_1.expect(bson_serialize_1.hexToByte('7f')).toBe(127); globals_1.expect(bson_serialize_1.hexToByte('f00f', 1)).toBe(15); globals_1.expect(bson_serialize_1.hexToByte('f0ff', 1)).toBe(255); globals_1.expect(bson_serialize_1.hexToByte('f00001', 2)).toBe(1); globals_1.expect(bson_serialize_1.hexToByte('f8')).toBe(16 * 15 + 8); globals_1.expect(bson_serialize_1.hexToByte('41')).toBe(16 * 4 + 1); globals_1.expect(bson_serialize_1.uuidStringToByte('bef8de96-41fe-442f-b70c-c3a150f8c96c', 1)).toBe(16 * 15 + 8); globals_1.expect(bson_serialize_1.uuidStringToByte('bef8de96-41fe-442f-b70c-c3a150f8c96c', 4)).toBe(16 * 4 + 1); globals_1.expect(bson_serialize_1.uuidStringToByte('bef8de96-41fe-442f-b70c-c3a150f8c96c', 6)).toBe(16 * 4 + 4); globals_1.expect(bson_serialize_1.uuidStringToByte('bef8de96-41fe-442f-b70c-c3a150f8c96c', 7)).toBe(16 * 2 + 15); globals_1.expect(bson_serialize_1.uuidStringToByte('bef8de96-41fe-442f-b70c-c3a150f8c96c', 8)).toBe(16 * 11 + 7); globals_1.expect(bson_serialize_1.uuidStringToByte('bef8de96-41fe-442f-b70c-c3a150f8c96c', 10)).toBe(16 * 12 + 3); globals_1.expect(bson_serialize_1.uuidStringToByte('bef8de96-41fe-442f-b70c-c3a150f8c96c', 11)).toBe(16 * 10 + 1); globals_1.expect(bson_serialize_1.uuidStringToByte('bef8de96-41fe-442f-b70c-c3a150f8c96c', 15)).toBe(16 * 6 + 12); }); globals_1.test('basic string', () => { const object = { name: 'Peter' }; const expectedSize = 4 //size uint32 + 1 // type (string) + 'name\0'.length + (4 //string size uint32 + 'Peter'.length + 1 //string content + null ) + 1 //object null ; globals_1.expect(calculateObjectSize(object)).toBe(expectedSize); const schema = type_1.t.schema({ name: type_1.t.string, }); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(object).byteLength).toBe(expectedSize); globals_1.expect(bson_serialize_1.createBSONSizer(schema)(object)).toBe(expectedSize); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(object)).toEqual(serialize(object)); }); globals_1.test('basic number int', () => { const object = { position: 24 }; const expectedSize = 4 //size uint32 + 1 // type (number) + 'position\0'.length + (4 //int uint32 ) + 1 //object null ; globals_1.expect(calculateObjectSize(object)).toBe(expectedSize); const schema = type_1.t.schema({ position: type_1.t.number, }); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(object).byteLength).toBe(expectedSize); globals_1.expect(bson_serialize_1.createBSONSizer(schema)(object)).toBe(expectedSize); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(object)).toEqual(serialize(object)); }); globals_1.test('basic long', () => { const object = { position: 3364367088039355000n }; const expectedSize = 4 //size uint32 + 1 // type (number) + 'position\0'.length + (4 //uint32 low bits + 4 //uint32 high bits ) + 1 //object null ; const schema = type_1.t.schema({ position: type_1.t.number, }); const serializer = bson_serialize_1.getBSONSerializer(schema); const deserializer = bson_jit_parser_1.getBSONDecoder(schema); globals_1.expect(bson_serialize_1.createBSONSizer(schema)(object)).toBe(expectedSize); globals_1.expect(serializer(object).byteLength).toBe(expectedSize); const reParsed = bson_jit_parser_1.getBSONDecoder(schema)(serializer(object)); globals_1.expect(reParsed.position).toBe(3364367088039355000n); globals_1.expect(serializer({ position: 123456n })).toEqual(serialize({ position: Long.fromNumber(123456) })); globals_1.expect(serializer({ position: -123456n })).toEqual(serialize({ position: Long.fromNumber(-123456) })); globals_1.expect(serializer({ position: 3364367088039355000n })).toEqual(serialize({ position: Long.fromBigInt(3364367088039355000n) })); globals_1.expect(serializer({ position: -3364367088039355000n })).toEqual(serialize({ position: Long.fromBigInt(-3364367088039355000n) })); globals_1.expect(deserializer(serializer({ position: 3364367088039355000n }))).toEqual({ position: 3364367088039355000n }); globals_1.expect(deserializer(serializer({ position: -3364367088039355000n }))).toEqual({ position: -3364367088039355000n }); }); globals_1.test('basic bigint', () => { const object = { position: 3364367088039355000n }; const expectedSize = 4 //size uint32 + 1 // type (binary) + 'position\0'.length + (4 //binary size + 1 //binary type + 9 //binary content ) + 1 //object null ; const schema = type_1.t.schema({ position: type_1.t.bigint, }); const serializer = bson_serialize_1.getBSONSerializer(schema); const deserializer = bson_jit_parser_1.getBSONDecoder(schema); globals_1.expect(bson_serialize_1.createBSONSizer(schema)(object)).toBe(expectedSize); globals_1.expect(serializer(object).byteLength).toBe(expectedSize); const reParsed = deserializer(serializer(object)); globals_1.expect(reParsed.position).toBe(3364367088039355000n); //this cases are valid when dynamic bigint serialization is activated // expect(serializer({ position: 123456n })).toEqual(serialize({ position: 123456 })); // expect(serializer({ position: -123456n })).toEqual(serialize({ position: -123456 })); // expect(serializer({ position: 3364367088039355000n })).toEqual(serialize({ position: Long.fromBigInt(3364367088039355000n) })); // expect(serializer({ position: -3364367088039355000n })).toEqual(serialize({ position: Long.fromBigInt(-3364367088039355000n) })); // // expect(serializer({ position: 9223372036854775807n })).toEqual(serialize({ position: Long.fromBigInt(9223372036854775807n) })); // expect(serializer({ position: -9223372036854775807n })).toEqual(serialize({ position: Long.fromBigInt(-9223372036854775807n) })); globals_1.expect(deserializer(serializer({ position: 123456n }))).toEqual({ position: 123456n }); globals_1.expect(deserializer(serializer({ position: -123456n }))).toEqual({ position: -123456n }); globals_1.expect(deserializer(serializer({ position: 3364367088039355000n }))).toEqual({ position: 3364367088039355000n }); globals_1.expect(deserializer(serializer({ position: -3364367088039355000n }))).toEqual({ position: -3364367088039355000n }); globals_1.expect(deserializer(serializer({ position: 9223372036854775807n }))).toEqual({ position: 9223372036854775807n }); globals_1.expect(deserializer(serializer({ position: -9223372036854775807n }))).toEqual({ position: -9223372036854775807n }); { const bson = serializer({ position: 9223372036854775810n }); //force binary format globals_1.expect(bson).toEqual(Buffer.from([ 29, 0, 0, 0, 5 /* BINARY */, 112, 111, 115, 105, 116, 105, 111, 110, 0, 9, 0, 0, 0, utils_1.BSON_BINARY_SUBTYPE_BIGINT, 1, 128, 0, 0, 0, 0, 0, 0, 2, 0, //object null ])); } { const bson = serializer({ position: -9223372036854775810n }); //force binary format globals_1.expect(bson).toEqual(Buffer.from([ 29, 0, 0, 0, 5 /* BINARY */, 112, 111, 115, 105, 116, 105, 111, 110, 0, 9, 0, 0, 0, utils_1.BSON_BINARY_SUBTYPE_BIGINT, 255, 128, 0, 0, 0, 0, 0, 0, 2, 0, //object null ])); } }); globals_1.test('basic any bigint', () => { const object = { position: 3364367088039355000n }; const expectedSize = 4 //size uint32 + 1 // type (binary) + 'position\0'.length + (4 //binary size + 1 //binary type + 9 //binary content ) + 1 //object null ; const schema = type_1.t.schema({ position: type_1.t.any, }); const serializer = bson_serialize_1.getBSONSerializer(schema); const deserializer = bson_jit_parser_1.getBSONDecoder(schema); globals_1.expect(bson_serialize_1.createBSONSizer(schema)(object)).toBe(expectedSize); globals_1.expect(serializer(object).byteLength).toBe(expectedSize); const reParsed = bson_jit_parser_1.getBSONDecoder(schema)(serializer(object)); globals_1.expect(reParsed.position).toBe(3364367088039355000n); globals_1.expect(deserializer(serializer({ position: 123456n }))).toEqual({ position: 123456n }); globals_1.expect(deserializer(serializer({ position: -123456n }))).toEqual({ position: -123456n }); globals_1.expect(deserializer(serializer({ position: 3364367088039355000n }))).toEqual({ position: 3364367088039355000n }); globals_1.expect(deserializer(serializer({ position: -3364367088039355000n }))).toEqual({ position: -3364367088039355000n }); globals_1.expect(deserializer(serializer({ position: 9223372036854775807n }))).toEqual({ position: 9223372036854775807n }); globals_1.expect(deserializer(serializer({ position: -9223372036854775807n }))).toEqual({ position: -9223372036854775807n }); { const bson = serializer({ position: 9223372036854775810n }); //force binary format globals_1.expect(bson).toEqual(Buffer.from([ 29, 0, 0, 0, 5 /* BINARY */, 112, 111, 115, 105, 116, 105, 111, 110, 0, 9, 0, 0, 0, utils_1.BSON_BINARY_SUBTYPE_BIGINT, 1, 128, 0, 0, 0, 0, 0, 0, 2, 0, //object null ])); } { const bson = serializer({ position: -9223372036854775810n }); //force binary format globals_1.expect(bson).toEqual(Buffer.from([ 29, 0, 0, 0, 5 /* BINARY */, 112, 111, 115, 105, 116, 105, 111, 110, 0, 9, 0, 0, 0, utils_1.BSON_BINARY_SUBTYPE_BIGINT, 255, 128, 0, 0, 0, 0, 0, 0, 2, 0, //object null ])); } }); globals_1.test('basic long bigint', () => { const bla = [ { n: 1, m: '1' }, { n: 1 << 16, m: 'max uint 16' }, { n: (1 << 16) + 100, m: 'max uint 16 + 100' }, { n: 4294967296, m: 'max uint 32' }, { n: 4294967296 - 100, m: 'max uint 32 - 100' }, { n: 4294967296 - 1, m: 'max uint 32 - 1' }, { n: 4294967296 + 100, m: 'max uint 32 + 100' }, { n: 4294967296 + 1, m: 'max uint 32 + 1' }, { n: 4294967296 * 10 + 1, m: 'max uint 32 * 10 + 1' }, // {n: 9223372036854775807, m: 'max uint64'}, // {n: 9223372036854775807 + 1, m: 'max uint64 - 1'}, // {n: 9223372036854775807 - 1, m: 'max uint64 + 2'}, ]; for (const b of bla) { const long = Long.fromNumber(b.n); console.log(b.n, long.toNumber(), long, b.m); } }); globals_1.test('basic number double', () => { const object = { position: 149943944399 }; const expectedSize = 4 //size uint32 + 1 // type (number) + 'position\0'.length + (8 //double, 64bit ) + 1 //object null ; const expectedSizeNull = 4 //size uint32 + 1 // type (number) + 'position\0'.length + (0 //undefined ) + 1 //object null ; globals_1.expect(calculateObjectSize(object)).toBe(expectedSize); globals_1.expect(calculateObjectSize({ position: null })).toBe(expectedSizeNull); globals_1.expect(calculateObjectSize({ position: undefined })).toBe(5); const schema = type_1.t.schema({ position: type_1.t.number, }); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(object).byteLength).toBe(expectedSize); globals_1.expect(bson_serialize_1.createBSONSizer(schema)(object)).toBe(expectedSize); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(object)).toEqual(serialize(object)); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)({ position: null }).byteLength).toBe(expectedSizeNull); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)({ position: undefined }).byteLength).toBe(expectedSizeNull); //explicitely annotataed undefined is included globals_1.expect(bson_serialize_1.getBSONSerializer(schema)({}).byteLength).toBe(5); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)({ position: null }).byteLength).toEqual(expectedSizeNull); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)({ position: undefined }).byteLength).toEqual(expectedSizeNull); //explicitely annotataed undefined is included globals_1.expect(bson_serialize_1.getBSONSerializer(schema)({}).byteLength).toEqual(5); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)({ position: null })).toEqual(serialize({ position: null })); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)({})).toEqual(serialize({})); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)({})).toEqual(serialize({ position: undefined })); //official bson drops undefined values }); globals_1.test('basic boolean', () => { const object = { valid: true }; const expectedSize = 4 //size uint32 + 1 // type (boolean) + 'valid\0'.length + (1 //boolean ) + 1 //object null ; globals_1.expect(calculateObjectSize(object)).toBe(expectedSize); const schema = type_1.t.schema({ valid: type_1.t.boolean, }); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(object).byteLength).toBe(expectedSize); globals_1.expect(bson_serialize_1.createBSONSizer(schema)(object)).toBe(expectedSize); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(object)).toEqual(serialize(object)); }); globals_1.test('basic date', () => { const object = { created: new Date }; const expectedSize = 4 //size uint32 + 1 // type (date) + 'created\0'.length + (8 //date ) + 1 //object null ; globals_1.expect(calculateObjectSize(object)).toBe(expectedSize); const schema = type_1.t.schema({ created: type_1.t.date, }); const serializer = bson_serialize_1.getBSONSerializer(schema); const deserializer = bson_jit_parser_1.getBSONDecoder(schema); // expect(serializer(object).byteLength).toBe(expectedSize); // expect(createBSONSizer(schema)(object)).toBe(expectedSize); // expect(serializer(object)).toEqual(serialize(object)); globals_1.expect(serializer({ created: new Date('2900-10-12T00:00:00.000Z') })).toEqual(serialize({ created: new Date('2900-10-12T00:00:00.000Z') })); globals_1.expect(serializer({ created: new Date('1900-10-12T00:00:00.000Z') })).toEqual(serialize({ created: new Date('1900-10-12T00:00:00.000Z') })); globals_1.expect(serializer({ created: new Date('1000-10-12T00:00:00.000Z') })).toEqual(serialize({ created: new Date('1000-10-12T00:00:00.000Z') })); globals_1.expect(deserializer(serializer({ created: new Date('2900-10-12T00:00:00.000Z') }))).toEqual({ created: new Date('2900-10-12T00:00:00.000Z') }); globals_1.expect(deserializer(serializer({ created: new Date('1900-10-12T00:00:00.000Z') }))).toEqual({ created: new Date('1900-10-12T00:00:00.000Z') }); globals_1.expect(deserializer(serializer({ created: new Date('1000-10-12T00:00:00.000Z') }))).toEqual({ created: new Date('1000-10-12T00:00:00.000Z') }); }); globals_1.test('basic binary', () => { const object = { binary: new Uint16Array(32) }; const expectedSize = 4 //size uint32 + 1 // type (date) + 'binary\0'.length + (4 //size of binary, uin32 + 1 //sub type + 32 * 2 //size of data ) + 1 //object null ; globals_1.expect(new Uint16Array(32).byteLength).toBe(32 * 2); //this doesn't support typed arrays // expect(calculateObjectSize(object)).toBe(expectedSize); const schema = type_1.t.schema({ binary: type_1.t.type(Uint16Array), }); globals_1.expect(schema.getProperty('binary').type).toBe('Uint16Array'); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(object).byteLength).toBe(expectedSize); globals_1.expect(bson_serialize_1.createBSONSizer(schema)(object)).toBe(expectedSize); //doesnt support typed arrays // expect(getBSONSerializer(schema)(object)).toEqual(serialize(object)); globals_1.expect(bson_jit_parser_1.getBSONDecoder(schema)(bson_serialize_1.getBSONSerializer(schema)(object))).toEqual(object); }); globals_1.test('basic arrayBuffer', () => { const arrayBuffer = new ArrayBuffer(5); const view = new Uint8Array(arrayBuffer); view[0] = 22; view[1] = 44; view[2] = 55; view[3] = 66; view[4] = 77; const object = { binary: arrayBuffer }; const expectedSize = 4 //size uint32 + 1 // type (date) + 'binary\0'.length + (4 //size of binary, uin32 + 1 //sub type + 5 //size of data ) + 1 //object null ; // expect(calculateObjectSize(object)).toBe(expectedSize); const schema = type_1.t.schema({ binary: type_1.t.type(ArrayBuffer), }); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(object).byteLength).toBe(expectedSize); globals_1.expect(bson_serialize_1.createBSONSizer(schema)(object)).toBe(expectedSize); globals_1.expect(bson_jit_parser_1.getBSONDecoder(schema)(bson_serialize_1.getBSONSerializer(schema)(object))).toEqual(object); // expect(getBSONSerializer(schema)(object)).toEqual(serialize(object)); }); globals_1.test('basic Buffer', () => { const object = { binary: new Uint8Array(32) }; const expectedSize = 4 //size uint32 + 1 // type (date) + 'binary\0'.length + (4 //size of binary, uin32 + 1 //sub type + 32 //size of data ) + 1 //object null ; // expect(calculateObjectSize(object)).toBe(expectedSize); const schema = type_1.t.schema({ binary: type_1.t.type(Uint8Array), }); globals_1.expect(schema.getProperty('binary').type).toBe('Uint8Array'); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(object).byteLength).toBe(expectedSize); globals_1.expect(bson_serialize_1.createBSONSizer(schema)(object)).toBe(expectedSize); globals_1.expect(bson_jit_parser_1.getBSONDecoder(schema)(bson_serialize_1.getBSONSerializer(schema)(object))).toEqual(object); Buffer.alloc(2); Buffer.alloc(200); Buffer.alloc(20000); globals_1.expect(bson_jit_parser_1.getBSONDecoder(schema)(bson_serialize_1.getBSONSerializer(schema)({ binary: Buffer.alloc(44) }))).toEqual({ binary: new Uint8Array(44) }); }); globals_1.test('basic uuid', () => { const uuidRandomBinary = new Binary(Buffer.allocUnsafe(16), Binary.SUBTYPE_UUID); const object = { uuid: '75ed2328-89f2-4b89-9c49-1498891d616d' }; const expectedSize = 4 //size uint32 + 1 // type (date) + 'uuid\0'.length + (4 //size of binary + 1 //sub type + 16 //content of uuid ) + 1 //object null ; globals_1.expect(calculateObjectSize({ uuid: uuidRandomBinary })).toBe(expectedSize); const schema = type_1.t.schema({ uuid: type_1.t.uuid, }); globals_1.expect(bson_serialize_1.getBSONSizer(schema)(object)).toBe(expectedSize); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(object).byteLength).toBe(expectedSize); const uuidPlain = Buffer.from([0x75, 0xed, 0x23, 0x28, 0x89, 0xf2, 0x4b, 0x89, 0x9c, 0x49, 0x14, 0x98, 0x89, 0x1d, 0x61, 0x6d]); const uuidBinary = new Binary(uuidPlain, 4); const objectBinary = { uuid: uuidBinary }; globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(object).byteLength).toBe(expectedSize); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(object)).toEqual(serialize(objectBinary)); const bson = serialize(objectBinary); const parsed = bson_parser_1.parseObject(new bson_parser_1.ParserV2(bson)); globals_1.expect(parsed.uuid).toBe('75ed2328-89f2-4b89-9c49-1498891d616d'); }); globals_1.test('basic objectId', () => { const object = { _id: '507f191e810c19729de860ea' }; const expectedSize = 4 //size uint32 + 1 // type + '_id\0'.length + (12 //size of objectId ) + 1 //object null ; const nativeBson = { _id: new OfficialObjectId('507f191e810c19729de860ea') }; globals_1.expect(calculateObjectSize(nativeBson)).toBe(expectedSize); const schema = type_1.t.schema({ _id: type_1.t.mongoId, }); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(object).byteLength).toBe(expectedSize); globals_1.expect(bson_serialize_1.createBSONSizer(schema)(object)).toBe(expectedSize); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(object)).toEqual(serialize(nativeBson)); }); globals_1.test('basic nested', () => { const object = { name: { anotherOne: 'Peter2' } }; const expectedSize = 4 //size uint32 + 1 //type (object) + 'name\0'.length + (4 //size uint32 + 1 //type (object) + 'anotherOne\0'.length + (4 //string size uint32 + 'Peter2'.length + 1 //string content + null ) + 1 //object null ) + 1 //object null ; globals_1.expect(calculateObjectSize(object)).toBe(expectedSize); const schema = type_1.t.schema({ name: { anotherOne: type_1.t.string, }, }); globals_1.expect(bson_serialize_1.createBSONSizer(schema)(object)).toBe(expectedSize); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(object)).toEqual(serialize(object)); }); globals_1.test('basic map', () => { const object = { name: { anotherOne: 'Peter2' } }; const expectedSize = 4 //size uint32 + 1 //type (object) + 'name\0'.length + (4 //size uint32 + 1 //type (object) + 'anotherOne\0'.length + (4 //string size uint32 + 'Peter2'.length + 1 //string content + null ) + 1 //object null ) + 1 //object null ; globals_1.expect(calculateObjectSize(object)).toBe(expectedSize); const schema = type_1.t.schema({ name: type_1.t.map(type_1.t.string) }); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(object).byteLength).toBe(expectedSize); globals_1.expect(bson_serialize_1.createBSONSizer(schema)(object)).toBe(expectedSize); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(object)).toEqual(serialize(object)); }); globals_1.test('basic array', () => { const object = { name: ['Peter3'] }; const expectedSize = 4 //size uint32 + 1 //type (array) + 'name\0'.length + (4 //size uint32 of array + 1 //type (string) + '0\0'.length //key + (4 //string size uint32 + 'Peter3'.length + 1 //string content + null ) + 1 //object null ) + 1 //object null ; globals_1.expect(calculateObjectSize(object)).toBe(expectedSize); const schema = type_1.t.schema({ name: type_1.t.array(type_1.t.string), }); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(object).byteLength).toBe(expectedSize); globals_1.expect(bson_serialize_1.createBSONSizer(schema)(object)).toBe(expectedSize); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(object)).toEqual(serialize(object)); }); globals_1.test('number', () => { const object = { name: 'Peter4', tags: ['a', 'b', 'c'], priority: 15, position: 149943944399, valid: true, created: new Date() }; const schema = type_1.t.schema({ name: type_1.t.string, tags: type_1.t.array(type_1.t.string), priority: type_1.t.number, position: type_1.t.number, valid: type_1.t.boolean, created: type_1.t.date, }); globals_1.expect(bson_serialize_1.createBSONSizer(schema)(object)).toBe(calculateObjectSize(object)); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(object)).toEqual(serialize(object)); }); globals_1.test('all supported types', () => { const object = { name: 'Peter4', tags: ['a', 'b', 'c'], priority: 15, position: 149943944399, valid: true, created: new Date() }; const schema = type_1.t.schema({ name: type_1.t.string, tags: type_1.t.array(type_1.t.string), priority: type_1.t.number, position: type_1.t.number, valid: type_1.t.boolean, created: type_1.t.date, }); globals_1.expect(bson_serialize_1.createBSONSizer(schema)(object)).toBe(calculateObjectSize(object)); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(object)).toEqual(serialize(object)); }); globals_1.test('string utf8', () => { const schema = type_1.t.schema({ name: type_1.t.string, any: type_1.t.any, }); const serialize = bson_serialize_1.getBSONSerializer(schema); const parse = bson_jit_parser_1.getBSONDecoder(schema); globals_1.expect(parse(serialize({ name: 'Peter' }))).toEqual({ name: 'Peter' }); globals_1.expect(parse(serialize({ name: 'Peter✌️' }))).toEqual({ name: 'Peter✌️' }); globals_1.expect(parse(serialize({ name: '✌️' }))).toEqual({ name: '✌️' }); globals_1.expect(parse(serialize({ name: '🌉' }))).toEqual({ name: '🌉' }); globals_1.expect(parse(serialize({ name: 'πøˆ️' }))).toEqual({ name: 'πøˆ️' }); globals_1.expect(parse(serialize({ name: 'Ѓ' }))).toEqual({ name: 'Ѓ' }); globals_1.expect(parse(serialize({ name: '㒨' }))).toEqual({ name: '㒨' }); globals_1.expect(parse(serialize({ name: '﨣' }))).toEqual({ name: '﨣' }); globals_1.expect(parse(serialize({ any: { base: true } }))).toEqual({ any: { base: true } }); globals_1.expect(parse(serialize({ any: { '✌️': true } }))).toEqual({ any: { '✌️': true } }); globals_1.expect(parse(serialize({ any: { 'Ѓ': true } }))).toEqual({ any: { 'Ѓ': true } }); globals_1.expect(parse(serialize({ any: { 㒨: true } }))).toEqual({ any: { 㒨: true } }); globals_1.expect(parse(serialize({ any: { 﨣: true } }))).toEqual({ any: { 﨣: true } }); }); globals_1.test('optional field', () => { const findSchema = type_1.t.schema({ find: type_1.t.string, batchSize: type_1.t.number, limit: type_1.t.number.optional, skip: type_1.t.number.optional, }); const findSerializer = bson_serialize_1.getBSONSerializer(findSchema); const bson = findSerializer({ find: 'user', batchSize: 1, limit: 1, }); const bsonOfficial = serialize({ find: 'user', batchSize: 1, limit: 1, }); globals_1.expect(bson).toEqual(bsonOfficial); }); globals_1.test('complex', () => { const findSchema = type_1.t.schema({ find: type_1.t.string, batchSize: type_1.t.number, limit: type_1.t.number.optional, filter: type_1.t.any, projection: type_1.t.any, sort: type_1.t.any, skip: type_1.t.number.optional, }); const findSerializer = bson_serialize_1.getBSONSerializer(findSchema); const bson = findSerializer({ find: 'user', batchSize: 1, limit: 1, }); const bsonOfficial = serialize({ find: 'user', batchSize: 1, limit: 1, }); globals_1.expect(bson).toEqual(bsonOfficial); }); globals_1.test('any objectId', () => { const schema = type_1.t.schema({ _id: type_1.t.any, q: type_1.t.any, }); { const doc = { _id: new model_1.ObjectId('507f191e810c19729de860ea') }; const officialDoc = { _id: new OfficialObjectId('507f191e810c19729de860ea') }; const bson = bson_serialize_1.getBSONSerializer(schema)(doc); const bsonOfficial = serialize(officialDoc); globals_1.expect(bson).toEqual(bsonOfficial); const parsed = deserialize(Buffer.from(bson)); globals_1.expect(parsed._id).toBeInstanceOf(OfficialObjectId); globals_1.expect(parsed._id.toHexString()).toBe('507f191e810c19729de860ea'); const parsed2 = bson_jit_parser_1.getBSONDecoder(schema)(bson); globals_1.expect(parsed2._id).toBe('507f191e810c19729de860ea'); } { const doc = { q: { id: new model_1.ObjectId('507f191e810c19729de860ea') } }; const officialDoc = { q: { id: new OfficialObjectId('507f191e810c19729de860ea') } }; const bson = bson_serialize_1.getBSONSerializer(schema)(doc); const bsonOfficial = serialize(officialDoc); globals_1.expect(bson).toEqual(bsonOfficial); const parsed = deserialize(Buffer.from(bson)); globals_1.expect(parsed.q.id).toBeInstanceOf(OfficialObjectId); globals_1.expect(parsed.q.id.toHexString()).toBe('507f191e810c19729de860ea'); const parsed2 = bson_jit_parser_1.getBSONDecoder(schema)(bson); globals_1.expect(parsed2.q.id).toBe('507f191e810c19729de860ea'); } }); globals_1.test('objectId string', () => { const schema = type_1.t.schema({ id: type_1.t.mongoId, }); { const doc = { id: '507f191e810c19729de860ea' }; const bson = bson_serialize_1.getBSONSerializer(schema)(doc); const bsonOfficial = serialize({ id: new OfficialObjectId('507f191e810c19729de860ea') }); globals_1.expect(bson).toEqual(bsonOfficial); const parsed = deserialize(Buffer.from(bson)); globals_1.expect(parsed.id).toBeInstanceOf(OfficialObjectId); globals_1.expect(parsed.id.toHexString()).toBe('507f191e810c19729de860ea'); const parsed2 = bson_jit_parser_1.getBSONDecoder(schema)(bson); globals_1.expect(parsed2.id).toBe('507f191e810c19729de860ea'); } }); globals_1.test('model 1, missing `public`', () => { let User = class User { constructor(id, name) { this.name = name; this.tags = []; this.priority = 0; } }; __decorate([ type_1.f, __metadata("design:type", Boolean) ], User.prototype, "ready", void 0); __decorate([ type_1.f.array(type_1.f.string), __metadata("design:type", Array) ], User.prototype, "tags", void 0); __decorate([ type_1.f, __metadata("design:type", Number) ], User.prototype, "priority", void 0); User = __decorate([ __param(0, type_1.f.primary), __param(1, type_1.f), __metadata("design:paramtypes", [Number, String]) ], User); const schema = type_1.getClassSchema(User); globals_1.expect(schema.getMethodProperties('constructor').length).toBe(2); globals_1.expect(schema.getPropertiesMap().size).toBe(5); { const user = new User(1, 'Peter ' + 1); user.ready = true; user.priority = 5; user.tags = ['a', 'b', 'c']; const bson = bson_serialize_1.getBSONSerializer(User)(user); const size = bson_serialize_1.getBSONSizer(User)(user); globals_1.expect(size).toBe(calculateObjectSize(user)); const s = bson_jit_parser_1.getBSONDecoder(User); const o = s(bson); globals_1.expect(o).toEqual(deserialize(Buffer.from(bson))); } { const user = { ready: true, priority: 5, tags: ['a', 'b', 'c'], id: null, name: 'Peter 1', }; const bson = bson_serialize_1.getBSONSerializer(User)(user); const s = bson_jit_parser_1.getBSONDecoder(User); const o = s(bson); globals_1.expect(o).not.toEqual(deserialize(Buffer.from(bson))); //because bson-js includes `id`, but we drop it since it's not assigned in the constructor } }); globals_1.test('decorated', () => { let DecoratedValue = class DecoratedValue { constructor(items = []) { this.items = items; } }; DecoratedValue = __decorate([ __param(0, type_1.t.array(type_1.t.string).decorated), __metadata("design:paramtypes", [Array]) ], DecoratedValue); const object = { v: new DecoratedValue(['Peter3']) }; const expectedSize = 4 //size uint32 + 1 //type (array) + 'v\0'.length + (4 //size uint32 of array + 1 //type (string) + '0\0'.length //key + (4 //string size uint32 + 'Peter3'.length + 1 //string content + null ) + 1 //object null ) + 1 //object null ; globals_1.expect(calculateObjectSize({ v: ['Peter3'] })).toBe(expectedSize); const schema = type_1.t.schema({ v: type_1.t.type(DecoratedValue), }); const bson = bson_serialize_1.getBSONSerializer(schema)(object); const officialDeserialize = deserialize(Buffer.from(bson)); console.log('officialDeserialize', officialDeserialize); globals_1.expect(officialDeserialize.v).toEqual(['Peter3']); globals_1.expect(bson.byteLength).toBe(expectedSize); globals_1.expect(bson_serialize_1.createBSONSizer(schema)(object)).toBe(expectedSize); globals_1.expect(bson).toEqual(serialize({ v: ['Peter3'] })); const back = bson_jit_parser_1.getBSONDecoder(schema)(bson); globals_1.expect(back.v).toBeInstanceOf(DecoratedValue); globals_1.expect(back.v.items).toEqual(['Peter3']); globals_1.expect(back).toEqual(object); }); globals_1.test('reference', () => { class User { constructor() { this.id = 1; this.managedUsers = []; } } __decorate([ type_1.t.primary, __metadata("design:type", Number) ], User.prototype, "id", void 0); __decorate([ type_1.t.array(User).backReference(), __metadata("design:type", Array) ], User.prototype, "managedUsers", void 0); __decorate([ type_1.t, __metadata("design:type", String) ], User.prototype, "name", void 0); __decorate([ type_1.t.optional.reference(), __metadata("design:type", User) ], User.prototype, "manager", void 0); { const object = new User(); object.name = 'Peter'; object.manager = null; const bson = bson_serialize_1.getBSONSerializer(User)(object); const json = deserialize(bson); globals_1.expect('manager' in json).toBe(true); //needs to be maintained in BSON since manager is optional. Only way to reset it. globals_1.expect(json.manager).toBe(null); //needs to be maintained in BSON since manager is optional. Only way to reset it. const trip = bson_jit_parser_1.getBSONDecoder(User)(bson); globals_1.expect(trip.manager).toBe(undefined); globals_1.expect('manager' in trip).toBe(false); //not part of the object since undefined/null } const updateSchema = type_1.t.schema({ update: type_1.t.string, $db: type_1.t.string, updates: type_1.t.array({ q: type_1.t.any, u: type_1.t.any, multi: type_1.t.boolean, }) }); { const object = { update: 'Nix', $db: 'admin', updates: [{ q: { id: 213 }, u: { manager: null } }] }; globals_1.expect(bson_serialize_1.getBSONSizer(updateSchema)(object)).toBe(calculateObjectSize(object)); const bson = bson_serialize_1.getBSONSerializer(updateSchema)(object); globals_1.expect(bson_jit_parser_1.getBSONDecoder(updateSchema)(bson)).toEqual(deserialize(Buffer.from(bson))); } }); globals_1.test('bson length', () => { const nonce = crypto_1.randomBytes(24); class SaslStartCommand extends type_1.t.class({ saslStart: type_1.t.literal(1), $db: type_1.t.string, mechanism: type_1.t.string, payload: type_1.t.type(Uint8Array), autoAuthorize: type_1.t.literal(1), options: { skipEmptyExchange: type_1.t.literal(true) } }) { } const message = { saslStart: 1, '$db': 'admin', mechanism: 'SCRAM-SHA-1', payload: Buffer.concat([Buffer.from('n,,', 'utf8'), Buffer.from(`n=Peter,r=${nonce.toString('base64')}`, 'utf8')]), autoAuthorize: 1, options: { skipEmptyExchange: true } }; globals_1.expect(message.payload.byteLength).toBe(13 + nonce.toString('base64').length); const size = bson_serialize_1.getBSONSizer(SaslStartCommand)(message); globals_1.expect(size).toBe(calculateObjectSize(message)); const bson = bson_serialize_1.getBSONSerializer(SaslStartCommand)(message); globals_1.expect(bson).toEqual(serialize(message)); }); globals_1.test('arrayBuffer', () => { const schema = type_1.t.schema({ name: type_1.t.string, secondId: type_1.t.mongoId, preview: type_1.t.type(ArrayBuffer), }); const message = type_1.jsonSerializer.for(schema).deserialize({ name: 'myName', secondId: '5bf4a1ccce060e0b38864c9e', preview: type_1.nodeBufferToArrayBuffer(Buffer.from('Baar', 'utf8')) }); globals_1.expect(Buffer.from(message.preview).toString('utf8')).toBe('Baar'); const mongoMessage = { name: message.name, secondId: new OfficialObjectId(message.secondId), preview: new Binary(Buffer.from(message.preview)), }; const size = bson_serialize_1.getBSONSizer(schema)(message); globals_1.expect(size).toBe(calculateObjectSize(mongoMessage)); const bson = bson_serialize_1.getBSONSerializer(schema)(message); globals_1.expect(bson).toEqual(serialize(mongoMessage)); const back = bson_jit_parser_1.getBSONDecoder(schema)(bson); globals_1.expect(Buffer.from(back.preview).toString('utf8')).toBe('Baar'); globals_1.expect(back.preview).toEqual(message.preview); }); globals_1.test('typed array', () => { const schema = type_1.t.schema({ name: type_1.t.string, secondId: type_1.t.mongoId, preview: type_1.t.type(Uint16Array), }); const message = type_1.jsonSerializer.for(schema).deserialize({ name: 'myName', secondId: '5bf4a1ccce060e0b38864c9e', preview: new Uint16Array(type_1.nodeBufferToArrayBuffer(Buffer.from('LAA3AEIATQBYAA==', 'base64'))), //44, 55, 66, 77, 88 }); globals_1.expect(message.preview).toBeInstanceOf(Uint16Array); globals_1.expect(message.preview.byteLength).toBe(10); const mongoMessage = { name: message.name, secondId: new OfficialObjectId(message.secondId), preview: new Binary(Buffer.from(new Uint8Array(message.preview.buffer, message.preview.byteOffset, message.preview.byteLength))), }; const size = bson_serialize_1.getBSONSizer(schema)(message); globals_1.expect(size).toBe(calculateObjectSize(mongoMessage)); const bson = bson_serialize_1.getBSONSerializer(schema)(message); globals_1.expect(bson).toEqual(serialize(mongoMessage)); const back = bson_jit_parser_1.getBSONDecoder(schema)(bson); globals_1.expect(back.preview).toEqual(message.preview); }); globals_1.test('typed any and undefined', () => { const schema = type_1.t.schema({ data: type_1.t.any, }); const message = type_1.jsonSerializer.for(schema).deserialize({ data: { $set: {}, $inc: undefined, }, }); // expect(getValueSize({ $inc: undefined })).toBe(calculateObjectSize({ $inc: undefined })); //official BSON does not include undefined values, but we do globals_1.expect(bson_serialize_1.getValueSize({ $inc: [undefined] })).toBe(calculateObjectSize({ $inc: [undefined] })); // const size = getBSONSizer(schema)(message); // expect(size).toBe(calculateObjectSize(message)); //official bson doesnt include undefined const bson = bson_serialize_1.getBSONSerializer(schema)(message); // expect(bson).toEqual(serialize(message)); //official bson doesnt include undefined const back = bson_jit_parser_1.getBSONDecoder(schema)(bson); globals_1.expect(back.data.$set).toEqual({}); globals_1.expect(back.data.$inc).toEqual(undefined); globals_1.expect('$inc' in back.data).toEqual(true); }); globals_1.test('test map map', () => { const schema = type_1.t.schema({ data: type_1.t.map(type_1.t.map(type_1.t.string)), }); const message = type_1.jsonSerializer.for(schema).deserialize({ data: { foo: { bar: 'abc' } }, }); const size = bson_serialize_1.getBSONSizer(schema)(message); globals_1.expect(size).toBe(calculateObjectSize(message)); const bson = bson_serialize_1.getBSONSerializer(schema)(message); globals_1.expect(bson).toEqual(serialize(message)); globals_1.expect(bson_jit_parser_1.getBSONDecoder(schema)(bson)).toEqual(message); }); globals_1.test('test array array', () => { const schema = type_1.t.schema({ data: type_1.t.array(type_1.t.array(type_1.t.string)), }); const message = type_1.jsonSerializer.for(schema).deserialize({ data: [['abc']], }); const size = bson_serialize_1.getBSONSizer(schema)(message); globals_1.expect(size).toBe(calculateObjectSize(message)); const bson = bson_serialize_1.getBSONSerializer(schema)(message); globals_1.expect(bson).toEqual(serialize(message)); globals_1.expect(bson_jit_parser_1.getBSONDecoder(schema)(bson)).toEqual(message); }); globals_1.test('test array optional', () => { const schema = type_1.t.schema({ data: type_1.t.array(type_1.t.date.optional), }); { const message = { data: [new Date, undefined] }; const size = bson_serialize_1.getBSONSizer(schema)(message); globals_1.expect(size).toBe(calculateObjectSize(message)); } }); globals_1.test('test map optional 1', () => { const schema = type_1.t.schema({ data: type_1.t.map(type_1.t.date.optional), }); { const message = { data: { first: new Date, second: undefined } }; // const size = getBSONSizer(schema)(message); //we maintain undefined as null, in contrary to BSON official // expect(size).toBe(calculateObjectSize(message)); globals_1.expect(bson_jit_parser_1.getBSONDecoder(schema)(bson_serialize_1.getBSONSerializer(schema)(message))).toEqual(message); // expect(getBSONSerializer(schema)(message)).toEqual(serialize(message)); } }); globals_1.test('test map optional 2', () => { const schema = type_1.t.schema({ data: type_1.t.map(type_1.t.date.optional), }); { const message = { data: { first: new Date, second: undefined } }; // const size = getBSONSizer(schema)(message); //we maintain undefined as null, in contrary to BSON official // expect(size).toBe(calculateObjectSize(message)); globals_1.expect(bson_jit_parser_1.getBSONDecoder(schema)(bson_serialize_1.getBSONSerializer(schema)(message))).toEqual(message); // expect(getBSONSerializer(schema)(message)).toEqual(serialize(message)); } }); globals_1.test('test union optional', () => { const schema = type_1.t.schema({ data: type_1.t.union('foo', 'bar').optional }); { const message = { data: 'foo' }; const size = bson_serialize_1.getBSONSizer(schema)(message); globals_1.expect(size).toBe(calculateObjectSize(message)); const serializer = bson_serialize_1.getBSONSerializer(schema); const bson = serializer(message); globals_1.expect(bson).toEqual(serialize(message)); globals_1.expect(bson_jit_parser_1.getBSONDecoder(schema)(bson_serialize_1.getBSONSerializer(schema)(message))).toEqual(message); } { const message = { data: undefined }; // const size = getBSONSizer(schema)(message); // expect(size).toBe(calculateObjectSize(message)); //official bson does not include undefined, but we do const trip = bson_jit_parser_1.getBSONDecoder(schema)(bson_serialize_1.getBSONSerializer(schema)(message)); globals_1.expect('data' in trip).toBe(true); globals_1.expect(trip.data).toEqual(undefined); // expect(getBSONSerializer(schema)(message)).toEqual(serialize(message)); } { const message = { data: 'bar' }; const size = bson_serialize_1.getBSONSizer(schema)(message); globals_1.expect(size).toBe(calculateObjectSize(message)); globals_1.expect(bson_jit_parser_1.getBSONDecoder(schema)(bson_serialize_1.getBSONSerializer(schema)(message))).toEqual(message); globals_1.expect(bson_serialize_1.getBSONSerializer(schema)(message)).toEqual(serialize(message)); } }); globals_1.test('test object', () => { let MyModel = class MyModel { constructor(name) { this.name = name; this.excluded = true; this.type = ''; } }; __decorate([ type_1.t, __metadata("design:type", String) ], MyModel.prototype, "type", void 0); MyModel = __decorate([ __param(0, type_1.t), __metadata("design:paramtypes", [String]) ], MyModel); const schema = type_1.t.schema({ data: type_1.t.type(MyModel), }); { const item = new MyModel('bar'); item.type = 'foo'; const message = { data: item }; globals_1.expect(bson_serialize_1.getBSONSizer(schema)(message)).not.toBe(calculateObjectSize(message)); //should bee different, since we do not include `excluded`, but official bson does const bson = bson_serialize_1.getBSONSerializer(schema)(message); const backOfficial = deserialize(Buffer.from(bson)); globals_1.expect(backOfficial.data.excluded).toBe(undefined); //`excluded` should not be part of the BSON globals_1.expect(bson).not.toEqual(serialize(message)); //should not be equal, since MyModel does not serialize `excluded` const back = bson_jit_parser_1.getBSONDecoder(schema)(bson); globals_1.expect(back.data).toBeInstanceOf(MyModel); globals_1.expect(back.data.name).toBe('bar'); globals_1.expect(back.data.type).toBe('foo'); globals_1.expect(back).toEqual(message); } }); globals_1.test('test union deep object', () => { let MyModel = class MyModel { constructor(name) { this.name = name; this.excluded = true; this.d = 'model'; this.type = ''; } }; __decorate([ type_1.t.literal('model'), __metadata("design:type", String) ], MyModel.prototype, "d", void 0); __decorate([ type_1.t, __metadata("design:type", String) ], MyModel.prototype, "type", void 0); MyModel = __decorate([ __param(0, type_1.t), __metadata("design:paramtypes", [String]) ], MyModel); const schema = type_1.t.schema({ data: type_1.t.union(type_1.t.string, MyModel), }); { const message = { data: 'peter' }; globals_1.expect(bson_serialize_1.getBSONSizer(schema)(message)).toBe(calculateObjectSize(message)); const bson = bson_serialize_1.getBSONSerializer(schema)(message); globals_1.expect(bson).toEqual(serialize(message)); globals_1.expect(bson_jit_parser_1.getBSONDecoder(schema)(bson)).toEqual(message); } { const item = new MyModel('bar'); item.type = 'foo'; const message = { data: item }; globals_1.expect(bson_serialize_1.getBSONSizer(schema)(message)).not.toBe(calculateObjectSize(message)); //should bee different, since we do not include `excluded`, but official bson does const bson