Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(NODE-4423): better type support for nested objects in query & update #3328

Merged
merged 7 commits into from
Jul 20, 2022
2 changes: 1 addition & 1 deletion src/mongo_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ export type NestedPaths<Type> = Type extends
: // child is an array, but it's not a recursive array
[Key, ...NestedPaths<Type[Key]>]
: // child is not structured the same as the parent
[Key, ...NestedPaths<Type[Key]>];
[Key, ...NestedPaths<Type[Key]>] | [Key];
}[Extract<keyof Type, string>]
: [];

Expand Down
3 changes: 3 additions & 0 deletions test/types/community/collection/filterQuery.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ expectNotType<Filter<PetModel>>({ 'regex.dotAll': true });
collectionT.find({ 'meta.updatedAt': new Date() });
collectionT.find({ 'meta.deep.nested.level': 123 });
collectionT.find({ meta: { deep: { nested: { level: 123 } } } }); // no impact on actual nesting
collectionT.find({ 'meta.deep': { nested: { level: 123 } } });
collectionT.find({ 'friends.0.name': 'John' });
collectionT.find({ 'playmates.0.name': 'John' });
// supports arrays with primitive types
Expand All @@ -203,6 +204,8 @@ expectNotType<Filter<PetModel>>({ 'friends.0.name': 123 });
expectNotType<Filter<PetModel>>({ 'playmates.0.name': 123 });
expectNotType<Filter<PetModel>>({ 'laps.foo': 'string' });
expectNotType<Filter<PetModel>>({ 'treats.0': 123 });
expectNotType<Filter<PetModel>>({ meta: { deep: { nested: { level: 'string' } } } });
expectNotType<Filter<PetModel>>({ 'meta.deep': { nested: { level: 'string' } } });

/// it should not accept wrong types for nested document array fields
expectError<Filter<PetModel>>({
Expand Down
16 changes: 16 additions & 0 deletions test/types/community/collection/updateX.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ interface SubTestModel {
field1: string;
field2?: string;
field3?: number;
nestedObject?: {
a: string;
b: string;
};
}

type FruitTypes = 'apple' | 'pear';
Expand All @@ -97,6 +101,7 @@ interface TestModel {
subInterfaceField: SubTestModel;
subInterfaceArray: SubTestModel[];
timestampField: Timestamp;
extras: Record<string, { id: string }>;
}
const collectionTType = db.collection<TestModel>('test.update');

Expand Down Expand Up @@ -201,9 +206,20 @@ expectAssignable<UpdateFilter<TestModel>>({
expectAssignable<UpdateFilter<TestModel>>({ $set: { doubleField: new Double(1.23) } });
expectAssignable<UpdateFilter<TestModel>>({ $set: { int32Field: new Int32(10) } });
expectAssignable<UpdateFilter<TestModel>>({ $set: { longField: Long.fromString('999') } });
expectAssignable<UpdateFilter<TestModel>>({ $set: { extras: { someExtras: { id: 'someId' } } } });
expectAssignable<UpdateFilter<TestModel>>({ $set: { stringField: 'a' } });
expectError(buildUpdateFilter({ $set: { stringField: 123 } }));
expectAssignable<UpdateFilter<TestModel>>({ $set: { 'subInterfaceField.field2': '2' } });
expectAssignable<UpdateFilter<TestModel>>({ $set: { 'subInterfaceField.nestedObject.a': '2' } });
expectAssignable<UpdateFilter<TestModel>>({
$set: { 'subInterfaceField.nestedObject': { a: '1', b: '2' } }
});
expectError<UpdateFilter<TestModel>>({
$set: { 'subInterfaceField.nestedObject': { a: '1' } }
});
coyotte508 marked this conversation as resolved.
Show resolved Hide resolved
expectError<UpdateFilter<TestModel>>({
$set: { 'subInterfaceField.nestedObject': { a: 1, 'b': '2' } }
dariakp marked this conversation as resolved.
Show resolved Hide resolved
});
expectError(buildUpdateFilter({ $set: { 'subInterfaceField.field2': 2 } }));
expectError(buildUpdateFilter({ $set: { 'unknown.field': null } }));
expectAssignable<UpdateFilter<TestModel>>({ $set: { 'numberArray.$': 40 } });
Expand Down