@@ -4,16 +4,19 @@ import { type InspectFn, defaultInspect } from './parser/utils';
4
4
import { ByteUtils } from './utils/byte_utils' ;
5
5
import { NumberUtils } from './utils/number_utils' ;
6
6
7
+ // Settings for ObjectId Buffer pool
8
+ // Disable pool by default in order to ensure compatibility
9
+ // Specify larger poolSize to enable pool
7
10
let currentPool : Uint8Array | null = null ;
8
- let poolSize = 1000 ; // Default: Hold 1000 ObjectId buffers in a pool
11
+ let poolSize = 1 ; // Disable pool by default.
9
12
let currentPoolOffset = 0 ;
10
13
11
14
/**
12
15
* Retrieves a ObjectId pool and offset. This function may create a new ObjectId buffer pool and reset the pool offset
13
16
* @internal
14
17
*/
15
18
function getPool ( ) : [ Uint8Array , number ] {
16
- if ( ! currentPool || currentPoolOffset + 12 > currentPool . byteLength ) {
19
+ if ( ! currentPool || currentPoolOffset + 12 > currentPool . length ) {
17
20
currentPool = ByteUtils . allocateUnsafe ( poolSize * 12 ) ;
18
21
currentPoolOffset = 0 ;
19
22
}
@@ -75,7 +78,7 @@ export class ObjectId extends BSONValue {
75
78
/** ObjectId buffer pool pointer @internal */
76
79
private pool : Uint8Array ;
77
80
/** Buffer pool offset @internal */
78
- private offset : number ;
81
+ private offset ? : number ;
79
82
80
83
/** ObjectId hexString cache @internal */
81
84
private __id ?: string ;
@@ -151,43 +154,55 @@ export class ObjectId extends BSONValue {
151
154
workingId = inputId ;
152
155
}
153
156
154
- const [ pool , offset ] = getPool ( ) ;
155
-
156
- // The following cases use workingId to construct an ObjectId
157
- if ( workingId == null || typeof workingId === 'number' ) {
158
- // The most common use case (blank id, new objectId instance)
159
- // Generate a new id
160
- ObjectId . generate ( typeof workingId === 'number' ? workingId : undefined , pool , offset ) ;
161
- } else if ( ArrayBuffer . isView ( workingId ) ) {
162
- if ( workingId . byteLength === 12 ) {
163
- inputIndex = 0 ;
164
- } else if (
165
- typeof inputIndex !== 'number' ||
166
- inputIndex < 0 ||
167
- workingId . byteLength < inputIndex + 12 ||
168
- isNaN ( inputIndex )
169
- ) {
170
- throw new BSONError ( 'Buffer length must be 12 or a valid offset must be specified' ) ;
171
- }
172
- for ( let i = 0 ; i < 12 ; i ++ ) pool [ offset + i ] = workingId [ inputIndex + i ] ;
173
- } else if ( typeof workingId === 'string' ) {
174
- if ( workingId . length === 24 && checkForHexRegExp . test ( workingId ) ) {
175
- pool . set ( ByteUtils . fromHex ( workingId ) , offset ) ;
157
+ let pool : Uint8Array ;
158
+ let offset : number ;
159
+
160
+ // Special case when poolSize === 1 and a 12 byte buffer is passed in - just persist buffer
161
+ if ( poolSize === 1 && ArrayBuffer . isView ( workingId ) && workingId . length === 12 ) {
162
+ pool = ByteUtils . toLocalBufferType ( workingId ) ;
163
+ offset = 0 ;
164
+ } else {
165
+ [ pool , offset ] = getPool ( ) ;
166
+
167
+ // The following cases use workingId to construct an ObjectId
168
+ if ( workingId == null || typeof workingId === 'number' ) {
169
+ // The most common use case (blank id, new objectId instance)
170
+ // Generate a new id
171
+ ObjectId . generate ( typeof workingId === 'number' ? workingId : undefined , pool , offset ) ;
172
+ } else if ( ArrayBuffer . isView ( workingId ) ) {
173
+ if ( workingId . length === 12 ) {
174
+ inputIndex = 0 ;
175
+ } else if (
176
+ typeof inputIndex !== 'number' ||
177
+ inputIndex < 0 ||
178
+ workingId . length < inputIndex + 12 ||
179
+ isNaN ( inputIndex )
180
+ ) {
181
+ throw new BSONError ( 'Buffer length must be 12 or a valid offset must be specified' ) ;
182
+ }
183
+ for ( let i = 0 ; i < 12 ; i ++ ) pool [ offset + i ] = workingId [ inputIndex + i ] ;
184
+ } else if ( typeof workingId === 'string' ) {
185
+ if ( workingId . length === 24 && checkForHexRegExp . test ( workingId ) ) {
186
+ pool . set ( ByteUtils . fromHex ( workingId ) , offset ) ;
187
+ } else {
188
+ throw new BSONError (
189
+ 'input must be a 24 character hex string, 12 byte Uint8Array, or an integer'
190
+ ) ;
191
+ }
176
192
} else {
177
- throw new BSONError (
178
- 'input must be a 24 character hex string, 12 byte Uint8Array, or an integer'
179
- ) ;
193
+ throw new BSONError ( 'Argument passed in does not match the accepted types' ) ;
180
194
}
181
- } else {
182
- throw new BSONError ( 'Argument passed in does not match the accepted types' ) ;
183
195
}
184
196
// If we are caching the hex string
185
197
if ( ObjectId . cacheHexString ) {
186
198
this . __id = ByteUtils . toHex ( pool , offset , offset + 12 ) ;
187
199
}
188
200
// Increment pool offset once we have completed initialization
189
201
this . pool = pool ;
190
- this . offset = offset ;
202
+ // Only set offset if pool is used
203
+ if ( poolSize > 1 ) {
204
+ this . offset = offset ;
205
+ }
191
206
incrementPool ( ) ;
192
207
}
193
208
@@ -201,6 +216,7 @@ export class ObjectId extends BSONValue {
201
216
* @readonly
202
217
*/
203
218
get id ( ) : Uint8Array {
219
+ if ( this . offset === undefined ) return this . pool ;
204
220
return this . pool . subarray ( this . offset , this . offset + 12 ) ;
205
221
}
206
222
@@ -219,8 +235,9 @@ export class ObjectId extends BSONValue {
219
235
if ( ObjectId . cacheHexString && this . __id ) {
220
236
return this . __id ;
221
237
}
238
+ const start = this . offset ?? 0 ;
222
239
223
- const hexString = ByteUtils . toHex ( this . pool , this . offset , this . offset + 12 ) ;
240
+ const hexString = ByteUtils . toHex ( this . pool , start , start + 12 ) ;
224
241
225
242
if ( ObjectId . cacheHexString && ! this . __id ) {
226
243
this . __id = hexString ;
@@ -329,16 +346,20 @@ export class ObjectId extends BSONValue {
329
346
}
330
347
331
348
if ( ObjectId . is ( otherId ) ) {
332
- if ( otherId . pool && typeof otherId . offset === 'number' ) {
349
+ if ( otherId . pool ) {
333
350
for ( let i = 11 ; i >= 0 ; i -- ) {
334
- if ( this . pool [ this . offset + i ] !== otherId . pool [ otherId . offset + i ] ) {
351
+ const offset = this . offset ?? 0 ;
352
+ const otherOffset = otherId . offset ?? 0 ;
353
+ if ( this . pool [ offset + i ] !== otherId . pool [ otherOffset + i ] ) {
335
354
return false ;
336
355
}
337
356
}
338
357
return true ;
339
358
}
340
359
// If otherId does not have pool and offset, fallback to buffer comparison for compatibility
341
- return ByteUtils . equals ( this . buffer , otherId . buffer ) ;
360
+ return (
361
+ this . buffer [ 11 ] === otherId . buffer [ 11 ] && ByteUtils . equals ( this . buffer , otherId . buffer )
362
+ ) ;
342
363
}
343
364
344
365
if ( typeof otherId === 'string' ) {
@@ -357,7 +378,7 @@ export class ObjectId extends BSONValue {
357
378
/** Returns the generation date (accurate up to the second) that this ID was generated. */
358
379
getTimestamp ( ) : Date {
359
380
const timestamp = new Date ( ) ;
360
- const time = NumberUtils . getUint32BE ( this . pool , this . offset ) ;
381
+ const time = NumberUtils . getUint32BE ( this . pool , this . offset ?? 0 ) ;
361
382
timestamp . setTime ( Math . floor ( time ) * 1000 ) ;
362
383
return timestamp ;
363
384
}
@@ -370,7 +391,7 @@ export class ObjectId extends BSONValue {
370
391
/** @internal */
371
392
serializeInto ( uint8array : Uint8Array , index : number ) : 12 {
372
393
const pool = this . pool ;
373
- const offset = this . offset ;
394
+ const offset = this . offset ?? 0 ;
374
395
uint8array [ index ] = pool [ offset ] ;
375
396
uint8array [ index + 1 ] = pool [ offset + 1 ] ;
376
397
uint8array [ index + 2 ] = pool [ offset + 2 ] ;
0 commit comments