Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 24 additions & 19 deletions test/types/queries.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ const schema: Schema<ITest, Model<ITest, QueryHelpers>, {}, QueryHelpers> = new
endDate: Date
});

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

schema.query.byName = function(name: string): QueryWithHelpers<ITest[], ITest, QueryHelpers> {
schema.query.byName = function (name: string): QueryWithHelpers<ITest[], ITest, QueryHelpers> {
expectError(this.notAQueryHelper());
return this._byName(name);
};
Expand Down Expand Up @@ -156,12 +156,12 @@ const p1: Record<string, number> = Test.find().projection('age docs.id');
const p2: Record<string, number> | 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: 'ss' })); // Only 0 and 1 are allowed
Test.find({}, { name: 3 });
Test.find({}, { name: true, age: false, endDate: true, tags: 1 });
Test.find({}, { name: true, age: false, endDate: true });
Test.find({}, { name: false, age: false, tags: false, child: { name: false }, docs: { myId: false, id: true } });
expectError(Test.find({ }, { tags: { something: 1 } })); // array of strings or numbers should only be allowed to be a boolean or 1 and 0
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
Expand Down Expand Up @@ -378,7 +378,7 @@ function gh14397() {
}

function gh12091() {
interface IUser{
interface IUser {
friendsNames: string[];
}
const userSchema = new Schema<IUser>({
Expand Down Expand Up @@ -412,19 +412,19 @@ async function gh12342_manual() {

interface ProjectQueryHelpers {
byName(name: string): QueryWithHelpers<
HydratedDocument<Project>[],
HydratedDocument<Project>,
ProjectQueryHelpers
HydratedDocument<Project>[],
HydratedDocument<Project>,
ProjectQueryHelpers
>
}

type ProjectModelType = Model<Project, ProjectQueryHelpers>;

const ProjectSchema = new Schema<
Project,
Model<Project, ProjectQueryHelpers>,
{},
ProjectQueryHelpers
Project,
Model<Project, ProjectQueryHelpers>,
{},
ProjectQueryHelpers
>({
name: String,
stars: Number
Expand Down Expand Up @@ -515,9 +515,9 @@ async function gh13142() {
projection: Projection,
options: Options
): Promise<
Options['lean'] extends true
? Pick<Blog, Extract<keyof Projection, keyof Blog>> | null
: HydratedDocument<Pick<Blog, Extract<keyof Projection, keyof Blog>>> | null
Options['lean'] extends true
? Pick<Blog, Extract<keyof Projection, keyof Blog>> | null
: HydratedDocument<Pick<Blog, Extract<keyof Projection, keyof Blog>>> | null
> {
return this.blogModel.findOne(filter, projection, options);
}
Expand Down Expand Up @@ -588,15 +588,15 @@ function gh14190() {
);
expectAssignable<
ModifyResult<ReturnType<(typeof UserModel)['hydrate']>>
>(res);
>(res);

const res2 = await UserModel.find().findByIdAndDelete(
'0'.repeat(24),
{ includeResultMetadata: true }
);
expectAssignable<
ModifyResult<ReturnType<(typeof UserModel)['hydrate']>>
>(res2);
>(res2);
}

function mongooseQueryOptions() {
Expand Down Expand Up @@ -717,7 +717,7 @@ function gh14510() {
// From https://stackoverflow.com/questions/56505560/how-to-fix-ts2322-could-be-instantiated-with-a-different-subtype-of-constraint:
// "Never assign a concrete type to a generic type parameter, consider it as read-only!"
// This function is generally something you shouldn't do in TypeScript, can work around it with `as` though.
function findById<ModelType extends {_id: Types.ObjectId | string}>(model: Model<ModelType>, _id: Types.ObjectId | string) {
function findById<ModelType extends { _id: Types.ObjectId | string }>(model: Model<ModelType>, _id: Types.ObjectId | string) {
return model.find({ _id: _id } as QueryFilter<ModelType>);
}
}
Expand Down Expand Up @@ -863,5 +863,10 @@ async function gh15786() {
}

const schema = new Schema<IDoc, Model<IDoc>, {}, {}, {}, DocStatics>({});
schema.static({ m1() {} } as DocStatics);
schema.static({ m1() { } } as DocStatics);
}

function gh15854() {
const filter = { foo: 'hi' } as mongoose.QueryFilter<{ foo: string }>;
filter.foo; // Should not error: Property 'foo' does not exist on type '_QueryFilter<{ foo: string; }>'
}
88 changes: 44 additions & 44 deletions types/query.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ declare module 'mongoose' {
type QueryTypeCasting<T> = T extends string
? StringQueryTypeCasting
: T extends Types.ObjectId
? ObjectIdQueryTypeCasting
: T extends Types.UUID
? UUIDQueryTypeCasting
: T extends Buffer
? BufferQueryCasting
: T extends NativeDate
? DateQueryTypeCasting
: T;
? ObjectIdQueryTypeCasting
: T extends Types.UUID
? UUIDQueryTypeCasting
: T extends Buffer
? BufferQueryCasting
: T extends NativeDate
? DateQueryTypeCasting
: T;

export type ApplyBasicQueryCasting<T> = QueryTypeCasting<T> | QueryTypeCasting<T[]> | (T extends (infer U)[] ? QueryTypeCasting<U> : T) | null;

type _QueryFilter<T> = ({ [P in keyof T]?: mongodb.Condition<ApplyBasicQueryCasting<T[P]>>; } & mongodb.RootFilterOperators<{ [P in keyof T]?: ApplyBasicQueryCasting<T[P]>; }>);
type _QueryFilter<T> = ({ [P in keyof T]?: mongodb.Condition<ApplyBasicQueryCasting<T[P]>>; } & mongodb.RootFilterOperators<{ [P in keyof T]?: ApplyBasicQueryCasting<T[P]>; }> & Record<string, any>);
type QueryFilter<T> = IsItRecordAndNotAny<T> extends true ? _QueryFilter<WithLevel1NestedPaths<T>> : _QueryFilter<Record<string, any>>;

type MongooseBaseQueryOptionKeys =
Expand Down Expand Up @@ -177,14 +177,14 @@ declare module 'mongoose' {

type MergePopulatePaths<RawDocType, ResultType, QueryOp, Paths, TQueryHelpers, TDocOverrides = Record<string, never>> = QueryOp extends QueryOpThatReturnsDocument
? ResultType extends null
? ResultType
: ResultType extends (infer U)[]
? U extends Document
? HydratedDocument<MergeType<RawDocType, Paths>, TDocOverrides, TQueryHelpers>[]
: (MergeType<U, Paths>)[]
: ResultType extends Document
? HydratedDocument<MergeType<RawDocType, Paths>, TDocOverrides, TQueryHelpers>
: MergeType<ResultType, Paths>
? ResultType
: ResultType extends (infer U)[]
? U extends Document
? HydratedDocument<MergeType<RawDocType, Paths>, TDocOverrides, TQueryHelpers>[]
: (MergeType<U, Paths>)[]
: ResultType extends Document
? HydratedDocument<MergeType<RawDocType, Paths>, TDocOverrides, TQueryHelpers>
: MergeType<ResultType, Paths>
: MergeType<ResultType, Paths>;

class Query<ResultType, DocType, THelpers = {}, RawDocType = unknown, QueryOp = 'find', TDocOverrides = Record<string, never>> implements SessionOperation {
Expand Down Expand Up @@ -350,8 +350,8 @@ declare module 'mongoose' {
): QueryWithHelpers<
Array<
DocKey extends keyof WithLevel1NestedPaths<DocType>
? WithoutUndefined<Unpacked<WithLevel1NestedPaths<DocType>[DocKey]>>
: ResultType
? WithoutUndefined<Unpacked<WithLevel1NestedPaths<DocType>[DocKey]>>
: ResultType
>,
DocType,
THelpers,
Expand All @@ -366,8 +366,8 @@ declare module 'mongoose' {
): QueryWithHelpers<
Array<
DocKey extends keyof WithLevel1NestedPaths<DocType>
? WithoutUndefined<Unpacked<WithLevel1NestedPaths<DocType>[DocKey]>>
: ResultType
? WithoutUndefined<Unpacked<WithLevel1NestedPaths<DocType>[DocKey]>>
: ResultType
>,
DocType,
THelpers,
Expand Down Expand Up @@ -561,62 +561,62 @@ declare module 'mongoose' {
/** Sets the lean option. */
lean(): QueryWithHelpers<
ResultType extends null
? GetLeanResultType<RawDocType, ResultType, QueryOp> | null
: GetLeanResultType<RawDocType, ResultType, QueryOp>,
? GetLeanResultType<RawDocType, ResultType, QueryOp> | null
: GetLeanResultType<RawDocType, ResultType, QueryOp>,
DocType,
THelpers,
RawDocType,
QueryOp,
TDocOverrides
>;
>;
lean(
val: true | LeanOptions
): QueryWithHelpers<
ResultType extends null
? GetLeanResultType<RawDocType, ResultType, QueryOp> | null
: GetLeanResultType<RawDocType, ResultType, QueryOp>,
? GetLeanResultType<RawDocType, ResultType, QueryOp> | null
: GetLeanResultType<RawDocType, ResultType, QueryOp>,
DocType,
THelpers,
RawDocType,
QueryOp,
TDocOverrides
>;
>;
lean(
val: false
): QueryWithHelpers<
ResultType extends AnyArray<any>
? DocType[]
: ResultType extends null
? DocType | null
: DocType,
? DocType[]
: ResultType extends null
? DocType | null
: DocType,
DocType,
THelpers,
RawDocType,
QueryOp,
TDocOverrides
>;
>;
lean<LeanResultType = RawDocType>(): QueryWithHelpers<
ResultType extends null
? LeanResultType | null
: LeanResultType,
? LeanResultType | null
: LeanResultType,
DocType,
THelpers,
RawDocType,
QueryOp,
TDocOverrides
>;
>;
lean<LeanResultType = RawDocType>(
val: boolean | LeanOptions
): QueryWithHelpers<
ResultType extends null
? LeanResultType | null
: LeanResultType,
? LeanResultType | null
: LeanResultType,
DocType,
THelpers,
RawDocType,
QueryOp,
TDocOverrides
>;
>;

/** Specifies the maximum number of documents the query will return. */
limit(val: number): this;
Expand Down Expand Up @@ -797,12 +797,12 @@ declare module 'mongoose' {
{},
ResultType,
ResultType extends any[]
? ResultType extends HydratedDocument<any>[]
? HydratedDocument<RawDocTypeOverride>[]
: RawDocTypeOverride[]
: (ResultType extends HydratedDocument<any>
? HydratedDocument<RawDocTypeOverride>
: RawDocTypeOverride) | (null extends ResultType ? null : never)
? ResultType extends HydratedDocument<any>[]
? HydratedDocument<RawDocTypeOverride>[]
: RawDocTypeOverride[]
: (ResultType extends HydratedDocument<any>
? HydratedDocument<RawDocTypeOverride>
: RawDocTypeOverride) | (null extends ResultType ? null : never)
>,
DocType,
THelpers,
Expand Down