Skip to content

Commit b766d0f

Browse files
authored
feat(NODE-6031): add t and i to Timestamp (#704)
1 parent ede8357 commit b766d0f

File tree

3 files changed

+61
-4
lines changed

3 files changed

+61
-4
lines changed

src/timestamp.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ export interface TimestampExtended {
2828
/**
2929
* @public
3030
* @category BSONType
31+
*
32+
* A special type for _internal_ MongoDB use and is **not** associated with the regular Date type.
3133
*/
3234
export class Timestamp extends LongWithoutOverridesClass {
3335
get _bsontype(): 'Timestamp' {
@@ -36,6 +38,20 @@ export class Timestamp extends LongWithoutOverridesClass {
3638

3739
static readonly MAX_VALUE = Long.MAX_UNSIGNED_VALUE;
3840

41+
/**
42+
* An incrementing ordinal for operations within a given second.
43+
*/
44+
get i(): number {
45+
return this.low >>> 0;
46+
}
47+
48+
/**
49+
* A `time_t` value measuring seconds since the Unix epoch
50+
*/
51+
get t(): number {
52+
return this.high >>> 0;
53+
}
54+
3955
/**
4056
* @param int - A 64-bit bigint representing the Timestamp.
4157
*/
@@ -127,7 +143,7 @@ export class Timestamp extends LongWithoutOverridesClass {
127143

128144
/** @internal */
129145
toExtendedJSON(): TimestampExtended {
130-
return { $timestamp: { t: this.high >>> 0, i: this.low >>> 0 } };
146+
return { $timestamp: { t: this.t, i: this.i } };
131147
}
132148

133149
/** @internal */
@@ -144,8 +160,8 @@ export class Timestamp extends LongWithoutOverridesClass {
144160

145161
inspect(depth?: number, options?: unknown, inspect?: InspectFn): string {
146162
inspect ??= defaultInspect;
147-
const t = inspect(this.high >>> 0, options);
148-
const i = inspect(this.low >>> 0, options);
163+
const t = inspect(this.t, options);
164+
const i = inspect(this.i, options);
149165
return `new Timestamp({ t: ${t}, i: ${i} })`;
150166
}
151167
}

test/node/timestamp.test.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,37 @@ describe('Timestamp', () => {
99
});
1010
});
1111

12+
describe('get i() and get t()', () => {
13+
it('i returns lower bits', () => {
14+
const l = new BSON.Long(1, 2);
15+
const ts = new BSON.Timestamp(l);
16+
expect(ts.i).to.equal(l.low);
17+
});
18+
19+
it('t returns higher bits', () => {
20+
const l = new BSON.Long(1, 2);
21+
const ts = new BSON.Timestamp(l);
22+
expect(ts.t).to.equal(l.high);
23+
});
24+
25+
describe('when signed negative input is provided to the constructor', () => {
26+
it('t and i return unsigned values', () => {
27+
const l = new BSON.Long(-1, -2);
28+
// Check the assumption that Long did NOT change the values to unsigned.
29+
expect(l).to.have.property('low', -1);
30+
expect(l).to.have.property('high', -2);
31+
32+
const ts = new BSON.Timestamp(l);
33+
expect(ts).to.have.property('i', 0xffffffff); // -1 unsigned
34+
expect(ts).to.have.property('t', 0xfffffffe); // -2 unsigned
35+
36+
// Timestamp is a subclass of Long, high and low do not change:
37+
expect(ts).to.have.property('low', -1);
38+
expect(ts).to.have.property('high', -2);
39+
});
40+
});
41+
});
42+
1243
it('should always be an unsigned value', () => {
1344
let bigIntInputs: Timestamp[] = [];
1445
if (!__noBigInt__) {
@@ -23,7 +54,8 @@ describe('Timestamp', () => {
2354
new BSON.Timestamp({ t: 0xffff_ffff, i: 0xffff_ffff }),
2455
// @ts-expect-error We do not advertise support for Int32 in the constructor of Timestamp
2556
// We do expect it to work so that round tripping the Int32 instance inside a Timestamp works
26-
new BSON.Timestamp({ t: new BSON.Int32(0x7fff_ffff), i: new BSON.Int32(0x7fff_ffff) })
57+
new BSON.Timestamp({ t: new BSON.Int32(0x7fff_ffff), i: new BSON.Int32(0x7fff_ffff) }),
58+
new BSON.Timestamp(new BSON.Timestamp({ t: 0xffff_ffff, i: 0xffff_ffff }))
2759
];
2860

2961
for (const timestamp of table) {
@@ -69,6 +101,12 @@ describe('Timestamp', () => {
69101
expect(timestamp.toExtendedJSON()).to.deep.equal({ $timestamp: input });
70102
});
71103

104+
it('accepts timestamp object as input', () => {
105+
const input = new BSON.Timestamp({ t: 89, i: 144 });
106+
const timestamp = new BSON.Timestamp(input);
107+
expect(timestamp.toExtendedJSON()).to.deep.equal({ $timestamp: { t: input.t, i: input.i } });
108+
});
109+
72110
it('accepts { t, i } object as input and coerce to integer', () => {
73111
const input = { t: new BSON.Int32(89), i: new BSON.Int32(144) };
74112
// @ts-expect-error We do not advertise support for Int32 in the constructor of Timestamp

test/types/bson.test-d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,6 @@ expectType<(depth?: number | undefined, options?: unknown, inspect?: InspectFn |
8282
expectNotDeprecated(new ObjectId('foo'));
8383
expectDeprecated(new ObjectId(42));
8484
expectNotDeprecated(new ObjectId(42 as string | number));
85+
86+
// Timestamp accepts timestamp because constructor allows: {i:number, t:number}
87+
new Timestamp(new Timestamp(0n))

0 commit comments

Comments
 (0)