Skip to content

Commit a93279a

Browse files
cache hex string by default and use private property
1 parent 883f238 commit a93279a

File tree

5 files changed

+84
-17
lines changed

5 files changed

+84
-17
lines changed

package-lock.json

Lines changed: 11 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"tar": "^7.4.3",
5858
"ts-node": "^10.9.2",
5959
"tsd": "^0.33.0",
60+
"tslib": "^2.8.1",
6061
"typescript": "^5.8.3",
6162
"typescript-cached-transpile": "0.0.6",
6263
"uuid": "^11.1.0"

src/objectid.ts

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@ import { NumberUtils } from './utils/number_utils';
77
// Unique sequence for the current process (initialized on first use)
88
let PROCESS_UNIQUE: Uint8Array | null = null;
99

10-
/** ObjectId hexString cache @internal */
11-
const __idCache = new WeakMap(); // TODO(NODE-6549): convert this to #__id private field when target updated to ES2022
12-
1310
/** @public */
1411
export interface ObjectIdLike {
1512
id: string | Uint8Array;
@@ -35,11 +32,28 @@ export class ObjectId extends BSONValue {
3532
/** @internal */
3633
private static index = Math.floor(Math.random() * 0xffffff);
3734

38-
static cacheHexString: boolean;
35+
static cacheHexString: boolean = true;
3936

4037
/** ObjectId Bytes @internal */
4138
private buffer!: Uint8Array;
4239

40+
/**
41+
* If hex string caching is enabled, contains the cached hex string. Otherwise, is null.
42+
*
43+
* Note that #hexString is populated lazily, and as a result simply checking `this.#hexString != null` is
44+
* not sufficient to determine if caching is enabled. `ObjectId.prototype.isCached()` can be used to
45+
* determine if the hex string has been cached yet for an ObjectId.
46+
*/
47+
#_hexString: string | null = null;
48+
49+
get #hexString(): string | null {
50+
return this.#_hexString;
51+
}
52+
53+
set #hexString(s: string) {
54+
this.#_hexString = s.toLowerCase();
55+
}
56+
4357
/** To generate a new ObjectId, use ObjectId() with no argument. */
4458
constructor();
4559
/**
@@ -107,7 +121,7 @@ export class ObjectId extends BSONValue {
107121
this.buffer = ByteUtils.fromHex(workingId);
108122
// If we are caching the hex string
109123
if (ObjectId.cacheHexString) {
110-
__idCache.set(this, workingId);
124+
this.#hexString = workingId;
111125
}
112126
} else {
113127
throw new BSONError(
@@ -130,7 +144,7 @@ export class ObjectId extends BSONValue {
130144
set id(value: Uint8Array) {
131145
this.buffer = value;
132146
if (ObjectId.cacheHexString) {
133-
__idCache.set(this, ByteUtils.toHex(value));
147+
this.#hexString = ByteUtils.toHex(value);
134148
}
135149
}
136150

@@ -159,15 +173,12 @@ export class ObjectId extends BSONValue {
159173

160174
/** Returns the ObjectId id as a 24 lowercase character hex string representation */
161175
toHexString(): string {
162-
if (ObjectId.cacheHexString) {
163-
const __id = __idCache.get(this);
164-
if (__id) return __id;
165-
}
176+
if (this.#hexString) return this.#hexString;
166177

167178
const hexString = ByteUtils.toHex(this.id);
168179

169180
if (ObjectId.cacheHexString) {
170-
__idCache.set(this, hexString);
181+
this.#hexString = hexString;
171182
}
172183

173184
return hexString;
@@ -365,9 +376,13 @@ export class ObjectId extends BSONValue {
365376
return new ObjectId(doc.$oid);
366377
}
367378

368-
/** @internal */
379+
/**
380+
* @internal
381+
*
382+
* used for testing
383+
*/
369384
private isCached(): boolean {
370-
return ObjectId.cacheHexString && __idCache.has(this);
385+
return ObjectId.cacheHexString && this.#hexString != null;
371386
}
372387

373388
/**

test/node/bson_test.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1572,6 +1572,7 @@ describe('BSON', function () {
15721572
* @ignore
15731573
*/
15741574
it('ObjectId should have a correct cached representation of the hexString', function (done) {
1575+
const cacheHexString = ObjectId.cacheHexString;
15751576
ObjectId.cacheHexString = true;
15761577
// generated ObjectID uses lazy caching
15771578
var a = new ObjectId();
@@ -1622,6 +1623,8 @@ describe('BSON', function () {
16221623
a.toHexString();
16231624
expect(a.isCached()).to.be.false;
16241625

1626+
ObjectId.cacheHexString = cacheHexString;
1627+
16251628
done();
16261629
});
16271630

test/node/object_id.test.ts

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,48 @@ import * as util from 'util';
44
import { expect } from 'chai';
55
import { bufferFromHexArray } from './tools/utils';
66
import { isBufferOrUint8Array } from './tools/utils';
7+
import { test } from 'mocha';
78

89
describe('ObjectId', function () {
10+
describe('hex string caching does not impact deep equality', function () {
11+
test('no hex strings cached', function () {
12+
const id = new ObjectId();
13+
const id2 = new ObjectId(id.id);
14+
15+
// @ts-expect-error isCached() is internal
16+
expect(id.isCached()).to.be.false;
17+
// @ts-expect-error isCached() is internal
18+
expect(id2.isCached()).to.be.false;
19+
20+
expect(new ObjectId(id.id)).to.deep.equal(id);
21+
});
22+
23+
test('one id with cached hex string, one without', function () {
24+
const id = new ObjectId();
25+
const id2 = new ObjectId(id.id);
26+
id2.toHexString();
27+
28+
// @ts-expect-error isCached() is internal
29+
expect(id.isCached()).to.be.false;
30+
// @ts-expect-error isCached() is internal
31+
expect(id2.isCached()).to.be.true;
32+
33+
expect(id).to.deep.equal(id2);
34+
});
35+
36+
test('both with cached hex string', function () {
37+
const id = new ObjectId();
38+
const id2 = new ObjectId(id.toHexString());
39+
40+
// @ts-expect-error isCached() is internal
41+
expect(id.isCached()).to.be.true;
42+
// @ts-expect-error isCached() is internal
43+
expect(id2.isCached()).to.be.true;
44+
45+
expect(id).to.deep.equal(id2);
46+
});
47+
});
48+
949
describe('static createFromTime()', () => {
1050
it('creates an objectId with user defined value in the timestamp field', function () {
1151
const a = ObjectId.createFromTime(1);
@@ -265,7 +305,7 @@ describe('ObjectId', function () {
265305
let a = 'AAAAAAAAAAAAAAAAAAAAAAAA';
266306
let b = new ObjectId(a);
267307
let c = b.equals(a); // => false
268-
expect(true).to.equal(c);
308+
expect(c).to.be.true;
269309

270310
a = 'aaaaaaaaaaaaaaaaaaaaaaaa';
271311
b = new ObjectId(a);

0 commit comments

Comments
 (0)