From ea8482e0c438c22dd086745a6e0d37afc3069106 Mon Sep 17 00:00:00 2001 From: Poorshad Shaddel Date: Sat, 16 Sep 2023 17:08:01 +0000 Subject: [PATCH 01/10] Projection Type Should handle all exclusion and inclusions --- test/types/queries.test.ts | 14 +++++++++++++- test/types/schema.test.ts | 2 +- types/index.d.ts | 23 +++++++++++++++++++++-- types/query.d.ts | 4 ++-- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/test/types/queries.test.ts b/test/types/queries.test.ts index efca12618a5..985a33e758f 100644 --- a/test/types/queries.test.ts +++ b/test/types/queries.test.ts @@ -15,7 +15,8 @@ import { QuerySelector, InferSchemaType, ProjectionFields, - QueryOptions + QueryOptions, + ProjectionType } from 'mongoose'; import { ObjectId } from 'mongodb'; import { expectAssignable, expectError, expectNotAssignable, expectType } from 'tsd'; @@ -154,6 +155,17 @@ const p1: Record = Test.find().projection('age docs.id'); const p2: Record | null = Test.find().projection(); const p3: null = Test.find().projection(null); +expectError(Test.find({ }, { name: 'ss' })); // Only 0 and 1 are allowed +expectError(Test.find({ }, { name: 3 })); // Only 0 and 1 are allowed +expectError(Test.find({ }, { name: true, age: false, endDate: true, tags: 1 })); // Exclusion in a inclusion projection is not allowed +expectError(Test.find({ }, { name: true, age: false, endDate: true })); // Inclusion in a exclusion projection is not allowed +expectError(Test.find({ }, { name: false, age: false, tags: false, child: { name: false }, docs: { myId: false, id: true } })); // Inclusion in a exclusion projection is not allowed in nested objects and arrays +expectError(Test.find({ }, { tags: { something: 1 } })); // array of strings or numbers should only be allowed to be a boolean or 1 and 0 +Test.find({}, { name: true, age: true, endDate: true, tags: 1, child: { name: true }, docs: { myId: true, id: true } }); // This should be allowed +Test.find({}, { name: 1, age: 1, endDate: 1, tags: 1, child: { name: 1 }, docs: { myId: 1, id: 1 } }); // This should be allowed +Test.find({}, { _id: 0, name: 1, age: 1, endDate: 1, tags: 1, child: 1, docs: 1 }); // _id is an exception and should be allowed to be excluded +Test.find({}, { name: 0, age: 0, endDate: 0, tags: 0, child: 0, docs: 0 }); // This should be allowed +Test.find({}, { name: 0, age: 0, endDate: 0, tags: 0, child: { name: 0 }, docs: { myId: 0, id: 0 } }); // This should be allowed // Sorting Test.find().sort(); Test.find().sort('-name'); diff --git a/test/types/schema.test.ts b/test/types/schema.test.ts index fc0204e2a71..a4468a078ba 100644 --- a/test/types/schema.test.ts +++ b/test/types/schema.test.ts @@ -760,7 +760,7 @@ function pluginOptions() { } const schema = new Schema({}); - expectType>(schema.plugin(pluginFunction)); // test that chaining would be possible + expectType(schema.plugin(pluginFunction)); // test that chaining would be possible // could not add strict tests that the parameters are inferred correctly, because i dont know how this would be done in tsd diff --git a/types/index.d.ts b/types/index.d.ts index 1bd4b0a7085..e41684009aa 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -588,8 +588,27 @@ declare module 'mongoose' { export type ReturnsNewDoc = { new: true } | { returnOriginal: false } | { returnDocument: 'after' }; - export type ProjectionElementType = number | string; - export type ProjectionType = { [P in keyof T]?: ProjectionElementType } | AnyObject | string; + type Projector = T extends Array ? Projector : T extends object ? { + [K in keyof T]?: T[K] extends object ? Projector | Element : Element; + } : Element; + type InclusionProjection = Projector & { _id?: true | 1 | false | 0 }; + type ExclusionProjection = Projector & { _id?: false | 0 }; + + type NestedRequired = T extends Array + ? Array> + : T extends object + ? { + [K in keyof T]-?: NestedRequired; + } + : T; + type NestedPartial = T extends object + ? { + [K in keyof T]?: NestedPartial; + } + : T; + + // Bazi vaghta chizaye chert o pert pas midan + export type ProjectionType = NestedPartial>> | NestedPartial>> | string | string[] | ((...agrs: any) => any); export type SortValues = SortOrder; diff --git a/types/query.d.ts b/types/query.d.ts index 3963481a20b..4c03e66ae48 100644 --- a/types/query.d.ts +++ b/types/query.d.ts @@ -19,7 +19,7 @@ declare module 'mongoose' { type MongooseQueryOptions = Pick, 'populate' | 'lean' | 'strict' | 'sanitizeProjection' | 'sanitizeFilter'>; - type ProjectionFields = { [Key in keyof DocType]?: any } & Record; + type ProjectionFields = { [Key in keyof DocType]?: any } & Record; // Test type QueryWithHelpers = Query & THelpers; @@ -614,7 +614,7 @@ declare module 'mongoose' { >; /** Get/set the current projection (AKA fields). Pass `null` to remove the current projection. */ - projection(fields?: ProjectionFields | string): ProjectionFields; + projection(fields?: ProjectionFields | string): ProjectionFields; // projection(fields: null): null; projection(): ProjectionFields | null; From 083499586628777a1fe4f9a71e7c56f91f3b43c6 Mon Sep 17 00:00:00 2001 From: Poorshad Shaddel Date: Thu, 19 Oct 2023 14:48:07 +0000 Subject: [PATCH 02/10] fix tests --- test/types/queries.test.ts | 1 + types/index.d.ts | 24 ++++++++++++------------ types/query.d.ts | 4 ++-- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/test/types/queries.test.ts b/test/types/queries.test.ts index 985a33e758f..e18cec54aba 100644 --- a/test/types/queries.test.ts +++ b/test/types/queries.test.ts @@ -166,6 +166,7 @@ Test.find({}, { name: 1, age: 1, endDate: 1, tags: 1, child: { name: 1 }, docs: Test.find({}, { _id: 0, name: 1, age: 1, endDate: 1, tags: 1, child: 1, docs: 1 }); // _id is an exception and should be allowed to be excluded Test.find({}, { name: 0, age: 0, endDate: 0, tags: 0, child: 0, docs: 0 }); // This should be allowed Test.find({}, { name: 0, age: 0, endDate: 0, tags: 0, child: { name: 0 }, docs: { myId: 0, id: 0 } }); // This should be allowed +Test.find({}, { name: 1, age: 1, _id: 0 }); // This should be allowed since _id is an exception // Sorting Test.find().sort(); Test.find().sort('-name'); diff --git a/types/index.d.ts b/types/index.d.ts index e41684009aa..e22f4ce5d3d 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -591,24 +591,24 @@ declare module 'mongoose' { type Projector = T extends Array ? Projector : T extends object ? { [K in keyof T]?: T[K] extends object ? Projector | Element : Element; } : Element; - type InclusionProjection = Projector & { _id?: true | 1 | false | 0 }; - type ExclusionProjection = Projector & { _id?: false | 0 }; + type _IDType = { _id?: boolean | 1 | 0 }; + type InclusionProjection = NestedPartial, true | 1> & _IDType>; + type ExclusionProjection = NestedPartial, false | 0> & _IDType>; type NestedRequired = T extends Array - ? Array> - : T extends object - ? { - [K in keyof T]-?: NestedRequired; - } - : T; + ? Array> + : T extends object + ? { + [K in keyof T]-?: NestedRequired; + } + : T; type NestedPartial = T extends object - ? { + ? { [K in keyof T]?: NestedPartial; } - : T; + : T; - // Bazi vaghta chizaye chert o pert pas midan - export type ProjectionType = NestedPartial>> | NestedPartial>> | string | string[] | ((...agrs: any) => any); + export type ProjectionType = (InclusionProjection | ExclusionProjection) & AnyObject | string | ((...agrs: any) => any); export type SortValues = SortOrder; diff --git a/types/query.d.ts b/types/query.d.ts index 4c03e66ae48..afc508f87ab 100644 --- a/types/query.d.ts +++ b/types/query.d.ts @@ -95,7 +95,7 @@ declare module 'mongoose' { updatedAt?: boolean; } - interface QueryOptions extends + interface QueryOptions extends PopulateOption, SessionOption { arrayFilters?: { [key: string]: any }[]; @@ -122,7 +122,7 @@ declare module 'mongoose' { new?: boolean; overwriteDiscriminatorKey?: boolean; - projection?: ProjectionType; + projection?: ProjectionType; /** * if true, returns the raw result from the MongoDB driver */ From b9fb82352ee39f8ead31b6ce41fa1461ca229467 Mon Sep 17 00:00:00 2001 From: Poorshad Shaddel Date: Thu, 19 Oct 2023 14:51:27 +0000 Subject: [PATCH 03/10] remove comment --- types/query.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/query.d.ts b/types/query.d.ts index afc508f87ab..436fb6249e8 100644 --- a/types/query.d.ts +++ b/types/query.d.ts @@ -614,7 +614,7 @@ declare module 'mongoose' { >; /** Get/set the current projection (AKA fields). Pass `null` to remove the current projection. */ - projection(fields?: ProjectionFields | string): ProjectionFields; // + projection(fields?: ProjectionFields | string): ProjectionFields; projection(fields: null): null; projection(): ProjectionFields | null; From 981737e2e947e116572efa19ea03c52cf4f79d09 Mon Sep 17 00:00:00 2001 From: Poorshad Shaddel Date: Thu, 19 Oct 2023 15:06:51 +0000 Subject: [PATCH 04/10] remove test --- types/query.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/query.d.ts b/types/query.d.ts index 436fb6249e8..3cf4d37bc60 100644 --- a/types/query.d.ts +++ b/types/query.d.ts @@ -19,7 +19,7 @@ declare module 'mongoose' { type MongooseQueryOptions = Pick, 'populate' | 'lean' | 'strict' | 'sanitizeProjection' | 'sanitizeFilter'>; - type ProjectionFields = { [Key in keyof DocType]?: any } & Record; // Test + type ProjectionFields = { [Key in keyof DocType]?: any } & Record; type QueryWithHelpers = Query & THelpers; From 1838def80947883dd56853333caf2b942e5d626b Mon Sep 17 00:00:00 2001 From: Poorshad Shaddel Date: Fri, 20 Oct 2023 06:04:44 +0000 Subject: [PATCH 05/10] fields which are not in schema should be allowed --- test/types/queries.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/types/queries.test.ts b/test/types/queries.test.ts index e18cec54aba..db51392a13b 100644 --- a/test/types/queries.test.ts +++ b/test/types/queries.test.ts @@ -167,6 +167,7 @@ Test.find({}, { _id: 0, name: 1, age: 1, endDate: 1, tags: 1, child: 1, docs: 1 Test.find({}, { name: 0, age: 0, endDate: 0, tags: 0, child: 0, docs: 0 }); // This should be allowed Test.find({}, { name: 0, age: 0, endDate: 0, tags: 0, child: { name: 0 }, docs: { myId: 0, id: 0 } }); // This should be allowed Test.find({}, { name: 1, age: 1, _id: 0 }); // This should be allowed since _id is an exception +Test.find({}, { someOtherField: 1 }); // This should be allowed since it's not a field in the schema // Sorting Test.find().sort(); Test.find().sort('-name'); From 88d6cb564d806448ef5601367e59f49a5727caef Mon Sep 17 00:00:00 2001 From: Poorshad Shaddel Date: Fri, 20 Oct 2023 06:42:30 +0000 Subject: [PATCH 06/10] support $slice and $elemMatch --- test/types/queries.test.ts | 6 ++++++ types/index.d.ts | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/test/types/queries.test.ts b/test/types/queries.test.ts index db51392a13b..f9c517e5882 100644 --- a/test/types/queries.test.ts +++ b/test/types/queries.test.ts @@ -168,6 +168,12 @@ Test.find({}, { name: 0, age: 0, endDate: 0, tags: 0, child: 0, docs: 0 }); // T Test.find({}, { name: 0, age: 0, endDate: 0, tags: 0, child: { name: 0 }, docs: { myId: 0, id: 0 } }); // This should be allowed Test.find({}, { name: 1, age: 1, _id: 0 }); // This should be allowed since _id is an exception Test.find({}, { someOtherField: 1 }); // This should be allowed since it's not a field in the schema +expectError(Test.find({}, { name: { $slice: 1 }})); // $slice should only be allowed on arrays +Test.find({}, { tags: { $slice: 1 } }); // $slice should be allowed on arrays +Test.find({}, { tags: { $slice: [1, 2] } }); // $slice with the format of [ , ] should also be allowed on arrays +expectError(Test.find({}, { age: { $elemMatch: {} } })); // $elemMatch should not be allowed on non arrays +Test.find({}, { tags: { $elemMatch: {} } }); // $elemMatch should be allowed on arrays +expectError(Test.find({}, { tags: { $slice: 1, $elemMatch: {} } })); // $elemMatch and $slice should not be allowed together // Sorting Test.find().sort(); Test.find().sort('-name'); diff --git a/types/index.d.ts b/types/index.d.ts index e22f4ce5d3d..4243227dc93 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -588,7 +588,8 @@ declare module 'mongoose' { export type ReturnsNewDoc = { new: true } | { returnOriginal: false } | { returnDocument: 'after' }; - type Projector = T extends Array ? Projector : T extends object ? { + type ArrayOperators = { $slice: number | [number, number], $elemMatch?: undefined } | { $elemMatch: object, $slice?: undefined } + type Projector = T extends Array ? Projector | ArrayOperators : T extends object ? { [K in keyof T]?: T[K] extends object ? Projector | Element : Element; } : Element; type _IDType = { _id?: boolean | 1 | 0 }; From e282b6e8a9bebc3928caa852e815c1442ae67115 Mon Sep 17 00:00:00 2001 From: Poorshad Shaddel Date: Fri, 20 Oct 2023 21:43:24 +0000 Subject: [PATCH 07/10] $slice and $elemMatch should be allowed with inclusion and exclusion queries --- test/types/queries.test.ts | 6 +++++- types/index.d.ts | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/test/types/queries.test.ts b/test/types/queries.test.ts index f9c517e5882..cfdecf3b0f0 100644 --- a/test/types/queries.test.ts +++ b/test/types/queries.test.ts @@ -168,12 +168,16 @@ Test.find({}, { name: 0, age: 0, endDate: 0, tags: 0, child: 0, docs: 0 }); // T Test.find({}, { name: 0, age: 0, endDate: 0, tags: 0, child: { name: 0 }, docs: { myId: 0, id: 0 } }); // This should be allowed Test.find({}, { name: 1, age: 1, _id: 0 }); // This should be allowed since _id is an exception Test.find({}, { someOtherField: 1 }); // This should be allowed since it's not a field in the schema -expectError(Test.find({}, { name: { $slice: 1 }})); // $slice should only be allowed on arrays +expectError(Test.find({}, { name: { $slice: 1 } })); // $slice should only be allowed on arrays Test.find({}, { tags: { $slice: 1 } }); // $slice should be allowed on arrays Test.find({}, { tags: { $slice: [1, 2] } }); // $slice with the format of [ , ] should also be allowed on arrays expectError(Test.find({}, { age: { $elemMatch: {} } })); // $elemMatch should not be allowed on non arrays Test.find({}, { tags: { $elemMatch: {} } }); // $elemMatch should be allowed on arrays expectError(Test.find({}, { tags: { $slice: 1, $elemMatch: {} } })); // $elemMatch and $slice should not be allowed together +Test.find({}, { age: 1, tags: { $slice: 5 } }); // $slice should be allowed in inclusion projection +Test.find({}, { age: 0, tags: { $slice: 5 } }); // $slice should be allowed in exclusion projection +Test.find({}, { age: 1, tags: { $elemMatch: {} } }); // $elemMatch should be allowed in inclusion projection +Test.find({}, { age: 0, tags: { $elemMatch: {} } }); // $elemMatch should be allowed in exclusion projection // Sorting Test.find().sort(); Test.find().sort('-name'); diff --git a/types/index.d.ts b/types/index.d.ts index 4243227dc93..efa023efa44 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -588,7 +588,7 @@ declare module 'mongoose' { export type ReturnsNewDoc = { new: true } | { returnOriginal: false } | { returnDocument: 'after' }; - type ArrayOperators = { $slice: number | [number, number], $elemMatch?: undefined } | { $elemMatch: object, $slice?: undefined } + type ArrayOperators = { $slice: number | [number, number], $elemMatch?: undefined } | { $elemMatch: object, $slice?: undefined }; type Projector = T extends Array ? Projector | ArrayOperators : T extends object ? { [K in keyof T]?: T[K] extends object ? Projector | Element : Element; } : Element; From 5755e127b0b7c44ace8f853e028da8602da6d287 Mon Sep 17 00:00:00 2001 From: Poorshad Shaddel Date: Wed, 25 Oct 2023 14:04:35 +0000 Subject: [PATCH 08/10] feat: :sparkles: support dot notation and a combination of object and dot notation projection --- test/types/queries.test.ts | 10 +++++ types/index.d.ts | 91 +++++++++++++++++++++++++++++++++----- 2 files changed, 89 insertions(+), 12 deletions(-) diff --git a/test/types/queries.test.ts b/test/types/queries.test.ts index cfdecf3b0f0..51eccdc1e1e 100644 --- a/test/types/queries.test.ts +++ b/test/types/queries.test.ts @@ -55,6 +55,9 @@ interface ISubdoc { myId?: Types.ObjectId; id?: number; tags?: string[]; + profiles: { + name?: string + } } interface ITest { @@ -178,6 +181,13 @@ Test.find({}, { age: 1, tags: { $slice: 5 } }); // $slice should be allowed in i Test.find({}, { age: 0, tags: { $slice: 5 } }); // $slice should be allowed in exclusion projection Test.find({}, { age: 1, tags: { $elemMatch: {} } }); // $elemMatch should be allowed in inclusion projection Test.find({}, { age: 0, tags: { $elemMatch: {} } }); // $elemMatch should be allowed in exclusion projection +expectError(Test.find({}, { 'docs.id': 11 })); // Dot notation should be allowed and does not accept any +expectError(Test.find({}, { docs: { id: '1' } })); // Dot notation should be able to use a combination with objects +Test.find({}, { docs: { id: false } }); // Dot notation should be allowed with valid values - should correctly handle arrays +Test.find({}, { docs: { id: true } }); // Dot notation should be allowed with valid values - should correctly handle arrays +Test.find({}, { child: 1 }); // Dot notation should be able to use a combination with objects +Test.find({}, { 'docs.profiles': { name: 1 } }); // should support a combination of dot notation and objects +expectError(Test.find({}, { 'docs.profiles': { name: 'aa' } })); // should support a combination of dot notation and objects // Sorting Test.find().sort(); Test.find().sort('-name'); diff --git a/types/index.d.ts b/types/index.d.ts index efa023efa44..ac53293c879 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -588,13 +588,18 @@ declare module 'mongoose' { export type ReturnsNewDoc = { new: true } | { returnOriginal: false } | { returnDocument: 'after' }; - type ArrayOperators = { $slice: number | [number, number], $elemMatch?: undefined } | { $elemMatch: object, $slice?: undefined }; - type Projector = T extends Array ? Projector | ArrayOperators : T extends object ? { - [K in keyof T]?: T[K] extends object ? Projector | Element : Element; - } : Element; + type ArrayOperators = { $slice: number | [number, number]; $elemMatch?: undefined } | { $elemMatch: object; $slice?: undefined }; + type Projector = T extends Array + ? Projector | ArrayOperators + : T extends object + ? { + [K in keyof T]?: T[K] extends object ? Projector | Element : Element; + } + : Element; type _IDType = { _id?: boolean | 1 | 0 }; - type InclusionProjection = NestedPartial, true | 1> & _IDType>; - type ExclusionProjection = NestedPartial, false | 0> & _IDType>; + type InclusionProjection = NestedPartial>, true | 1> & _IDType>; + type ExclusionProjection = NestedPartial>, false | 0> & _IDType>; + type ProjectionUnion = InclusionProjection | ExclusionProjection; type NestedRequired = T extends Array ? Array> @@ -603,14 +608,76 @@ declare module 'mongoose' { [K in keyof T]-?: NestedRequired; } : T; - type NestedPartial = T extends object - ? { - [K in keyof T]?: NestedPartial; - } - : T; + type NestedPartial = T extends Array + ? Array> + : T extends object + ? { + [K in keyof T]?: NestedPartial; + } + : T; + + /** https://stackoverflow.com/questions/58434389/typescript-deep-keyof-of-a-nested-object/58436959#58436959 for dot nested implementation it is used and then modified */ + type DotPrefix = T extends '' ? '' : `.${T}`; - export type ProjectionType = (InclusionProjection | ExclusionProjection) & AnyObject | string | ((...agrs: any) => any); + /** https://stackoverflow.com/questions/75419012/how-do-i-limit-the-level-of-nesting-on-a-recursive-type-in-typescript */ + type Length = T extends { length: infer L } ? L : never; + type BuildTuple = T extends { length: L } ? T : BuildTuple; + type MinusOne = BuildTuple extends [...infer U, unknown] ? Length : never; + + /** + * Generates a union from dot path in object + * We have to give it the Depth to prevent infinite recursion and also prevent slow compilation when the object is too much nested + */ + type DotNestedKeys = ( + Depth extends 0 + ? never + : T extends object + ? { [K in Exclude]: `${K}` | `${K}${DotPrefix>>}` }[Exclude] + : '' + ) extends infer D + ? Extract + : never; + type FindDottedPathType = Path extends `${infer K}.${infer R}` + ? K extends keyof T + ? FindDottedPathType ? U : T[K], R> + : never + : Path extends keyof T + ? T[Path] + : never; + type ExtractNestedArrayElement = T extends (infer U)[] + ? ExtractNestedArrayElement + : T extends object + ? { [K in keyof T]: ExtractNestedArrayElement } + : T; + type DotnotationMaximumDepth = 4; + /** + * Create dot path for nested objects + * It creates dot notation for arrays similar to mongodb. For example { a: { c: { b: number}[] }[] } => 'a.c.b': number, 'a.c': { b: number }[] + */ + type DotKeys = { + [key in DotNestedKeys, DotnotationMaximumDepth>]?: FindDottedPathType, key>; + }; + /** + * This types are equivalent to primary types + */ + type SpecialTypes = DateSchemaDefinition | Date | DateConstructor | Types.Buffer | Types.Decimal128 | Types.Buffer | BooleanSchemaDefinition | NumberSchemaDefinition; + type Replacer = T extends SpecialTypes ? string : T; + /** + * Date type is like a Primitiv type for us and we do not want to project something inside it. + * ObjectId is also similar. + */ + type ReplaceSpecialTypes = T extends SpecialTypes + ? string + : T extends Array + ? Array> + : T extends object + ? { + [K in keyof T]?: ReplaceSpecialTypes; + } + : Replacer; + + export type ProjectionType = (ProjectionUnion> & AnyObject) | string | ((...agrs: any) => any); export type SortValues = SortOrder; export type SortOrder = -1 | 1 | 'asc' | 'ascending' | 'desc' | 'descending'; From 0e854e7ef664b238cb6971af7d03fa1ad79c6bbe Mon Sep 17 00:00:00 2001 From: Poorshad Shaddel Date: Fri, 27 Oct 2023 14:31:05 +0000 Subject: [PATCH 09/10] should not project methods inside Date type --- test/types/queries.test.ts | 1 + types/index.d.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/test/types/queries.test.ts b/test/types/queries.test.ts index 51eccdc1e1e..6ccc945c903 100644 --- a/test/types/queries.test.ts +++ b/test/types/queries.test.ts @@ -188,6 +188,7 @@ Test.find({}, { docs: { id: true } }); // Dot notation should be allowed with va Test.find({}, { child: 1 }); // Dot notation should be able to use a combination with objects Test.find({}, { 'docs.profiles': { name: 1 } }); // should support a combination of dot notation and objects expectError(Test.find({}, { 'docs.profiles': { name: 'aa' } })); // should support a combination of dot notation and objects +expectError(Test.find({}, { endDate: { toString: 1 } })); // Sorting Test.find().sort(); Test.find().sort('-name'); diff --git a/types/index.d.ts b/types/index.d.ts index ac53293c879..a714f6f6f7e 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -661,7 +661,7 @@ declare module 'mongoose' { /** * This types are equivalent to primary types */ - type SpecialTypes = DateSchemaDefinition | Date | DateConstructor | Types.Buffer | Types.Decimal128 | Types.Buffer | BooleanSchemaDefinition | NumberSchemaDefinition; + type SpecialTypes = DateSchemaDefinition | Date | globalThis.Date | DateConstructor | Types.Buffer | Types.Decimal128 | Types.Buffer | BooleanSchemaDefinition | NumberSchemaDefinition; type Replacer = T extends SpecialTypes ? string : T; /** * Date type is like a Primitiv type for us and we do not want to project something inside it. From 5938d6bc955ddc490ae9527d891aa172516a7399 Mon Sep 17 00:00:00 2001 From: Poorshad Shaddel Date: Fri, 27 Oct 2023 14:34:27 +0000 Subject: [PATCH 10/10] use replacer type --- types/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/index.d.ts b/types/index.d.ts index a714f6f6f7e..ca62cf7172a 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -668,7 +668,7 @@ declare module 'mongoose' { * ObjectId is also similar. */ type ReplaceSpecialTypes = T extends SpecialTypes - ? string + ? Replacer : T extends Array ? Array> : T extends object