Skip to content

Commit 3b36e62

Browse files
authored
fix(shell-api): add toBSON overrides to MinKey/MaxKey ctors MONGOSH-1024 (#1154)
Add `.toBSON` overrides so that sending `MinKey` or `MaxKey` over the wire results in the same document that `MinKey()` or `MaxKey()` would have generated, for compatibility with the legacy shell.
1 parent 4134759 commit 3b36e62

File tree

3 files changed

+40
-2
lines changed

3 files changed

+40
-2
lines changed

packages/cli-repl/test/e2e-bson.spec.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,19 @@ describe('BSON e2e', function() {
317317
shell.assertNoErrors();
318318
});
319319
});
320+
describe('MaxKey/MinKey special handling', () => {
321+
it('inserts and retrieves MaxKey/MinKey regardless of whether they have been called as functions', async() => {
322+
await shell.executeLine(`use ${dbName}`);
323+
await shell.executeLine(`db.test.insertOne({
324+
maxfn: MaxKey, maxval: MaxKey(), minfn: MinKey, minval: MinKey()
325+
})`);
326+
const output = await shell.executeLine('db.test.findOne()');
327+
expect(output).to.include('maxfn: MaxKey()');
328+
expect(output).to.include('maxval: MaxKey()');
329+
expect(output).to.include('minfn: MinKey()');
330+
expect(output).to.include('minval: MinKey()');
331+
});
332+
});
320333
describe('help methods', () => {
321334
it('ObjectId has help when returned from the server', async() => {
322335
const value = new bson.ObjectId();

packages/shell-api/src/shell-bson.spec.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* eslint camelcase: 0, new-cap: 0 */
22
import { CommonErrors, MongoshInvalidInputError } from '@mongosh/errors';
33
import { bson } from '@mongosh/service-provider-core';
4+
import { serialize as bsonSerialize, deserialize as bsonDeserialize } from 'bson';
45
import { expect } from 'chai';
56
import sinon from 'ts-sinon';
67
import { ALL_SERVER_VERSIONS } from './enums';
@@ -77,6 +78,10 @@ describe('Shell BSON', () => {
7778
const s = new (shellBson.MaxKey as any)();
7879
expect(s._bsontype).to.equal('MaxKey');
7980
});
81+
it('using toBSON', () => {
82+
const s = (shellBson.MaxKey as any).toBSON();
83+
expect(s._bsontype).to.equal('MaxKey');
84+
});
8085
it('has help and other metadata', async() => {
8186
const s = shellBson.MaxKey();
8287
expect((await toShellResult(s.help)).type).to.equal('Help');
@@ -93,13 +98,31 @@ describe('Shell BSON', () => {
9398
const s = new (shellBson.MinKey as any)();
9499
expect(s._bsontype).to.equal('MinKey');
95100
});
101+
it('using toBSON', () => {
102+
const s = (shellBson.MinKey as any).toBSON();
103+
expect(s._bsontype).to.equal('MinKey');
104+
});
96105
it('has help and other metadata', async() => {
97106
const s = shellBson.MinKey();
98107
expect((await toShellResult(s.help)).type).to.equal('Help');
99108
expect((await toShellResult(s.help())).type).to.equal('Help');
100109
expect(s.serverVersions).to.deep.equal(ALL_SERVER_VERSIONS);
101110
});
102111
});
112+
describe('MinKey & MaxKey constructor special handling', () => {
113+
it('round-trips through bson as expected', () => {
114+
const { MinKey, MaxKey } = shellBson as any;
115+
const expected = { a: { $minKey: 1 }, b: { $maxKey: 1 } };
116+
function roundtrip(value: any): any {
117+
return bson.EJSON.serialize(bsonDeserialize(bsonSerialize(value)));
118+
}
119+
120+
expect(roundtrip({ a: new MinKey(), b: new MaxKey() })).to.deep.equal(expected);
121+
expect(roundtrip({ a: MinKey(), b: MaxKey() })).to.deep.equal(expected);
122+
expect(roundtrip({ a: MinKey.toBSON(), b: MaxKey.toBSON() })).to.deep.equal(expected);
123+
expect(roundtrip({ a: MinKey, b: MaxKey })).to.deep.equal(expected);
124+
});
125+
});
103126
describe('ObjectId', () => {
104127
it('without new', () => {
105128
const s = shellBson.ObjectId('5ebbe8e2905bb493d6981b6b');
@@ -615,6 +638,7 @@ describe('Shell BSON', () => {
615638
delete bsonProperties.length;
616639
delete shellProperties.index; // ObjectId.index is a random number
617640
delete bsonProperties.index; // ObjectId.index is a random number
641+
delete shellProperties.toBSON; // toBSON is something we add for MaxKey/MinKey as a shell-specific extension
618642
try {
619643
expect(shellProperties).to.deep.equal(bsonProperties);
620644
} catch (err) {

packages/shell-api/src/shell-bson.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,13 @@ export default function constructShellBson(bson: typeof BSON, printWarning: (msg
9494
assertArgsDefinedType([object], ['object'], 'bsonsize');
9595
return bson.calculateObjectSize(object);
9696
},
97+
// See https://jira.mongodb.org/browse/MONGOSH-1024 for context on the toBSON additions
9798
MaxKey: Object.assign(function MaxKey(): typeof bson.MaxKey.prototype {
9899
return new bson.MaxKey();
99-
}, { ...bson.MaxKey, prototype: bson.MaxKey.prototype }),
100+
}, { ...bson.MaxKey, toBSON: () => new bson.MaxKey(), prototype: bson.MaxKey.prototype }),
100101
MinKey: Object.assign(function MinKey(): typeof bson.MinKey.prototype {
101102
return new bson.MinKey();
102-
}, { ...bson.MinKey, prototype: bson.MinKey.prototype }),
103+
}, { ...bson.MinKey, toBSON: () => new bson.MinKey(), prototype: bson.MinKey.prototype }),
103104
ObjectId: Object.assign(function ObjectId(id?: string | number | typeof bson.ObjectId.prototype | Buffer): typeof bson.ObjectId.prototype {
104105
assertArgsDefinedType([id], [[undefined, 'string', 'number', 'object']], 'ObjectId');
105106
return new bson.ObjectId(id);

0 commit comments

Comments
 (0)