Skip to content

Commit 11ae31b

Browse files
committed
feat: Filter invalid ObjectId constructor types in getIds
1 parent 7fdbe02 commit 11ae31b

File tree

2 files changed

+102
-17
lines changed

2 files changed

+102
-17
lines changed

src/__tests__/utils.test.ts

Lines changed: 91 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1-
import { deepStrictEqual, equal, ok } from 'node:assert/strict';
1+
import { deepStrictEqual, ok } from 'node:assert/strict';
22
import { describe, test } from 'node:test';
33
import { ObjectId } from 'mongodb';
44
import { expectType } from 'ts-expect';
55
import { DefaultsOption } from '../schema';
6-
import { NestedPaths, ProjectionType, getIds, PropertyType, getDefaultValues } from '../utils';
6+
import {
7+
NestedPaths,
8+
ProjectionType,
9+
getIds,
10+
PropertyType,
11+
getDefaultValues,
12+
ObjectIdConstructorParameter,
13+
} from '../utils';
714

815
describe('utils', () => {
916
interface TestDocument {
@@ -379,19 +386,88 @@ describe('utils', () => {
379386
});
380387

381388
describe('getIds', () => {
382-
for (const input of [
383-
['123456789012345678900001', '123456789012345678900002'],
384-
[new ObjectId('123456789012345678900001'), new ObjectId('123456789012345678900002')],
385-
['123456789012345678900001', new ObjectId('123456789012345678900002')],
386-
]) {
387-
test('case', () => {
388-
const result = getIds(input);
389-
390-
equal(result.length, 2);
391-
ok(result[0] instanceof ObjectId);
392-
equal(result[0].toHexString(), '123456789012345678900001');
393-
ok(result[1] instanceof ObjectId);
394-
equal(result[1].toHexString(), '123456789012345678900002');
389+
const testCases: readonly [
390+
string,
391+
{
392+
readonly input: readonly ObjectIdConstructorParameter[];
393+
readonly expected: readonly ObjectId[];
394+
},
395+
][] = [
396+
[
397+
'strings',
398+
{
399+
input: ['123456789012345678900001', '123456789012345678900002'],
400+
expected: [
401+
new ObjectId('123456789012345678900001'),
402+
new ObjectId('123456789012345678900002'),
403+
],
404+
},
405+
],
406+
[
407+
'ObjectIds',
408+
{
409+
input: [
410+
new ObjectId('123456789012345678900099'),
411+
new ObjectId('123456789012345678900022'),
412+
],
413+
expected: [
414+
new ObjectId('123456789012345678900099'),
415+
new ObjectId('123456789012345678900022'),
416+
],
417+
},
418+
],
419+
[
420+
'Uint8Arrays',
421+
{
422+
input: [
423+
new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
424+
new Uint8Array([13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]),
425+
],
426+
expected: [
427+
new ObjectId('0102030405060708090a0b0c'),
428+
new ObjectId('0d0e0f101112131415161718'),
429+
],
430+
},
431+
],
432+
[
433+
'mixed',
434+
{
435+
input: ['123456789012345678900014', new ObjectId('123456789012345678900088')],
436+
expected: [
437+
new ObjectId('123456789012345678900014'),
438+
new ObjectId('123456789012345678900088'),
439+
],
440+
},
441+
],
442+
[
443+
'invalid values',
444+
{
445+
input: ['123', '123456789012345678900021'],
446+
expected: [new ObjectId('123456789012345678900021')],
447+
},
448+
],
449+
];
450+
451+
for (const testCase of testCases) {
452+
const [caseName, { input, expected }] = testCase;
453+
454+
test(`case ${caseName}`, () => {
455+
// Given
456+
ok(expected.length <= input.length);
457+
458+
// When
459+
const actual = getIds(input);
460+
461+
// Then
462+
deepStrictEqual(actual, expected);
463+
464+
const isEveryObjectId = actual.every((id) => id instanceof ObjectId);
465+
ok(isEveryObjectId);
466+
467+
const isEveryHexEquivalent = actual.every(
468+
(id, index) => id.toHexString() === expected[index].toHexString()
469+
);
470+
ok(isEveryHexEquivalent);
395471
});
396472
}
397473
});

src/utils.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,17 @@ export type RequireAtLeastOne<TObj, Keys extends keyof TObj = keyof TObj> = {
194194
}[Keys] &
195195
Pick<TObj, Exclude<keyof TObj, Keys>>;
196196

197-
export function getIds(ids: Set<string> | readonly (ObjectId | string)[]): ObjectId[] {
198-
return [...ids].map((id) => new ObjectId(id));
197+
export type ObjectIdConstructorParameter = ConstructorParameters<typeof ObjectId>[0];
198+
export function getIds(ids: Iterable<ObjectIdConstructorParameter>): ObjectId[] {
199+
return Array.from(ids).flatMap((id) => {
200+
try {
201+
return new ObjectId(id);
202+
} catch {
203+
// Intentionally empty
204+
}
205+
206+
return [];
207+
});
199208
}
200209

201210
/**

0 commit comments

Comments
 (0)