From 1b6ecd5b28fb793336ba667bdc8caa81d0e5d96f Mon Sep 17 00:00:00 2001 From: Poorshad Date: Sun, 10 Sep 2023 13:47:04 +0200 Subject: [PATCH 1/6] fix: :bug: pass document type to required function --- types/index.d.ts | 22 +++++++++++----------- types/schematypes.d.ts | 16 ++++++++-------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/types/index.d.ts b/types/index.d.ts index 840a3634e16..1bd4b0a7085 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -236,7 +236,7 @@ declare module 'mongoose' { /** * Create a new schema */ - constructor(definition?: SchemaDefinition> | DocType, options?: SchemaOptions | ResolveSchemaOptions); + constructor(definition?: SchemaDefinition, EnforcedDocType> | DocType, options?: SchemaOptions | ResolveSchemaOptions); /** Adds key path / schema type pairs to this schema. */ add(obj: SchemaDefinition> | Schema, prefix?: string): this; @@ -300,7 +300,7 @@ declare module 'mongoose' { methods: { [F in keyof TInstanceMethods]: TInstanceMethods[F] } & AnyObject; /** The original object passed to the schema constructor */ - obj: SchemaDefinition>; + obj: SchemaDefinition, EnforcedDocType>; /** Gets/sets schema paths. */ path>(path: string): ResultType; @@ -484,26 +484,26 @@ declare module 'mongoose' { ? DateSchemaDefinition : (Function | string); - export type SchemaDefinitionProperty = SchemaDefinitionWithBuiltInClass | - SchemaTypeOptions | + export type SchemaDefinitionProperty = SchemaDefinitionWithBuiltInClass | + SchemaTypeOptions | typeof SchemaType | Schema | Schema[] | - SchemaTypeOptions>[] | + SchemaTypeOptions, EnforcedDocType>[] | Function[] | - SchemaDefinition | - SchemaDefinition>[] | + SchemaDefinition | + SchemaDefinition, EnforcedDocType>[] | typeof Schema.Types.Mixed | - MixedSchemaTypeOptions; + MixedSchemaTypeOptions; - export type SchemaDefinition = T extends undefined + export type SchemaDefinition = T extends undefined ? { [path: string]: SchemaDefinitionProperty; } - : { [path in keyof T]?: SchemaDefinitionProperty; }; + : { [path in keyof T]?: SchemaDefinitionProperty; }; export type AnyArray = T[] | ReadonlyArray; export type ExtractMongooseArray = T extends Types.Array ? AnyArray> : T; - export interface MixedSchemaTypeOptions extends SchemaTypeOptions { + export interface MixedSchemaTypeOptions extends SchemaTypeOptions { type: typeof Schema.Types.Mixed; } diff --git a/types/schematypes.d.ts b/types/schematypes.d.ts index 5f7514a8e03..91620dbf7b8 100644 --- a/types/schematypes.d.ts +++ b/types/schematypes.d.ts @@ -39,7 +39,7 @@ declare module 'mongoose' { type DefaultType = T extends Schema.Types.Mixed ? any : Partial>; - class SchemaTypeOptions { + class SchemaTypeOptions { type?: T extends string ? StringSchemaDefinition : T extends number ? NumberSchemaDefinition : @@ -48,12 +48,12 @@ declare module 'mongoose' { T extends Map ? SchemaDefinition : T extends Buffer ? SchemaDefinition : T extends Types.ObjectId ? ObjectIdSchemaDefinition : - T extends Types.ObjectId[] ? AnyArray | AnyArray> : - T extends object[] ? (AnyArray> | AnyArray>> | AnyArray>>) : - T extends string[] ? AnyArray | AnyArray> : - T extends number[] ? AnyArray | AnyArray> : - T extends boolean[] ? AnyArray | AnyArray> : - T extends Function[] ? AnyArray | AnyArray>> : + T extends Types.ObjectId[] ? AnyArray | AnyArray> : + T extends object[] ? (AnyArray> | AnyArray>> | AnyArray, EnforcedDocType>>) : + T extends string[] ? AnyArray | AnyArray> : + T extends number[] ? AnyArray | AnyArray> : + T extends boolean[] ? AnyArray | AnyArray> : + T extends Function[] ? AnyArray | AnyArray, EnforcedDocType>> : T | typeof SchemaType | Schema | SchemaDefinition | Function | AnyArray; /** Defines a virtual with the given name that gets/sets this path. */ @@ -74,7 +74,7 @@ declare module 'mongoose' { * path cannot be set to a nullish value. If a function, Mongoose calls the * function and only checks for nullish values if the function returns a truthy value. */ - required?: boolean | (() => boolean) | [boolean, string] | [() => boolean, string]; + required?: boolean | ((doc: EnforcedDocType) => boolean) | [boolean, string] | [(doc: EnforcedDocType) => boolean, string]; /** * The default value for this path. If a function, Mongoose executes the function From 97dec3843ddb33ec7d1f7e7f98a7606b725601d8 Mon Sep 17 00:00:00 2001 From: Poorshad Date: Sun, 10 Sep 2023 18:27:39 +0200 Subject: [PATCH 2/6] type this in required function --- types/schematypes.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/schematypes.d.ts b/types/schematypes.d.ts index 91620dbf7b8..be425f39b21 100644 --- a/types/schematypes.d.ts +++ b/types/schematypes.d.ts @@ -74,7 +74,7 @@ declare module 'mongoose' { * path cannot be set to a nullish value. If a function, Mongoose calls the * function and only checks for nullish values if the function returns a truthy value. */ - required?: boolean | ((doc: EnforcedDocType) => boolean) | [boolean, string] | [(doc: EnforcedDocType) => boolean, string]; + required?: boolean | ((this: EnforcedDocType) => boolean) | [boolean, string] | [(this: EnforcedDocType) => boolean, string]; /** * The default value for this path. If a function, Mongoose executes the function From db299292813e019e21c43326c47187f0757b7546 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Sun, 10 Sep 2023 12:52:27 -0400 Subject: [PATCH 3/6] docs(model): add examples of using `diffIndexes()` to `syncIndexes()` and `diffIndexes()` api docs Fix #13771 --- lib/model.js | 20 ++++++++++++++++++-- test/types/schema.test.ts | 2 +- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/model.js b/lib/model.js index 320ea334153..dca25a92ef6 100644 --- a/lib/model.js +++ b/lib/model.js @@ -1451,6 +1451,17 @@ Model.createCollection = async function createCollection(options) { * // Will drop the 'age' index and create an index on `name` * await Customer.syncIndexes(); * + * You should be careful about running `syncIndexes()` on production applications under heavy load, + * because index builds are expensive operations, and unexpected index drops can lead to degraded + * performance. Before running `syncIndexes()`, you can use the [`diffIndexes()` function](#Model.diffIndexes()) + * to check what indexes `syncIndexes()` will drop and create. + * + * #### Example: + * + * const { toDrop, toCreate } = await Model.diffIndexes(); + * toDrop; // Array of strings containing names of indexes that `syncIndexes()` will drop + * toCreate; // Array of strings containing names of indexes that `syncIndexes()` will create + * * @param {Object} [options] options to pass to `ensureIndexes()` * @param {Boolean} [options.background=null] if specified, overrides each index's `background` property * @return {Promise} @@ -1483,9 +1494,14 @@ Model.syncIndexes = async function syncIndexes(options) { /** * Does a dry-run of `Model.syncIndexes()`, returning the indexes that `syncIndexes()` would drop and create if you were to run `syncIndexes()`. * + * #### Example: + * + * const { toDrop, toCreate } = await Model.diffIndexes(); + * toDrop; // Array of strings containing names of indexes that `syncIndexes()` will drop + * toCreate; // Array of strings containing names of indexes that `syncIndexes()` will create + * * @param {Object} [options] - * @returns {Promise} which contains an object, {toDrop, toCreate}, which - * are indexes that would be dropped in MongoDB and indexes that would be created in MongoDB. + * @returns {Promise<{ toDrop: string[], toCreate: string[] }>} contains the indexes that would be dropped in MongoDB and indexes that would be created in MongoDB. */ Model.diffIndexes = async function diffIndexes() { diff --git a/test/types/schema.test.ts b/test/types/schema.test.ts index b6726bfdc78..16f58ed938b 100644 --- a/test/types/schema.test.ts +++ b/test/types/schema.test.ts @@ -1217,4 +1217,4 @@ function gh13800() { expectType(this.lastName); expectError(this.someOtherField); }); -} \ No newline at end of file +} From e14e049d40fcc3c1579ac969247b72175a39ad97 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Sun, 10 Sep 2023 12:57:11 -0400 Subject: [PATCH 4/6] docs: quick fix for diffIndexes() api docs --- lib/model.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/model.js b/lib/model.js index dca25a92ef6..a6743f87d3d 100644 --- a/lib/model.js +++ b/lib/model.js @@ -1501,7 +1501,7 @@ Model.syncIndexes = async function syncIndexes(options) { * toCreate; // Array of strings containing names of indexes that `syncIndexes()` will create * * @param {Object} [options] - * @returns {Promise<{ toDrop: string[], toCreate: string[] }>} contains the indexes that would be dropped in MongoDB and indexes that would be created in MongoDB. + * @return {Promise} contains the indexes that would be dropped in MongoDB and indexes that would be created in MongoDB as `{ toDrop: string[], toCreate: string[] }`. */ Model.diffIndexes = async function diffIndexes() { From cfbccec08cd0699c777fcc80945eff691bcc8e75 Mon Sep 17 00:00:00 2001 From: Poorshad Date: Sun, 10 Sep 2023 20:01:32 +0200 Subject: [PATCH 5/6] add test of 13797 --- test/types/schema.test.ts | 9 ++++++++- types/schematypes.d.ts | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/test/types/schema.test.ts b/test/types/schema.test.ts index b6726bfdc78..51fb751457d 100644 --- a/test/types/schema.test.ts +++ b/test/types/schema.test.ts @@ -1217,4 +1217,11 @@ function gh13800() { expectType(this.lastName); expectError(this.someOtherField); }); -} \ No newline at end of file +} + +async function gh13797() { + interface IUser { + name: string; + } + const schema2 = new Schema({ name: { type: String, required: function () { expectType(this); return true } } }); +} diff --git a/types/schematypes.d.ts b/types/schematypes.d.ts index be425f39b21..4e494ba2848 100644 --- a/types/schematypes.d.ts +++ b/types/schematypes.d.ts @@ -39,7 +39,7 @@ declare module 'mongoose' { type DefaultType = T extends Schema.Types.Mixed ? any : Partial>; - class SchemaTypeOptions { + class SchemaTypeOptions { type?: T extends string ? StringSchemaDefinition : T extends number ? NumberSchemaDefinition : From 5c03f80484b4d5378ade3cb1d4afa6815fc3209c Mon Sep 17 00:00:00 2001 From: Poorshad Date: Sun, 10 Sep 2023 21:40:51 +0200 Subject: [PATCH 6/6] fix linting problems and add this type to default function --- test/types/schema.test.ts | 7 ++++++- types/schematypes.d.ts | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/test/types/schema.test.ts b/test/types/schema.test.ts index 51fb751457d..fc0204e2a71 100644 --- a/test/types/schema.test.ts +++ b/test/types/schema.test.ts @@ -1223,5 +1223,10 @@ async function gh13797() { interface IUser { name: string; } - const schema2 = new Schema({ name: { type: String, required: function () { expectType(this); return true } } }); + new Schema({ name: { type: String, required: function() { + expectType(this); return true; + } } }); + new Schema({ name: { type: String, default: function() { + expectType(this); return ''; + } } }); } diff --git a/types/schematypes.d.ts b/types/schematypes.d.ts index 4e494ba2848..088bc27c598 100644 --- a/types/schematypes.d.ts +++ b/types/schematypes.d.ts @@ -80,7 +80,7 @@ declare module 'mongoose' { * The default value for this path. If a function, Mongoose executes the function * and uses the return value as the default. */ - default?: DefaultType | ((this: any, doc: any) => DefaultType) | null; + default?: DefaultType | ((this: EnforcedDocType, doc: any) => DefaultType) | null; /** * The model that `populate()` should use if populating this path.