Skip to content

Commit

Permalink
feat(populate+schema): add support for populate schematype option t…
Browse files Browse the repository at this point in the history
…hat sets default populate options

Fix #6029
  • Loading branch information
vkarpov15 committed Nov 14, 2020
1 parent 032c47f commit a659b2b
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 13 deletions.
6 changes: 6 additions & 0 deletions docs/schematypes.pug
Expand Up @@ -290,18 +290,24 @@ block content
* `enum`: Array, creates a [validator](./validation.html) that checks if the value is in the given array.
* `minLength`: Number, creates a [validator](./validation.html) that checks if the value length is not less than the given number
* `maxLength`: Number, creates a [validator](./validation.html) that checks if the value length is not greater than the given number
* `populate`: Object, sets default [populate options](/docs/populate.html#query-conditions)

<h5 id="number-validators">Number</h5>

* `min`: Number, creates a [validator](./validation.html) that checks if the value is greater than or equal to the given minimum.
* `max`: Number, creates a [validator](./validation.html) that checks if the value is less than or equal to the given maximum.
* `enum`: Array, creates a [validator](./validation.html) that checks if the value is strictly equal to one of the values in the given array.
* `populate`: Object, sets default [populate options](/docs/populate.html#query-conditions)

<h5>Date</h5>

* `min`: Date
* `max`: Date

<h5>ObjectId</h5>

* `populate`: Object, sets default [populate options](/docs/populate.html#query-conditions)

<h3 id="usage-notes"><a href="#usage-notes">Usage Notes</a></h3>

<h4 id="strings">String</h4>
Expand Down
4 changes: 4 additions & 0 deletions lib/helpers/populate/getModelsMapForPopulate.js
Expand Up @@ -67,6 +67,7 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {
modelNames = null;
let isRefPath = !!_firstWithRefPath;
let normalizedRefPath = _firstWithRefPath ? get(_firstWithRefPath, 'options.refPath', null) : null;
let schemaOptions = null;

if (Array.isArray(schema)) {
const schemasArray = schema;
Expand Down Expand Up @@ -104,6 +105,7 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {
isRefPath = res.isRefPath;
normalizedRefPath = res.refPath;
justOne = res.justOne;
schemaOptions = get(schema, 'options.populate', null);
} catch (error) {
return error;
}
Expand Down Expand Up @@ -319,6 +321,8 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {

if (isVirtual && get(virtual, 'options.options')) {
currentOptions.options = utils.clone(virtual.options.options);
} else if (schemaOptions != null) {
currentOptions.options = Object.assign({}, schemaOptions);
}
utils.merge(currentOptions, options);

Expand Down
25 changes: 25 additions & 0 deletions lib/options/SchemaNumberOptions.js
Expand Up @@ -67,6 +67,31 @@ Object.defineProperty(SchemaNumberOptions.prototype, 'max', opts);

Object.defineProperty(SchemaNumberOptions.prototype, 'enum', opts);

/**
* Sets default [populate options](/docs/populate.html#query-conditions).
*
* ####Example:
* const schema = new Schema({
* child: {
* type: Number,
* ref: 'Child',
* populate: { select: 'name' }
* }
* });
* const Parent = mongoose.model('Parent', schema);
*
* // Automatically adds `.select('name')`
* Parent.findOne().populate('child');
*
* @api public
* @property populate
* @memberOf SchemaNumberOptions
* @type Object
* @instance
*/

Object.defineProperty(SchemaNumberOptions.prototype, 'populate', opts);

/*!
* ignore
*/
Expand Down
25 changes: 25 additions & 0 deletions lib/options/SchemaObjectIdOptions.js
Expand Up @@ -31,6 +31,31 @@ const opts = require('./propertyOptions');

Object.defineProperty(SchemaObjectIdOptions.prototype, 'auto', opts);

/**
* Sets default [populate options](/docs/populate.html#query-conditions).
*
* ####Example:
* const schema = new Schema({
* child: {
* type: 'ObjectId',
* ref: 'Child',
* populate: { select: 'name' }
* }
* });
* const Parent = mongoose.model('Parent', schema);
*
* // Automatically adds `.select('name')`
* Parent.findOne().populate('child');
*
* @api public
* @property populate
* @memberOf SchemaObjectIdOptions
* @type Object
* @instance
*/

Object.defineProperty(SchemaObjectIdOptions.prototype, 'populate', opts);

/*!
* ignore
*/
Expand Down
12 changes: 12 additions & 0 deletions lib/options/SchemaStringOptions.js
Expand Up @@ -119,6 +119,18 @@ Object.defineProperty(SchemaStringOptions.prototype, 'minlength', opts);
Object.defineProperty(SchemaStringOptions.prototype, 'maxLength', opts);
Object.defineProperty(SchemaStringOptions.prototype, 'maxlength', opts);

/**
* Sets default [populate options](/docs/populate.html#query-conditions).
*
* @api public
* @property populate
* @memberOf SchemaStringOptions
* @type Object
* @instance
*/

Object.defineProperty(SchemaStringOptions.prototype, 'populate', opts);

/*!
* ignore
*/
Expand Down
26 changes: 13 additions & 13 deletions test/debug.test.js
Expand Up @@ -32,8 +32,8 @@ describe('debug: shell', function() {
let testModel;

let lastLog;
let originalConsole = console.info;
let originalDebugOption = mongoose.options.debug
const originalConsole = console.info;
const originalDebugOption = mongoose.options.debug;

before(function(done) {
db = start();
Expand All @@ -44,29 +44,29 @@ describe('debug: shell', function() {
lastLog = arguments[0];
if (originalDebugOption) {
originalConsole.apply(console, arguments);
};
}
}
};

done();
});

after(function(done) {
// revert monkey patch
console.info = originalConsole;
mongoose.set('debug', originalDebugOption)
mongoose.set('debug', originalDebugOption);
db.close(done);
});

it('no-shell', async function() {
mongoose.set('debug', {shell: false});
await testModel.create({dob: new Date()});
assert.equal(true, lastLog.includes('new Date'));
it('no-shell', function() {
mongoose.set('debug', { shell: false });
return testModel.create({ dob: new Date() }).
then(() => assert.equal(true, lastLog.includes('new Date')));
});

it('shell', async function() {
mongoose.set('debug', {shell: true});
await testModel.create({dob: new Date()});
assert.equal(true, lastLog.includes('ISODate'));
it('shell', function() {
mongoose.set('debug', { shell: true });
testModel.create({ dob: new Date() }).
then(() => assert.equal(true, lastLog.includes('ISODate')));
});

});
23 changes: 23 additions & 0 deletions test/model.populate.test.js
Expand Up @@ -9819,4 +9819,27 @@ describe('model: populate:', function() {
assert.strictEqual(res[1].linkedId, undefined);
});
});

it('supports default populate options (gh-6029)', function() {
const parentSchema = Schema({
child: {
type: 'ObjectId',
ref: 'Child',
populate: { select: 'name' }
}
});
const Parent = db.model('Parent', parentSchema);

const childSchema = new Schema({ name: String, age: Number });
const Child = db.model('Child', childSchema);

return co(function*() {
const child = yield Child.create({ name: 'my name', age: 30 });
yield Parent.create({ child: child._id });

const res = yield Parent.findOne().populate('child');
assert.equal(res.child.name, 'my name');
assert.strictEqual(res.child.age, void 0);
});
});
});

0 comments on commit a659b2b

Please sign in to comment.