Skip to content

Commit

Permalink
Merge pull request #11843 from Automattic/vkarpov15/gh11758
Browse files Browse the repository at this point in the history
feat(types+document): add `$assertPopulated()` for working with manually populated paths in TypeScript
  • Loading branch information
vkarpov15 committed May 28, 2022
2 parents ef3237b + 6b08472 commit 2cff001
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 4 deletions.
39 changes: 35 additions & 4 deletions lib/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -4251,10 +4251,10 @@ Document.prototype.$getPopulatedDocs = function $getPopulatedDocs() {
*
* #### Example:
*
* Model.findOne().populate('author').exec(function (err, doc) {
* console.log(doc.author.name) // Dr.Seuss
* console.log(doc.populated('author')) // '5144cf8050f071d979c118a7'
* })
* const doc = await Model.findOne().populate('author');
*
* console.log(doc.author.name); // Dr.Seuss
* console.log(doc.populated('author')); // '5144cf8050f071d979c118a7'
*
* If the path was not populated, returns `undefined`.
*
Expand Down Expand Up @@ -4308,6 +4308,37 @@ Document.prototype.populated = function(path, val, options) {

Document.prototype.$populated = Document.prototype.populated;

/**
* Throws an error if a given path is not populated
*
* #### Example:
*
* const doc = await Model.findOne().populate('author');
*
* doc.$assertPopulated('author'); // does not throw
* doc.$assertPopulated('other path'); // throws an error
*
*
* @param {String | Array<String>} path
* @return {Document} this
* @memberOf Document
* @instance
* @api public
*/

Document.prototype.$assertPopulated = function $assertPopulated(paths) {
if (Array.isArray(paths)) {
paths.forEach(path => this.$assertPopulated(path));
return this;
}

if (!this.$populated(paths)) {
throw new MongooseError(`Expected path "${paths}" to be populated`);
}

return this;
};

/**
* Takes a populated field and returns it to its unpopulated state.
*
Expand Down
27 changes: 27 additions & 0 deletions test/types/populate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,4 +228,31 @@ async function _11532() {
if (!leanResult) return;
expectType<string>(leanResult.child.name);
expectError(leanResult?.__v);
}

function gh11758() {
interface NestedChild {
name: string
_id: Types.ObjectId
}
const nestedChildSchema: Schema = new Schema({ name: String });

interface Parent {
nestedChild: Types.ObjectId
name?: string
}

const ParentModel = model<Parent>('Parent', new Schema({
nestedChild: { type: Schema.Types.ObjectId, ref: 'NestedChild' },
name: String
}));

const NestedChildModel = model<NestedChild>('NestedChild', nestedChildSchema);

const parent = new ParentModel({
nestedChild: new NestedChildModel({ name: 'test' }),
name: 'Parent'
}).$assertPopulated<{ nestedChild: NestedChild }>('nestedChild');

expectType<string>(parent.nestedChild.name);
}
3 changes: 3 additions & 0 deletions types/document.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ declare module 'mongoose' {
/** This documents __v. */
__v?: any;

/** Assert that a given path or paths is populated. Throws an error if not populated. */
$assertPopulated<Paths = {}>(paths: string | string[]): Omit<this, keyof Paths> & Paths;

/* Get all subdocs (by bfs) */
$getAllSubdocs(): Document[];

Expand Down

0 comments on commit 2cff001

Please sign in to comment.