Skip to content

Commit

Permalink
perf(index.d.ts): simplify Schema typedef for query helpers and met…
Browse files Browse the repository at this point in the history
…hods to significantly reduce TS compiler overhead

Re: #10349
  • Loading branch information
vkarpov15 committed Dec 30, 2021
1 parent d723d8d commit 1141ec4
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 33 deletions.
53 changes: 24 additions & 29 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1258,7 +1258,6 @@ declare module 'mongoose' {
type SchemaPreOptions = { document?: boolean, query?: boolean };
type SchemaPostOptions = { document?: boolean, query?: boolean };

type ExtractQueryHelpers<M> = M extends Model<any, infer TQueryHelpers, any, any> ? TQueryHelpers : {};
type ExtractVirtuals<M> = M extends Model<any, any, any, infer TVirtuals> ? TVirtuals : {};

type IndexDirection = 1 | -1 | '2d' | '2dsphere' | 'geoHaystack' | 'hashed' | 'text';
Expand All @@ -1269,7 +1268,7 @@ declare module 'mongoose' {
type PostMiddlewareFunction<ThisType, ResType = any> = (this: ThisType, res: ResType, next: (err?: CallbackError) => void) => void | Promise<void>;
type ErrorHandlingMiddlewareFunction<ThisType, ResType = any> = (this: ThisType, err: NativeError, res: ResType, next: (err?: CallbackError) => void) => void;

class Schema<DocType = any, M = Model<DocType, any, any, any>, TInstanceMethods = any> extends events.EventEmitter {
class Schema<DocType = any, M = Model<DocType, any, any, any>, TInstanceMethods = any, TQueryHelpers = any> extends events.EventEmitter {
/**
* Create a new schema
*/
Expand Down Expand Up @@ -1316,11 +1315,11 @@ declare module 'mongoose' {
loadClass(model: Function, onlyVirtuals?: boolean): this;

/** Adds an instance method to documents constructed from Models compiled from this schema. */
method(name: string, fn: (this: HydratedDocument<DocType, TInstanceMethods, ExtractVirtuals<M>>, ...args: any[]) => any, opts?: any): this;
method(obj: { [name: string]: (this: HydratedDocument<DocType, TInstanceMethods, ExtractVirtuals<M>>, ...args: any[]) => any }): this;
method<Context = any>(name: string, fn: (this: Context, ...args: any[]) => any, opts?: any): this;
method(obj: Partial<TInstanceMethods>): this;

/** Object of currently defined methods on this schema. */
methods: { [name: string]: (this: HydratedDocument<DocType, TInstanceMethods, ExtractVirtuals<M>>, ...args: any[]) => any };
methods: { [F in keyof TInstanceMethods]: TInstanceMethods[F] };

/** The original object passed to the schema constructor */
obj: SchemaDefinition<SchemaDefinitionType<DocType>>;
Expand All @@ -1341,37 +1340,37 @@ declare module 'mongoose' {
plugin(fn: (schema: Schema<DocType>, opts?: any) => void, opts?: any): this;

/** Defines a post hook for the model. */
post<T = HydratedDocument<DocType, TInstanceMethods, ExtractVirtuals<M>>>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, fn: PostMiddlewareFunction<T>): this;
post<T = HydratedDocument<DocType, TInstanceMethods, ExtractVirtuals<M>>>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, options: SchemaPostOptions, fn: PostMiddlewareFunction<T>): this;
post<T extends Query<any, any> = Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, fn: PostMiddlewareFunction<T>): this;
post<T extends Query<any, any> = Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, options: SchemaPostOptions, fn: PostMiddlewareFunction<T>): this;
post<T extends Aggregate<any> = Aggregate<any>>(method: 'aggregate' | RegExp, fn: PostMiddlewareFunction<T, Array<any>>): this;
post<T extends Aggregate<any> = Aggregate<any>>(method: 'aggregate' | RegExp, options: SchemaPostOptions, fn: PostMiddlewareFunction<T, Array<any>>): this;
post<T extends Document>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, fn: PostMiddlewareFunction<T>): this;
post<T extends Document>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, options: SchemaPostOptions, fn: PostMiddlewareFunction<T>): this;
post<T extends Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, fn: PostMiddlewareFunction<T>): this;
post<T extends Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, options: SchemaPostOptions, fn: PostMiddlewareFunction<T>): this;
post<T extends Aggregate<any>>(method: 'aggregate' | RegExp, fn: PostMiddlewareFunction<T, Array<any>>): this;
post<T extends Aggregate<any>>(method: 'aggregate' | RegExp, options: SchemaPostOptions, fn: PostMiddlewareFunction<T, Array<any>>): this;
post<T = M>(method: 'insertMany' | RegExp, fn: PostMiddlewareFunction<T>): this;
post<T = M>(method: 'insertMany' | RegExp, options: SchemaPostOptions, fn: PostMiddlewareFunction<T>): this;

post<T = HydratedDocument<DocType, TInstanceMethods, ExtractVirtuals<M>>>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, fn: ErrorHandlingMiddlewareFunction<T>): this;
post<T = HydratedDocument<DocType, TInstanceMethods, ExtractVirtuals<M>>>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, options: SchemaPostOptions, fn: ErrorHandlingMiddlewareFunction<T>): this;
post<T extends Query<any, any> = Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, fn: ErrorHandlingMiddlewareFunction<T>): this;
post<T extends Query<any, any> = Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, options: SchemaPostOptions, fn: ErrorHandlingMiddlewareFunction<T>): this;
post<T extends Aggregate<any> = Aggregate<any>>(method: 'aggregate' | RegExp, fn: ErrorHandlingMiddlewareFunction<T, Array<any>>): this;
post<T extends Aggregate<any> = Aggregate<any>>(method: 'aggregate' | RegExp, options: SchemaPostOptions, fn: ErrorHandlingMiddlewareFunction<T, Array<any>>): this;
post<T extends Document>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, fn: ErrorHandlingMiddlewareFunction<T>): this;
post<T extends Document>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, options: SchemaPostOptions, fn: ErrorHandlingMiddlewareFunction<T>): this;
post<T extends Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, fn: ErrorHandlingMiddlewareFunction<T>): this;
post<T extends Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, options: SchemaPostOptions, fn: ErrorHandlingMiddlewareFunction<T>): this;
post<T extends Aggregate<any>>(method: 'aggregate' | RegExp, fn: ErrorHandlingMiddlewareFunction<T, Array<any>>): this;
post<T extends Aggregate<any>>(method: 'aggregate' | RegExp, options: SchemaPostOptions, fn: ErrorHandlingMiddlewareFunction<T, Array<any>>): this;
post<T = M>(method: 'insertMany' | RegExp, fn: ErrorHandlingMiddlewareFunction<T>): this;
post<T = M>(method: 'insertMany' | RegExp, options: SchemaPostOptions, fn: ErrorHandlingMiddlewareFunction<T>): this;

/** Defines a pre hook for the model. */
pre<T = HydratedDocument<DocType, TInstanceMethods, ExtractVirtuals<M>>>(method: 'save', fn: PreSaveMiddlewareFunction<T>): this;
pre<T = HydratedDocument<DocType, TInstanceMethods, ExtractVirtuals<M>>>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, fn: PreMiddlewareFunction<T>): this;
pre<T = HydratedDocument<DocType, TInstanceMethods, ExtractVirtuals<M>>>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, options: SchemaPreOptions, fn: PreMiddlewareFunction<T>): this;
pre<T extends Query<any, any> = Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, fn: PreMiddlewareFunction<T>): this;
pre<T extends Query<any, any> = Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, options: SchemaPreOptions, fn: PreMiddlewareFunction<T>): this;
pre<T extends Aggregate<any> = Aggregate<any>>(method: 'aggregate' | RegExp, fn: PreMiddlewareFunction<T>): this;
pre<T extends Aggregate<any> = Aggregate<any>>(method: 'aggregate' | RegExp, options: SchemaPreOptions, fn: PreMiddlewareFunction<T>): this;
pre<T extends Document>(method: 'save', fn: PreSaveMiddlewareFunction<T>): this;
pre<T extends Document>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, fn: PreMiddlewareFunction<T>): this;
pre<T extends Query<any, any>>(method: MongooseDocumentMiddleware | MongooseDocumentMiddleware[] | RegExp, options: SchemaPreOptions, fn: PreMiddlewareFunction<T>): this;
pre<T extends Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, fn: PreMiddlewareFunction<T>): this;
pre<T extends Query<any, any>>(method: MongooseQueryMiddleware | MongooseQueryMiddleware[] | string | RegExp, options: SchemaPreOptions, fn: PreMiddlewareFunction<T>): this;
pre<T extends Aggregate<any>>(method: 'aggregate' | RegExp, fn: PreMiddlewareFunction<T>): this;
pre<T extends Aggregate<any>>(method: 'aggregate' | RegExp, options: SchemaPreOptions, fn: PreMiddlewareFunction<T>): this;
pre<T = M>(method: 'insertMany' | RegExp, fn: (this: T, next: (err?: CallbackError) => void, docs: any | Array<any>) => void | Promise<void>): this;
pre<T = M>(method: 'insertMany' | RegExp, options: SchemaPreOptions, fn: (this: T, next: (err?: CallbackError) => void, docs: any | Array<any>) => void | Promise<void>): this;

/** Object of currently defined query helpers on this schema. */
query: { [name: string]: (this: QueryWithHelpers<any, DocType, ExtractQueryHelpers<M>>, ...args: any[]) => any };
query: TQueryHelpers;

/** Adds a method call to the queue. */
queue(name: string, args: any[]): this;
Expand Down Expand Up @@ -2710,10 +2709,6 @@ declare module 'mongoose' {
export type SchemaDefinitionType<T> = T extends Document ? Omit<T, Exclude<keyof Document, '_id' | 'id' | '__v'>> : T;
export type LeanDocument<T> = Omit<_LeanDocument<T>, Exclude<keyof Document, '_id' | 'id' | '__v'> | '$isSingleNested'>;

type DeepPartial<T> = {
[K in keyof T]?: DeepPartial<T[K]>;
}

export type LeanDocumentOrArray<T> = 0 extends (1 & T) ? T :
T extends unknown[] ? LeanDocument<T[number]>[] :
T extends Document ? LeanDocument<T> :
Expand Down
8 changes: 4 additions & 4 deletions test/typescript/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,25 @@ import { ObjectId } from 'mongodb';

interface QueryHelpers {
_byName(this: QueryWithHelpers<any, ITest, QueryHelpers>, name: string): QueryWithHelpers<Array<ITest>, ITest, QueryHelpers>;
byName(name: string): QueryWithHelpers<Array<ITest>, ITest, QueryHelpers>;
byName(this: QueryWithHelpers<any, ITest, QueryHelpers>, name: string): QueryWithHelpers<Array<ITest>, ITest, QueryHelpers>;
}

const childSchema: Schema = new Schema({ name: String });
const ChildModel = model<Child>('Child', childSchema);

const schema: Schema<ITest, Model<ITest, QueryHelpers>> = new Schema({
const schema: Schema<ITest, Model<ITest, QueryHelpers>, {}, QueryHelpers> = new Schema({
name: { type: 'String' },
tags: [String],
child: { type: 'ObjectId', ref: 'Child' },
docs: [{ _id: 'ObjectId', id: Number, tags: [String] }],
endDate: Date
});

schema.query._byName = function(name: string): QueryWithHelpers<any, ITest> {
schema.query._byName = function(name: string): QueryWithHelpers<any, ITest, QueryHelpers> {
return this.find({ name });
};

schema.query.byName = function(name: string): QueryWithHelpers<any, ITest> {
schema.query.byName = function(name: string): QueryWithHelpers<any, ITest, QueryHelpers> {
this.notAQueryHelper();
return this._byName(name);
};
Expand Down

0 comments on commit 1141ec4

Please sign in to comment.