Skip to content

Commit

Permalink
Merge pull request #13721 from Automattic/vkarpov15/gh-13705
Browse files Browse the repository at this point in the history
types(models+query): return `lean` type when passing QueryOptions with `lean: true` to relevant model functions like `find()` and `findOne()`
  • Loading branch information
vkarpov15 committed Aug 11, 2023
2 parents 48edaf1 + d348ce9 commit 513340a
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 3 deletions.
36 changes: 35 additions & 1 deletion test/types/models.test.ts
@@ -1,4 +1,4 @@
import {
import mongoose, {
Schema,
Document,
Model,
Expand Down Expand Up @@ -639,3 +639,37 @@ function gh13529() {
resourceDoc.foo = 'bar';
}
}

async function gh13705() {
const schema = new Schema({ name: String });
const TestModel = model('Test', schema);

type ExpectedLeanDoc = (mongoose.FlattenMaps<{ name?: string }> & { _id: mongoose.Types.ObjectId });

const findByIdRes = await TestModel.findById('0'.repeat(24), undefined, { lean: true });
expectType<ExpectedLeanDoc | null>(findByIdRes);

const findOneRes = await TestModel.findOne({ _id: '0'.repeat(24) }, undefined, { lean: true });
expectType<ExpectedLeanDoc | null>(findOneRes);

const findRes = await TestModel.find({ _id: '0'.repeat(24) }, undefined, { lean: true });
expectType<ExpectedLeanDoc[]>(findRes);

const findByIdAndDeleteRes = await TestModel.findByIdAndDelete('0'.repeat(24), { lean: true });
expectType<ExpectedLeanDoc | null>(findByIdAndDeleteRes);

const findByIdAndRemoveRes = await TestModel.findByIdAndRemove('0'.repeat(24), { lean: true });
expectType<ExpectedLeanDoc | null>(findByIdAndRemoveRes);

const findByIdAndUpdateRes = await TestModel.findByIdAndUpdate('0'.repeat(24), {}, { lean: true });
expectType<ExpectedLeanDoc | null>(findByIdAndUpdateRes);

const findOneAndDeleteRes = await TestModel.findOneAndDelete({ _id: '0'.repeat(24) }, { lean: true });
expectType<ExpectedLeanDoc | null>(findOneAndDeleteRes);

const findOneAndReplaceRes = await TestModel.findOneAndReplace({ _id: '0'.repeat(24) }, {}, { lean: true });
expectType<ExpectedLeanDoc | null>(findOneAndReplaceRes);

const findOneAndUpdateRes = await TestModel.findOneAndUpdate({}, {}, { lean: true });
expectType<ExpectedLeanDoc | null>(findOneAndUpdateRes);
}
96 changes: 96 additions & 0 deletions types/models.d.ts
Expand Up @@ -297,6 +297,17 @@ declare module 'mongoose' {
* equivalent to `findOne({ _id: id })`. If you want to query by a document's
* `_id`, use `findById()` instead of `findOne()`.
*/
findById<ResultDoc = THydratedDocumentType>(
id: any,
projection: ProjectionType<TRawDocType> | null | undefined,
options: QueryOptions<TRawDocType> & { lean: true }
): QueryWithHelpers<
GetLeanResultType<TRawDocType, TRawDocType, 'findOne'> | null,
ResultDoc,
TQueryHelpers,
TRawDocType,
'findOne'
>;
findById<ResultDoc = THydratedDocumentType>(
id: any,
projection?: ProjectionType<TRawDocType> | null,
Expand All @@ -308,6 +319,17 @@ declare module 'mongoose' {
): QueryWithHelpers<ResultDoc | null, ResultDoc, TQueryHelpers, TRawDocType, 'findOne'>;

/** Finds one document. */
findOne<ResultDoc = THydratedDocumentType>(
filter: FilterQuery<TRawDocType>,
projection: ProjectionType<TRawDocType> | null | undefined,
options: QueryOptions<TRawDocType> & { lean: true }
): QueryWithHelpers<
GetLeanResultType<TRawDocType, TRawDocType, 'findOne'> | null,
ResultDoc,
TQueryHelpers,
TRawDocType,
'findOne'
>;
findOne<ResultDoc = THydratedDocumentType>(
filter?: FilterQuery<TRawDocType>,
projection?: ProjectionType<TRawDocType> | null,
Expand Down Expand Up @@ -460,6 +482,17 @@ declare module 'mongoose' {
>;

/** Creates a `find` query: gets a list of documents that match `filter`. */
find<ResultDoc = THydratedDocumentType>(
filter: FilterQuery<TRawDocType>,
projection: ProjectionType<TRawDocType> | null | undefined,
options: QueryOptions<TRawDocType> & { lean: true }
): QueryWithHelpers<
GetLeanResultType<TRawDocType, TRawDocType[], 'find'>,
ResultDoc,
TQueryHelpers,
TRawDocType,
'find'
>;
find<ResultDoc = THydratedDocumentType>(
filter: FilterQuery<TRawDocType>,
projection?: ProjectionType<TRawDocType> | null | undefined,
Expand All @@ -476,18 +509,49 @@ declare module 'mongoose' {
): QueryWithHelpers<Array<ResultDoc>, ResultDoc, TQueryHelpers, TRawDocType, 'find'>;

/** Creates a `findByIdAndDelete` query, filtering by the given `_id`. */
findByIdAndDelete<ResultDoc = THydratedDocumentType>(
id: mongodb.ObjectId | any,
options: QueryOptions<TRawDocType> & { lean: true }
): QueryWithHelpers<
GetLeanResultType<TRawDocType, TRawDocType, 'findOneAndDelete'> | null,
ResultDoc,
TQueryHelpers,
TRawDocType,
'findOneAndDelete'
>;
findByIdAndDelete<ResultDoc = THydratedDocumentType>(
id?: mongodb.ObjectId | any,
options?: QueryOptions<TRawDocType> | null
): QueryWithHelpers<ResultDoc | null, ResultDoc, TQueryHelpers, TRawDocType, 'findOneAndDelete'>;

/** Creates a `findByIdAndRemove` query, filtering by the given `_id`. */
findByIdAndRemove<ResultDoc = THydratedDocumentType>(
id: mongodb.ObjectId | any,
options: QueryOptions<TRawDocType> & { lean: true }
): QueryWithHelpers<
GetLeanResultType<TRawDocType, TRawDocType, 'findOneAndDelete'> | null,
ResultDoc,
TQueryHelpers,
TRawDocType,
'findOneAndDelete'
>;
findByIdAndRemove<ResultDoc = THydratedDocumentType>(
id?: mongodb.ObjectId | any,
options?: QueryOptions<TRawDocType> | null
): QueryWithHelpers<ResultDoc | null, ResultDoc, TQueryHelpers, TRawDocType, 'findOneAndDelete'>;

/** Creates a `findOneAndUpdate` query, filtering by the given `_id`. */
findByIdAndUpdate<ResultDoc = THydratedDocumentType>(
id: mongodb.ObjectId | any,
update: UpdateQuery<TRawDocType>,
options: QueryOptions<TRawDocType> & { lean: true }
): QueryWithHelpers<
GetLeanResultType<TRawDocType, TRawDocType, 'findOneAndUpdate'> | null,
ResultDoc,
TQueryHelpers,
TRawDocType,
'findOneAndUpdate'
>;
findByIdAndUpdate<ResultDoc = THydratedDocumentType>(
id: mongodb.ObjectId | any,
update: UpdateQuery<TRawDocType>,
Expand All @@ -509,6 +573,16 @@ declare module 'mongoose' {
): QueryWithHelpers<ResultDoc | null, ResultDoc, TQueryHelpers, TRawDocType, 'findOneAndUpdate'>;

/** Creates a `findOneAndDelete` query: atomically finds the given document, deletes it, and returns the document as it was before deletion. */
findOneAndDelete<ResultDoc = THydratedDocumentType>(
filter: FilterQuery<TRawDocType>,
options: QueryOptions<TRawDocType> & { lean: true }
): QueryWithHelpers<
GetLeanResultType<TRawDocType, TRawDocType, 'findOneAndDelete'> | null,
ResultDoc,
TQueryHelpers,
TRawDocType,
'findOneAndDelete'
>;
findOneAndDelete<ResultDoc = THydratedDocumentType>(
filter?: FilterQuery<TRawDocType>,
options?: QueryOptions<TRawDocType> | null
Expand All @@ -521,6 +595,17 @@ declare module 'mongoose' {
): QueryWithHelpers<ResultDoc | null, ResultDoc, TQueryHelpers, TRawDocType, 'findOneAndRemove'>;

/** Creates a `findOneAndReplace` query: atomically finds the given document and replaces it with `replacement`. */
findOneAndReplace<ResultDoc = THydratedDocumentType>(
filter: FilterQuery<TRawDocType>,
replacement: TRawDocType | AnyObject,
options: QueryOptions<TRawDocType> & { lean: true }
): QueryWithHelpers<
GetLeanResultType<TRawDocType, TRawDocType, 'findOneAndReplace'> | null,
ResultDoc,
TQueryHelpers,
TRawDocType,
'findOneAndReplace'
>;
findOneAndReplace<ResultDoc = THydratedDocumentType>(
filter: FilterQuery<TRawDocType>,
replacement: TRawDocType | AnyObject,
Expand All @@ -538,6 +623,17 @@ declare module 'mongoose' {
): QueryWithHelpers<ResultDoc | null, ResultDoc, TQueryHelpers, TRawDocType, 'findOneAndReplace'>;

/** Creates a `findOneAndUpdate` query: atomically find the first document that matches `filter` and apply `update`. */
findOneAndUpdate<ResultDoc = THydratedDocumentType>(
filter: FilterQuery<TRawDocType>,
update: UpdateQuery<TRawDocType>,
options: QueryOptions<TRawDocType> & { lean: true }
): QueryWithHelpers<
GetLeanResultType<TRawDocType, TRawDocType, 'findOneAndUpdate'> | null,
ResultDoc,
TQueryHelpers,
TRawDocType,
'findOneAndUpdate'
>;
findOneAndUpdate<ResultDoc = THydratedDocumentType>(
filter: FilterQuery<TRawDocType>,
update: UpdateQuery<TRawDocType>,
Expand Down
18 changes: 16 additions & 2 deletions types/query.d.ts
Expand Up @@ -179,6 +179,10 @@ declare module 'mongoose' {

type QueryOpThatReturnsDocument = 'find' | 'findOne' | 'findOneAndUpdate' | 'findOneAndReplace' | 'findOneAndDelete';

type GetLeanResultType<RawDocType, ResultType, QueryOp> = QueryOp extends QueryOpThatReturnsDocument
? (ResultType extends any[] ? Require_id<FlattenMaps<RawDocType>>[] : Require_id<FlattenMaps<RawDocType>>)
: ResultType;

class Query<ResultType, DocType, THelpers = {}, RawDocType = DocType, QueryOp = 'find'> implements SessionOperation {
_mongooseOptions: MongooseQueryOptions<DocType>;

Expand Down Expand Up @@ -499,9 +503,19 @@ declare module 'mongoose' {
j(val: boolean | null): this;

/** Sets the lean option. */
lean<LeanResultType = QueryOp extends QueryOpThatReturnsDocument ? (ResultType extends any[] ? Require_id<FlattenMaps<RawDocType>>[] : Require_id<FlattenMaps<RawDocType>>) : ResultType>(
lean<
LeanResultType = GetLeanResultType<RawDocType, ResultType, QueryOp>
>(
val?: boolean | any
): QueryWithHelpers<ResultType extends null ? LeanResultType | null : LeanResultType, DocType, THelpers, RawDocType, QueryOp>;
): QueryWithHelpers<
ResultType extends null
? LeanResultType | null
: LeanResultType,
DocType,
THelpers,
RawDocType,
QueryOp
>;

/** Specifies the maximum number of documents the query will return. */
limit(val: number): this;
Expand Down

0 comments on commit 513340a

Please sign in to comment.