Skip to content
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@ coverage/
*.d.ts
*.tgz
docs/public

*.0x
95 changes: 95 additions & 0 deletions etc/benchmarks/main.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/* eslint-disable @typescript-eslint/no-var-requires */
import { performance } from 'perf_hooks';
import { readFile } from 'fs/promises';
import { cpus, totalmem } from 'os';

const hw = cpus();
const ram = totalmem() / 1024 ** 3;
const platform = { name: hw[0].model, cores: hw.length, ram: `${ram}GB` };
const ITERATIONS = 1_000_000;

const systemInfo = [
`\n- cpu: ${platform.name}`,
`- cores: ${platform.cores}`,
`- os: ${process.platform}`,
`- ram: ${platform.ram}`,
`- iterations: ${ITERATIONS.toLocaleString()}`
].join('\n');

const readJSONFile = async path =>
JSON.parse(await readFile(new URL(path, import.meta.url), { encoding: 'utf8' }));

function average(array) {
let sum = 0;
for (const value of array) sum += value;
return sum / array.length;
}

function testPerformance(fn, iterations = ITERATIONS) {
let measurements = [];
for (let i = 0; i < iterations; i++) {
const start = performance.now();
fn(i);
const end = performance.now();
measurements.push(end - start);
}
return average(measurements).toFixed(8);
}

async function main() {
const [currentBSON, currentReleaseBSON, legacyBSONLib] = await Promise.all([
(async () => ({
lib: await import('../../lib/bson.js'),
version: 'current local'
}))(),
(async () => ({
lib: await import('../../node_modules/bson_latest/lib/bson.js'),
version: (await readJSONFile('../../node_modules/bson_latest/package.json')).version
}))(),
(async () => {
const legacyBSON = (await import('../../node_modules/bson_legacy/index.js')).default;
return {
lib: { ...legacyBSON, ...legacyBSON.prototype },
version: (await readJSONFile('../../node_modules/bson_legacy/package.json')).version
};
})()
]).catch(error => {
console.error(error);
console.error(
`Please run:\n${[
'npm run build',
'npm install --no-save bson_legacy@npm:bson@1 bson_latest@npm:bson@latest'
].join('\n')}`
);
process.exit(1);
});

const documents = Array.from({ length: ITERATIONS }, () =>
currentReleaseBSON.lib.serialize({
_id: new currentReleaseBSON.lib.ObjectId(),
field1: 'value1'
})
);

console.log(systemInfo);

for (const bson of [currentBSON, currentReleaseBSON, legacyBSONLib]) {
console.log(`\nBSON@${bson.version}`);
console.log(
`deserialize({ oid, string }, { validation: { utf8: false } }) takes ${testPerformance(i =>
bson.lib.deserialize(documents[i], { validation: { utf8: false } })
)}ms on average`
);

const oidBuffer = Buffer.from('00'.repeat(12), 'hex');
console.log(
`new Oid(buf) take ${testPerformance(() => new bson.lib.ObjectId(oidBuffer))}ms on average`
);
}

console.log();
}

main()
.then(() => null)
.catch(error => console.error(error));
140 changes: 70 additions & 70 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion src/objectid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ export class ObjectId {
// Generate a new id
this[kId] = ObjectId.generate(typeof workingId === 'number' ? workingId : undefined);
} else if (ArrayBuffer.isView(workingId) && workingId.byteLength === 12) {
this[kId] = ensureBuffer(workingId);
// If intstanceof matches we can escape calling ensure buffer in Node.js environments
this[kId] = workingId instanceof Buffer ? workingId : ensureBuffer(workingId);
} else if (typeof workingId === 'string') {
if (workingId.length === 12) {
const bytes = Buffer.from(workingId);
Expand Down
13 changes: 13 additions & 0 deletions test/node/object_id_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -383,4 +383,17 @@ describe('ObjectId', function () {
expect(propAccessRecord).to.deep.equal([oidKId, oidKId]);
});
});

it('should return the same instance if a buffer is passed in', function () {
const inBuffer = Buffer.from('00'.repeat(12), 'hex');

const outBuffer = new ObjectId(inBuffer);

// instance equality
expect(inBuffer).to.equal(outBuffer.id);
// deep equality
expect(inBuffer).to.deep.equal(outBuffer.id);
// class method equality
expect(Buffer.prototype.equals.call(inBuffer, outBuffer.id)).to.be.true;
});
});
1 change: 1 addition & 0 deletions test/node/tools/utils.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* globals window */
'use strict';

exports.assertArrayEqual = function (array1, array2) {
Expand Down