Skip to content

Commit

Permalink
fix(populate+types): call foreignField functions with doc as 1st …
Browse files Browse the repository at this point in the history
…param, better typings for `localField` and `foreignField` functions

Fix #11321
  • Loading branch information
vkarpov15 committed Mar 7, 2022
1 parent 200c277 commit 5ce23b2
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 6 deletions.
2 changes: 1 addition & 1 deletion lib/helpers/populate/getModelsMapForPopulate.js
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ function _virtualPopulate(model, docs, options, _virtualRes) {
localField = localField.call(doc, doc);
}
if (typeof foreignField === 'function') {
foreignField = foreignField.call(doc);
foreignField = foreignField.call(doc, doc);
}

data.isRefPath = false;
Expand Down
29 changes: 28 additions & 1 deletion test/types/populate.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Schema, model, Document, PopulatedDoc, Types } from 'mongoose';
import { Schema, model, Document, PopulatedDoc, Types, HydratedDocument } from 'mongoose';
// Use the mongodb ObjectId to make instanceof calls possible
import { ObjectId } from 'mongodb';
import { expectError } from 'tsd';
Expand Down Expand Up @@ -122,4 +122,31 @@ function gh11014() {
.then(parents => {
parents.map(p => p.child.name);
});
}

function gh11321(): void {
interface Parent {
child?: ObjectId,
name?: string
}

const parentSchema: Schema<Parent> = new Schema<Parent>({
child: { type: 'ObjectId', ref: 'Child' },
name: String
});

parentSchema.virtual('test', {
localField: (doc: HydratedDocument<Parent, {}>): string => {
if (typeof doc.name === 'string') {
return doc.name;
}
return 'foo';
},
foreignField: (doc: HydratedDocument<Parent, {}>): string => {
if (typeof doc.name === 'string') {
return doc.name;
}
return 'foo';
}
});
}
8 changes: 4 additions & 4 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1226,7 +1226,7 @@ declare module 'mongoose' {
statics: { [name: string]: (this: M, ...args: any[]) => any };

/** Creates a virtual type with the given name. */
virtual(name: string, options?: VirtualTypeOptions): VirtualType;
virtual<T = HydratedDocument<DocType, TInstanceMethods>>(name: string, options?: VirtualTypeOptions<T>): VirtualType;

/** Object of currently defined virtuals on this schema */
virtuals: any;
Expand Down Expand Up @@ -1657,15 +1657,15 @@ declare module 'mongoose' {

type InferId<T> = T extends { _id?: any } ? T['_id'] : Types.ObjectId;

interface VirtualTypeOptions {
interface VirtualTypeOptions<HydratedDocType = Document> {
/** If `ref` is not nullish, this becomes a populated virtual. */
ref?: string | Function;

/** The local field to populate on if this is a populated virtual. */
localField?: string | Function;
localField?: string | ((this: HydratedDocType, doc: HydratedDocType) => string);

/** The foreign field to populate on if this is a populated virtual. */
foreignField?: string | Function;
foreignField?: string | ((this: HydratedDocType, doc: HydratedDocType) => string);

/**
* By default, a populated virtual is an array. If you set `justOne`,
Expand Down

0 comments on commit 5ce23b2

Please sign in to comment.