diff --git a/snippets/mongocompat/mongotypes.js b/snippets/mongocompat/mongotypes.js index 9a659a8..32539d9 100644 --- a/snippets/mongocompat/mongotypes.js +++ b/snippets/mongocompat/mongotypes.js @@ -378,10 +378,57 @@ if (!NumberLong.prototype) { NumberLong.prototype = {}; } +NumberLong.prototype.nativeToString = NumberLong.prototype.toString; +NumberLong.prototype.toString = function () { + const INT32_MIN = -2147483648; + const INT32_MAX = 2147483647; + + const numValue = this.toNumber ? this.toNumber() : Number(this); + if (numValue >= INT32_MIN && numValue <= INT32_MAX && Number.isInteger(numValue)) { + return `NumberLong(${numValue})`; + } + return `NumberLong("${this.exactValueString}")`; +}; + NumberLong.prototype.tojson = function() { return this.toString(); }; +Object.defineProperty(NumberLong.prototype, 'floatApprox', { + enumerable: false, + configurable: true, + get: function() { + return this.toNumber ? this.toNumber() : Number(this); + } +}); + +Object.defineProperty(NumberLong.prototype, 'top', { + enumerable: false, + configurable: true, + get: function() { + return this.high; + } +}); + +Object.defineProperty(NumberLong.prototype, 'bottom', { + enumerable: false, + configurable: true, + get: function() { + return this.low; + } +}); + +Object.defineProperty(NumberLong.prototype, 'exactValueString', { + enumerable: false, + configurable: true, + get: function() { + const high = BigInt(this.high); + const low = BigInt(this.low >>> 0); + const value = (high << 32n) | low; + return value.toString(); + } +}); + // NumberInt if (!NumberInt.prototype) { NumberInt.prototype = {}; diff --git a/snippets/mongocompat/test.js b/snippets/mongocompat/test.js index 6913ae0..66e15f7 100644 --- a/snippets/mongocompat/test.js +++ b/snippets/mongocompat/test.js @@ -1,4 +1,24 @@ load(__dirname + '/index.js'); assert.strictEqual(ObjectId('0123456789abcdef01234567').tojson(), 'ObjectId("0123456789abcdef01234567")'); + assert.strictEqual(BinData(4, 'abcdefgh').toString(), 'BinData(4,"abcdefgh")'); + +assert.strictEqual(NumberLong(2147483647).toString(), 'NumberLong(2147483647)'); +assert.strictEqual(NumberLong("2147483648").toString(), 'NumberLong("2147483648")'); +assert.strictEqual(NumberLong(-2147483648).toString(), 'NumberLong(-2147483648)'); +assert.strictEqual(NumberLong(-2147483649).toString(), 'NumberLong("-2147483649")'); +assert.strictEqual(NumberLong(9223372036854775807).toString(), 'NumberLong("9223372036854775807")'); +assert.strictEqual(NumberLong(-9223372036854775808).toString(), 'NumberLong("-9223372036854775808")'); +const maxLong = NumberLong(9223372036854775807, 2147483647, -1); +assert.strictEqual(maxLong.floatApprox, 9223372036854775807); +assert.strictEqual(maxLong.top, 2147483647); +assert.strictEqual(maxLong.bottom, -1);//mongosh uses signed representation, while old shell uses unsigned +assert.strictEqual(maxLong.exactValueString, "9223372036854775807"); +const minLong = NumberLong(-9223372036854775808); +assert.strictEqual(minLong.floatApprox, -9223372036854776000); +assert.strictEqual(minLong.top, -2147483648); +assert.strictEqual(minLong.bottom, 0); +assert.strictEqual(minLong.exactValueString, "-9223372036854775808"); +const nl2 = NumberLong("200"); +assert.strictEqual(maxLong.compare(nl2), 1);