Skip to content

Commit 38c7c26

Browse files
Add old shell compatibility for Timestamp for JS Engine (#18)
1 parent 4059955 commit 38c7c26

File tree

2 files changed

+99
-0
lines changed

2 files changed

+99
-0
lines changed

snippets/mongocompat/mongotypes.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,59 @@
11
// Date and time types
22
if (typeof (Timestamp) != "undefined") {
3+
const OriginalTimestamp = Timestamp;
4+
5+
// Reference: https://github.com/mongodb/mongo/blob/c4d21d3346572e28df2f174df4d87e7618df4a77/src/mongo/scripting/mozjs/timestamp.cpp#L67-L78
6+
function validateTimestampComponent(component, name) {
7+
const MAX_UINT32 = 4294967295;
8+
9+
if (typeof component !== 'number') {
10+
throw new TypeError(`${name} must be a number`);
11+
}
12+
13+
const val = Math.floor(component);
14+
if (val < 0 || val > MAX_UINT32) {
15+
throw new TypeError(
16+
`${name} must be non-negative and not greater than ${MAX_UINT32}, got ${val}`
17+
);
18+
}
19+
20+
return val;
21+
}
22+
23+
Timestamp = function(t, i) {
24+
if (arguments.length === 0) {
25+
return new OriginalTimestamp({ t: 0, i: 0 });
26+
}
27+
28+
if (arguments.length === 1) {
29+
const proto = Object.getPrototypeOf(t);
30+
if ((proto === null || proto === Object.prototype) && ('t' in t || 'i' in t)) {
31+
const validatedT = validateTimestampComponent(t.t || 0, "Timestamp time (seconds)");
32+
const validatedI = validateTimestampComponent(t.i || 0, "Timestamp increment");
33+
return new OriginalTimestamp({ t: validatedT, i: validatedI });
34+
}
35+
return new OriginalTimestamp(t);
36+
}
37+
38+
// Reference: https://github.com/mongodb/mongo/blob/c4d21d3346572e28df2f174df4d87e7618df4a77/src/mongo/scripting/mozjs/timestamp.cpp#L91-L98
39+
if (arguments.length === 2) {
40+
const validatedT = validateTimestampComponent(t, "Timestamp time (seconds)");
41+
const validatedI = validateTimestampComponent(i, "Timestamp increment");
42+
return new OriginalTimestamp({ t: validatedT, i: validatedI });
43+
}
44+
45+
throw new Error("Timestamp needs 0 or 2 arguments");
46+
};
47+
48+
Timestamp.prototype = OriginalTimestamp.prototype;
49+
50+
for (const key of Object.getOwnPropertyNames(OriginalTimestamp)) {
51+
// Skip prototype, length, name(function internals)
52+
if (key !== 'prototype' && key !== 'length' && key !== 'name') {
53+
Timestamp[key] = OriginalTimestamp[key];
54+
}
55+
}
56+
357
Timestamp.prototype.tojson = function() {
458
return this.toStringIncomparable();
559
};

snippets/mongocompat/test.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,51 @@ assert.strictEqual(minLong.bottom, 0);
2222
assert.strictEqual(minLong.exactValueString, "-9223372036854775808");
2323
const nl2 = NumberLong("200");
2424
assert.strictEqual(maxLong.compare(nl2), 1);
25+
2526
const decimal = NumberDecimal("1.1");
2627
assert.strictEqual(decimal.toString(), 'NumberDecimal("1.1")');
2728
assert.strictEqual(decimal.tojson(), 'NumberDecimal("1.1")');
29+
30+
const ts1 = Timestamp();
31+
assert.strictEqual(ts1.toString(), 'Timestamp(0, 0)');
32+
const ts2 = Timestamp(100, 200);
33+
assert.strictEqual(ts2.toString(), 'Timestamp(100, 200)');
34+
const ts3 = Timestamp(1.9, 2.1);
35+
assert.strictEqual(ts3.toString(), 'Timestamp(1, 2)');
36+
try {
37+
Timestamp(-1, 0);
38+
assert.fail('Should throw for negative time');
39+
} catch (e) {
40+
assert(e.message.includes('must be non-negative'));
41+
}
42+
try {
43+
Timestamp(0, 5000000000);
44+
assert.fail('Should throw for i > uint32 max');
45+
} catch (e) {
46+
assert(e.message.includes('not greater than 4294967295'));
47+
}
48+
const ts4 = Timestamp(123, 456);
49+
assert(ts4 instanceof Timestamp);
50+
assert.strictEqual(ts4.toString(), 'Timestamp(123, 456)');
51+
assert.strictEqual(ts4.tojson(), 'Timestamp(123, 456)');
52+
assert.strictEqual(ts4.getTime(), 123);
53+
assert.strictEqual(ts4.getInc(), 456);
54+
assert.strictEqual(ts4._bsontype, 'Timestamp');
55+
const tsFromBits = Timestamp.fromBits(100, 200);
56+
assert(tsFromBits instanceof Timestamp);
57+
assert.strictEqual(tsFromBits.i, 100);
58+
assert.strictEqual(tsFromBits.t, 200);
59+
assert.strictEqual(tsFromBits.toString(), 'Timestamp(200, 100)');
60+
const tsFromInt = Timestamp.fromInt(12345);
61+
assert.strictEqual(tsFromInt._bsontype, 'Timestamp');
62+
assert.strictEqual(tsFromInt.i, 12345);
63+
assert.strictEqual(tsFromInt.t, 0);
64+
const tsFromNum = Timestamp.fromNumber(67890);
65+
assert.strictEqual(tsFromNum._bsontype, 'Timestamp');
66+
assert.strictEqual(tsFromNum.i, 67890);
67+
assert.strictEqual(tsFromNum.t, 0);
68+
const tsFromStr = Timestamp.fromString('ff', 16);
69+
assert.strictEqual(tsFromStr.i, 255);
70+
assert.strictEqual(tsFromStr.t, 0);
71+
assert.strictEqual(Timestamp.MAX_VALUE._bsontype, 'Long');
72+
assert.strictEqual(Timestamp.MAX_VALUE, Long.MAX_UNSIGNED_VALUE);

0 commit comments

Comments
 (0)