From 1f0cbb4d0f4800c31fb2583ee9b6b43131a78995 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Fri, 2 Jul 2021 13:02:58 +0200 Subject: [PATCH] fix(shell-api): relax BSON type validation MONGOSH-865 Since for the types that the BSON library itself provides, the only benefit of our wrappers is the extra type validation, we should ensure that it is accurate. --- packages/shell-api/src/shell-bson.spec.ts | 24 +++++++++++++++++++---- packages/shell-api/src/shell-bson.ts | 22 ++++++++++----------- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/packages/shell-api/src/shell-bson.spec.ts b/packages/shell-api/src/shell-bson.spec.ts index 4aec3c4190..ac6ee8c27d 100644 --- a/packages/shell-api/src/shell-bson.spec.ts +++ b/packages/shell-api/src/shell-bson.spec.ts @@ -111,6 +111,11 @@ describe('Shell BSON', () => { expect(s._bsontype).to.equal('ObjectID'); expect(s.toHexString()).to.equal('5ebbe8e2905bb493d6981b6b'); }); + it('works with an integer argument', () => { + const s = new (shellBson.ObjectId as any)(0x12345678); + expect(s._bsontype).to.equal('ObjectID'); + expect(s.toHexString().slice(0, 8)).to.equal('12345678'); + }); it('has help and other metadata', async() => { const s = shellBson.ObjectId(); expect((await toShellResult(s.help)).type).to.equal('Help'); @@ -119,9 +124,9 @@ describe('Shell BSON', () => { }); it('errors for wrong type of arg 1', () => { try { - (shellBson.ObjectId as any)(1); + (shellBson.ObjectId as any)(Symbol('foo')); } catch (e) { - return expect(e.message).to.contain('string, got number'); + return expect(e.message).to.contain('object, got symbol'); } expect.fail('Expecting error, nothing thrown'); }); @@ -152,6 +157,11 @@ describe('Shell BSON', () => { const s = new (shellBson.Timestamp as any)(0, 100); expect(s._bsontype).to.equal('Timestamp'); }); + it('with a long argument', () => { + const s = shellBson.Timestamp(shellBson.Long(1, 2)); + expect(s._bsontype).to.equal('Timestamp'); + expect(s.toExtendedJSON()).to.deep.equal({ $timestamp: { t: 2, i: 1 } }); + }); it('has help and other metadata', async() => { const s = shellBson.Timestamp(0, 100); expect((await toShellResult(s.help)).type).to.equal('Help'); @@ -162,7 +172,7 @@ describe('Shell BSON', () => { try { (shellBson.Timestamp as any)('1'); } catch (e) { - return expect(e.message).to.contain('number, got string'); + return expect(e.message).to.contain('object, got string'); } expect.fail('Expecting error, nothing thrown'); }); @@ -191,6 +201,12 @@ describe('Shell BSON', () => { expect(code.code).to.equal('code'); expect(code.scope).to.deep.equal({ k: 'v' }); }); + it('works with a function argument', () => { + const fn = function() { expect.fail(); }; + const code = shellBson.Code(fn, { k: 'v' }); + expect(code.code).to.equal(fn); + expect(code.scope).to.deep.equal({ k: 'v' }); + }); it('has help and other metadata', async() => { const s = shellBson.Code('code', { k: 'v' }); expect((await toShellResult(s.help)).type).to.equal('Help'); @@ -201,7 +217,7 @@ describe('Shell BSON', () => { try { (shellBson.Code as any)(1); } catch (e) { - return expect(e.message).to.contain('string, got number'); + return expect(e.message).to.contain('function, got number'); } expect.fail('Expecting error, nothing thrown'); }); diff --git a/packages/shell-api/src/shell-bson.ts b/packages/shell-api/src/shell-bson.ts index c8ffa79b02..b665486249 100644 --- a/packages/shell-api/src/shell-bson.ts +++ b/packages/shell-api/src/shell-bson.ts @@ -51,32 +51,32 @@ export default function constructShellBson(bson: typeof BSON, printWarning: (msg (bson.BSONSymbol as any).prototype.deprecated = true; const bsonPkg = { - DBRef: Object.assign(function(namespace: string, oid: any, db?: string): any { + DBRef: Object.assign(function(namespace: string, oid: any, db?: string): typeof bson.DBRef.prototype { assertArgsDefinedType([namespace, oid, db], ['string', true, [undefined, 'string']], 'DBRef'); return new bson.DBRef(namespace, oid, db); }, { prototype: bson.DBRef.prototype }), // DBPointer not available in the bson 1.x library, but depreciated since 1.6 Map: bson.Map, - bsonsize: function(object: any): any { + bsonsize: function(object: any): number { assertArgsDefinedType([object], ['object'], 'bsonsize'); return bson.calculateObjectSize(object); }, - MaxKey: Object.assign(function(): any { + MaxKey: Object.assign(function(): typeof bson.MaxKey.prototype { return new bson.MaxKey(); }, { prototype: bson.MaxKey.prototype }), - MinKey: Object.assign(function(): any { + MinKey: Object.assign(function(): typeof bson.MinKey.prototype { return new bson.MinKey(); }, { prototype: bson.MinKey.prototype }), - ObjectId: Object.assign(function(id?: string): any { - assertArgsDefinedType([id], [[undefined, 'string']], 'ObjectId'); + ObjectId: Object.assign(function(id?: string | number | typeof bson.ObjectId.prototype | Buffer): typeof bson.ObjectId.prototype { + assertArgsDefinedType([id], [[undefined, 'string', 'number', 'object']], 'ObjectId'); return new bson.ObjectId(id); }, { prototype: bson.ObjectId.prototype }), - Timestamp: Object.assign(function(low = 0, high = 0): any { - assertArgsDefinedType([low, high], ['number', 'number'], 'Timestamp'); - return new bson.Timestamp(low, high); + Timestamp: Object.assign(function(low?: number | typeof bson.Long.prototype, high?: number): typeof bson.Timestamp.prototype { + assertArgsDefinedType([low, high], [['number', 'object', undefined], [undefined, 'number']], 'Timestamp'); + return new bson.Timestamp(low as number, high as number); }, { prototype: bson.Timestamp.prototype }), - Code: Object.assign(function(c: any = '', s?: any): any { - assertArgsDefinedType([c, s], [[undefined, 'string'], [undefined, 'object']], 'Code'); + Code: Object.assign(function(c: string | Function = '', s?: any): typeof bson.Code.prototype { + assertArgsDefinedType([c, s], [[undefined, 'string', 'function'], [undefined, 'object']], 'Code'); return new bson.Code(c, s); }, { prototype: bson.Code.prototype }), NumberDecimal: Object.assign(function(s = '0'): any {