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
4 changes: 2 additions & 2 deletions test/types/populate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ ParentModel.
findOne({}).
populate<{ child: Document<ObjectId> & Child }>('child').
orFail().
then((doc: Document<ObjectId, {}, Parent> & Parent) => {
then((doc) => {
const child = doc.child;
if (child == null || child instanceof ObjectId) {
throw new Error('should be populated');
} else {
useChildDoc(child);
}
const lean = doc.toObject<typeof doc>();
const lean = doc.toObject<mongoose.MergeType<Parent, { Child: Child }>>();
const leanChild = lean.child;
if (leanChild == null || leanChild instanceof ObjectId) {
throw new Error('should be populated');
Expand Down
7 changes: 3 additions & 4 deletions test/types/queries.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import {
Condition,
HydratedDocument,
Schema,
model,
Expand All @@ -11,14 +10,14 @@ import {
PopulatedDoc,
UpdateQuery,
UpdateQueryKnownOnly,
QuerySelector,
InferRawDocType,
InferSchemaType,
ProjectionFields,
QueryOptions,
ProjectionType,
QueryFilter
} from 'mongoose';
import mongodb from 'mongodb';
import mongoose from 'mongoose';
import { ModifyResult, ObjectId } from 'mongodb';
import { expectAssignable, expectError, expectNotAssignable, expectType } from 'tsd';
Expand Down Expand Up @@ -352,7 +351,7 @@ function autoTypedQuery() {
function gh11964() {
class Repository<T extends { id: string }> {
find(id: string) {
const idCondition: Condition<T['id']> = id as Condition<T['id']>;
const idCondition: mongodb.Condition<T['id']> = id as mongodb.Condition<T['id']>;

// `as` is necessary because `T` can be `{ id: never }`,
// so we need to explicitly coerce
Expand All @@ -362,7 +361,7 @@ function gh11964() {
}

function gh14397() {
type Condition<T> = T | QuerySelector<T>; // redefined here because it's not exported by mongoose
type Condition<T> = mongodb.Condition<T>; // redefined here because it's not exported by mongoose

type WithId<T extends object> = T & { id: string };

Expand Down
73 changes: 2 additions & 71 deletions types/query.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ declare module 'mongoose' {
? BufferQueryCasting
: T;

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

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

/**
* Filter query to select the documents that match the query
Expand All @@ -26,7 +24,7 @@ declare module 'mongoose' {
* { age: { $gte: 30 } }
* ```
*/
type _QueryFilter<T> = { [P in keyof T]?: Condition<T[P]>; } & RootQuerySelector<T>
type _QueryFilter<T> = ({ [P in keyof T]?: mongodb.Condition<ApplyBasicQueryCasting<QueryTypeCasting<T[P]>>>; } & mongodb.RootFilterOperators<{ [P in keyof T]?: ApplyBasicQueryCasting<QueryTypeCasting<T[P]>>; }>) | Query<any, any>;
type QueryFilter<T> = _QueryFilter<WithLevel1NestedPaths<T>>;

type MongooseBaseQueryOptionKeys =
Expand Down Expand Up @@ -60,73 +58,6 @@ declare module 'mongoose' {
TDocOverrides = Record<string, never>
> = Query<ResultType, DocType, THelpers, RawDocType, QueryOp, TDocOverrides> & THelpers;

type QuerySelector<T> = {
// Comparison
$eq?: T | null | undefined;
$gt?: T;
$gte?: T;
$in?: [T] extends AnyArray<any> ? Unpacked<T>[] : T[];
$lt?: T;
$lte?: T;
$ne?: T | null | undefined;
$nin?: [T] extends AnyArray<any> ? Unpacked<T>[] : T[];
// Logical
$not?: T extends string ? QuerySelector<T> | RegExp : QuerySelector<T>;
// Element
/**
* When `true`, `$exists` matches the documents that contain the field,
* including documents where the field value is null.
*/
$exists?: boolean;
$type?: string | number;
// Evaluation
$expr?: any;
$jsonSchema?: any;
$mod?: T extends number ? [number, number] : never;
$regex?: T extends string ? RegExp | string : never;
$options?: T extends string ? string : never;
// Geospatial
// TODO: define better types for geo queries
$geoIntersects?: { $geometry: object };
$geoWithin?: object;
$near?: object;
$nearSphere?: object;
$maxDistance?: number;
// Array
// TODO: define better types for $all and $elemMatch
$all?: T extends AnyArray<any> ? any[] : never;
$elemMatch?: T extends AnyArray<any> ? object : never;
$size?: T extends AnyArray<any> ? number : never;
// Bitwise
$bitsAllClear?: number | mongodb.Binary | number[];
$bitsAllSet?: number | mongodb.Binary | number[];
$bitsAnyClear?: number | mongodb.Binary | number[];
$bitsAnySet?: number | mongodb.Binary | number[];
};

type RootQuerySelector<T> = {
/** @see https://www.mongodb.com/docs/manual/reference/operator/query/and/#op._S_and */
$and?: Array<QueryFilter<T>>;
/** @see https://www.mongodb.com/docs/manual/reference/operator/query/nor/#op._S_nor */
$nor?: Array<QueryFilter<T>>;
/** @see https://www.mongodb.com/docs/manual/reference/operator/query/or/#op._S_or */
$or?: Array<QueryFilter<T>>;
/** @see https://www.mongodb.com/docs/manual/reference/operator/query/text */
$text?: {
$search: string;
$language?: string;
$caseSensitive?: boolean;
$diacriticSensitive?: boolean;
};
/** @see https://www.mongodb.com/docs/manual/reference/operator/query/where/#op._S_where */
$where?: string | Function;
/** @see https://www.mongodb.com/docs/manual/reference/operator/query/comment/#op._S_comment */
$comment?: string;
$expr?: Record<string, any>;
// this will mark all unrecognized properties as any (including nested queries)
[key: string]: any;
};

interface QueryTimestampsConfig {
createdAt?: boolean;
updatedAt?: boolean;
Expand Down
Loading