mongoose 5.4.0 → 5.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/model.js CHANGED
@@ -171,26 +171,49 @@ Model.prototype.baseModelName;
171
171
  * MyModel.events.on('error', err => console.log(err.message));
172
172
  *
173
173
  * // Prints a 'CastError' because of the above handler
174
- * await MyModel.findOne({ _id: 'notanid' }).catch({} => {});
174
+ * await MyModel.findOne({ _id: 'notanid' }).catch(noop);
175
175
  *
176
176
  * @api public
177
177
  * @fires error whenever any query or model function errors
178
- * @property events
179
178
  * @memberOf Model
180
- * @static
179
+ * @static events
181
180
  */
182
181
 
183
182
  Model.events;
184
183
 
184
+ /*!
185
+ * Compiled middleware for this model. Set in `applyHooks()`.
186
+ *
187
+ * @api private
188
+ * @property _middleware
189
+ * @memberOf Model
190
+ * @static
191
+ */
192
+
193
+ Model._middleware;
194
+
195
+ /*!
196
+ * ignore
197
+ */
198
+
199
+ function _applyCustomWhere(doc, where) {
200
+ if (doc.$where == null) {
201
+ return;
202
+ }
203
+
204
+ const keys = Object.keys(doc.$where);
205
+ const len = keys.length;
206
+ for (let i = 0; i < len; ++i) {
207
+ where[keys[i]] = doc.$where[keys[i]];
208
+ }
209
+ }
210
+
185
211
  /*!
186
212
  * ignore
187
213
  */
188
214
 
189
215
  Model.prototype.$__handleSave = function(options, callback) {
190
216
  const _this = this;
191
- let i;
192
- let keys;
193
- let len;
194
217
  let saveOptions = {};
195
218
 
196
219
  if ('safe' in options) {
@@ -274,13 +297,7 @@ Model.prototype.$__handleSave = function(options, callback) {
274
297
  return;
275
298
  }
276
299
 
277
- if (this.$where) {
278
- keys = Object.keys(this.$where);
279
- len = keys.length;
280
- for (i = 0; i < len; ++i) {
281
- where[keys[i]] = this.$where[keys[i]];
282
- }
283
- }
300
+ _applyCustomWhere(this, where);
284
301
 
285
302
  this[modelCollectionSymbol].updateOne(where, delta[1], saveOptions, function(err, ret) {
286
303
  if (err) {
@@ -409,6 +426,7 @@ function generateVersionError(doc, modifiedPaths) {
409
426
  * @param {Boolean} [options.j] set to true for MongoDB to wait until this `save()` has been [journaled before resolving the returned promise](https://docs.mongodb.com/manual/reference/write-concern/#j-option). Overrides the [schema-level `writeConcern` option](/docs/guide.html#writeConcern)
410
427
  * @param {Number} [options.wtimeout] sets a [timeout for the write concern](https://docs.mongodb.com/manual/reference/write-concern/#wtimeout). Overrides the [schema-level `writeConcern` option](/docs/guide.html#writeConcern).
411
428
  * @param {Boolean} [options.checkKeys=true] the MongoDB driver prevents you from saving keys that start with '$' or contain '.' by default. Set this option to `false` to skip that check. See [restrictions on field names](https://docs.mongodb.com/manual/reference/limits/#Restrictions-on-Field-Names)
429
+ * @param {Boolean} [options.timestamps=true] if `false` and [timestamps](./guide.html#timestamps) are enabled, skip timestamps for this `save()`.
412
430
  * @param {Function} [fn] optional callback
413
431
  * @return {Promise|undefined} Returns undefined if used with callback or a Promise otherwise.
414
432
  * @api public
@@ -447,8 +465,11 @@ Model.prototype.save = function(options, fn) {
447
465
  return cb(parallelSave);
448
466
  }
449
467
 
468
+ this.$__.saveOptions = options;
469
+
450
470
  this.$__save(options, error => {
451
471
  this.$__.saving = undefined;
472
+ delete this.$__.saveOptions;
452
473
 
453
474
  if (error) {
454
475
  this.$__handleReject(error);
@@ -904,6 +925,8 @@ Model.prototype.$__remove = function $__remove(options, cb) {
904
925
  return cb(where);
905
926
  }
906
927
 
928
+ _applyCustomWhere(this, where);
929
+
907
930
  this[modelCollectionSymbol].deleteOne(where, options, err => {
908
931
  if (!err) {
909
932
  this.$__.isDeleted = true;
@@ -3750,7 +3773,11 @@ function populate(model, docs, options, callback) {
3750
3773
 
3751
3774
  for (const doc of docs) {
3752
3775
  try {
3753
- utils.setValue(mod.options.path, count, doc);
3776
+ if (doc.$__ != null) {
3777
+ doc.set(mod.options.path, count);
3778
+ } else {
3779
+ utils.setValue(mod.options.path, count, doc);
3780
+ }
3754
3781
  } catch (err) {
3755
3782
  return callback(err);
3756
3783
  }
@@ -4370,7 +4397,7 @@ function valueFilter(val, assignmentOpts, populateOptions) {
4370
4397
  const numValues = val.length;
4371
4398
  for (let i = 0; i < numValues; ++i) {
4372
4399
  const subdoc = val[i];
4373
- if (!isDoc(subdoc) && (!populateOptions.retainNullValues || subdoc != null)) {
4400
+ if (!isPopulatedObject(subdoc) && (!populateOptions.retainNullValues || subdoc != null)) {
4374
4401
  continue;
4375
4402
  }
4376
4403
  maybeRemoveId(subdoc, assignmentOpts);
@@ -4393,7 +4420,7 @@ function valueFilter(val, assignmentOpts, populateOptions) {
4393
4420
  }
4394
4421
 
4395
4422
  // findOne
4396
- if (isDoc(val)) {
4423
+ if (isPopulatedObject(val)) {
4397
4424
  maybeRemoveId(val, assignmentOpts);
4398
4425
  return val;
4399
4426
  }
@@ -4422,34 +4449,19 @@ function maybeRemoveId(subdoc, assignmentOpts) {
4422
4449
  }
4423
4450
 
4424
4451
  /*!
4425
- * Determine if `doc` is a document returned
4426
- * by a populate query.
4452
+ * Determine if `obj` is something we can set a populated path to. Can be a
4453
+ * document, a lean document, or an array/map that contains docs.
4427
4454
  */
4428
4455
 
4429
- function isDoc(doc) {
4430
- if (doc == null) {
4431
- return false;
4432
- }
4433
-
4434
- const type = typeof doc;
4435
- if (type === 'string') {
4456
+ function isPopulatedObject(obj) {
4457
+ if (obj == null) {
4436
4458
  return false;
4437
4459
  }
4438
4460
 
4439
- if (type === 'number') {
4440
- return false;
4441
- }
4442
-
4443
- if (Buffer.isBuffer(doc)) {
4444
- return false;
4445
- }
4446
-
4447
- if (doc.constructor.name === 'ObjectID') {
4448
- return false;
4449
- }
4450
-
4451
- // only docs
4452
- return true;
4461
+ return Array.isArray(obj) ||
4462
+ obj.$isMongooseMap ||
4463
+ obj.$__ != null ||
4464
+ leanPopulateMap.has(obj);
4453
4465
  }
4454
4466
 
4455
4467
  /*!
@@ -4494,6 +4506,7 @@ Model.compile = function compile(name, schema, collectionName, connection, base)
4494
4506
  model.hooks = schema.s.hooks.clone();
4495
4507
  model.base = base;
4496
4508
  model.modelName = name;
4509
+
4497
4510
  if (!(model.prototype instanceof Model)) {
4498
4511
  model.__proto__ = Model;
4499
4512
  model.prototype.__proto__ = Model.prototype;
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ const objectIdSymbol = require('../helpers/symbols').objectIdSymbol;
3
4
  const utils = require('../utils');
4
5
 
5
6
  /*!
@@ -15,6 +16,10 @@ module.exports = function shardingPlugin(schema) {
15
16
  applyWhere.call(this);
16
17
  next();
17
18
  });
19
+ schema.pre('remove', function(next) {
20
+ applyWhere.call(this);
21
+ next();
22
+ });
18
23
  schema.post('save', function() {
19
24
  storeShard.call(this);
20
25
  });
@@ -63,11 +68,13 @@ function storeShard() {
63
68
 
64
69
  for (let i = 0; i < len; ++i) {
65
70
  val = this.getValue(paths[i]);
66
- if (utils.isMongooseObject(val)) {
71
+ if (val == null) {
72
+ orig[paths[i]] = val;
73
+ } else if (utils.isMongooseObject(val)) {
67
74
  orig[paths[i]] = val.toObject({depopulate: true, _isNested: true});
68
- } else if (val !== null && val !== undefined && val.valueOf &&
69
- // Explicitly don't take value of dates
70
- (!val.constructor || utils.getFunctionName(val.constructor) !== 'Date')) {
75
+ } else if (val instanceof Date || val[objectIdSymbol]) {
76
+ orig[paths[i]] = val;
77
+ } else if (typeof val.valueOf === 'function') {
71
78
  orig[paths[i]] = val.valueOf();
72
79
  } else {
73
80
  orig[paths[i]] = val;
package/lib/query.js CHANGED
@@ -5,11 +5,13 @@
5
5
  */
6
6
 
7
7
  const CastError = require('./error/cast');
8
+ const Kareem = require('kareem');
8
9
  const ObjectParameterError = require('./error/objectParameter');
9
10
  const QueryCursor = require('./cursor/QueryCursor');
10
11
  const ReadPreference = require('./driver').get().ReadPreference;
11
12
  const applyWriteConcern = require('./helpers/schema/applyWriteConcern');
12
13
  const cast = require('./cast');
14
+ const castArrayFilters = require('./helpers/update/castArrayFilters');
13
15
  const castUpdate = require('./helpers/query/castUpdate');
14
16
  const completeMany = require('./helpers/query/completeMany');
15
17
  const get = require('./helpers/get');
@@ -23,6 +25,7 @@ const slice = require('sliced');
23
25
  const updateValidators = require('./helpers/updateValidators');
24
26
  const util = require('util');
25
27
  const utils = require('./utils');
28
+ const wrapThunk = require('./helpers/query/wrapThunk');
26
29
 
27
30
  /**
28
31
  * Query constructor used for building queries. You do not need
@@ -55,6 +58,8 @@ function Query(conditions, options, model, collection) {
55
58
  options = options || {};
56
59
 
57
60
  this._transforms = [];
61
+ this._hooks = new Kareem();
62
+ this._executionCount = 0;
58
63
 
59
64
  // this is the case where we have a CustomQuery, we need to check if we got
60
65
  // options passed in, and if we did, merge them in
@@ -1724,6 +1729,18 @@ Query.prototype._castConditions = function() {
1724
1729
  }
1725
1730
  };
1726
1731
 
1732
+ /*!
1733
+ * ignore
1734
+ */
1735
+
1736
+ function _castArrayFilters(query) {
1737
+ try {
1738
+ castArrayFilters(query);
1739
+ } catch (err) {
1740
+ query.error(err);
1741
+ }
1742
+ }
1743
+
1727
1744
  /**
1728
1745
  * Thunk around find()
1729
1746
  *
@@ -1731,7 +1748,7 @@ Query.prototype._castConditions = function() {
1731
1748
  * @return {Query} this
1732
1749
  * @api private
1733
1750
  */
1734
- Query.prototype._find = function(callback) {
1751
+ Query.prototype._find = wrapThunk(function(callback) {
1735
1752
  this._castConditions();
1736
1753
 
1737
1754
  if (this.error() != null) {
@@ -1786,9 +1803,10 @@ Query.prototype._find = function(callback) {
1786
1803
  const options = this._optionsForExec();
1787
1804
  options.projection = this._fieldsForExec();
1788
1805
  const filter = this._conditions;
1806
+
1789
1807
  this._collection.find(filter, options, cb);
1790
1808
  return null;
1791
- };
1809
+ });
1792
1810
 
1793
1811
  /**
1794
1812
  * Find all documents that match `selector`. The result will be an array of documents.
@@ -1954,7 +1972,7 @@ Query.prototype._completeOne = function(doc, res, callback) {
1954
1972
  * @api private
1955
1973
  */
1956
1974
 
1957
- Query.prototype._findOne = function(callback) {
1975
+ Query.prototype._findOne = wrapThunk(function(callback) {
1958
1976
  this._castConditions();
1959
1977
 
1960
1978
  if (this.error()) {
@@ -1974,7 +1992,7 @@ Query.prototype._findOne = function(callback) {
1974
1992
 
1975
1993
  this._completeOne(doc, null, _wrapThunkCallback(this, callback));
1976
1994
  });
1977
- };
1995
+ });
1978
1996
 
1979
1997
  /**
1980
1998
  * Declares the query a findOne operation. When executed, the first found document is passed to the callback.
@@ -2064,7 +2082,7 @@ Query.prototype.findOne = function(conditions, projection, options, callback) {
2064
2082
  * @api private
2065
2083
  */
2066
2084
 
2067
- Query.prototype._count = function(callback) {
2085
+ Query.prototype._count = wrapThunk(function(callback) {
2068
2086
  try {
2069
2087
  this.cast(this.model);
2070
2088
  } catch (err) {
@@ -2079,7 +2097,7 @@ Query.prototype._count = function(callback) {
2079
2097
  const options = this._optionsForExec();
2080
2098
 
2081
2099
  this._collection.count(conds, options, utils.tick(callback));
2082
- };
2100
+ });
2083
2101
 
2084
2102
  /**
2085
2103
  * Thunk around countDocuments()
@@ -2089,7 +2107,7 @@ Query.prototype._count = function(callback) {
2089
2107
  * @api private
2090
2108
  */
2091
2109
 
2092
- Query.prototype._countDocuments = function(callback) {
2110
+ Query.prototype._countDocuments = wrapThunk(function(callback) {
2093
2111
  try {
2094
2112
  this.cast(this.model);
2095
2113
  } catch (err) {
@@ -2104,7 +2122,7 @@ Query.prototype._countDocuments = function(callback) {
2104
2122
  const options = this._optionsForExec();
2105
2123
 
2106
2124
  this._collection.collection.countDocuments(conds, options, utils.tick(callback));
2107
- };
2125
+ });
2108
2126
 
2109
2127
  /**
2110
2128
  * Thunk around estimatedDocumentCount()
@@ -2114,7 +2132,7 @@ Query.prototype._countDocuments = function(callback) {
2114
2132
  * @api private
2115
2133
  */
2116
2134
 
2117
- Query.prototype._estimatedDocumentCount = function(callback) {
2135
+ Query.prototype._estimatedDocumentCount = wrapThunk(function(callback) {
2118
2136
  if (this.error()) {
2119
2137
  return callback(this.error());
2120
2138
  }
@@ -2122,7 +2140,7 @@ Query.prototype._estimatedDocumentCount = function(callback) {
2122
2140
  const options = this._optionsForExec();
2123
2141
 
2124
2142
  this._collection.collection.estimatedDocumentCount(options, utils.tick(callback));
2125
- };
2143
+ });
2126
2144
 
2127
2145
  /**
2128
2146
  * Specifies this query as a `count` query.
@@ -2447,7 +2465,7 @@ Query.prototype.remove = function(filter, callback) {
2447
2465
  * ignore
2448
2466
  */
2449
2467
 
2450
- Query.prototype._remove = function(callback) {
2468
+ Query.prototype._remove = wrapThunk(function(callback) {
2451
2469
  this._castConditions();
2452
2470
 
2453
2471
  if (this.error() != null) {
@@ -2458,7 +2476,7 @@ Query.prototype._remove = function(callback) {
2458
2476
  callback = _wrapThunkCallback(this, callback);
2459
2477
 
2460
2478
  return Query.base.remove.call(this, helpers.handleWriteOpResult(callback));
2461
- };
2479
+ });
2462
2480
 
2463
2481
  /**
2464
2482
  * Declare and/or execute this query as a `deleteOne()` operation. Works like
@@ -2506,10 +2524,10 @@ Query.prototype.deleteOne = function(filter, callback) {
2506
2524
  };
2507
2525
 
2508
2526
  /*!
2509
- * ignore
2527
+ * Internal thunk for `deleteOne()`
2510
2528
  */
2511
2529
 
2512
- Query.prototype._deleteOne = function(callback) {
2530
+ Query.prototype._deleteOne = wrapThunk(function(callback) {
2513
2531
  this._castConditions();
2514
2532
 
2515
2533
  if (this.error() != null) {
@@ -2520,7 +2538,7 @@ Query.prototype._deleteOne = function(callback) {
2520
2538
  callback = _wrapThunkCallback(this, callback);
2521
2539
 
2522
2540
  return Query.base.deleteOne.call(this, helpers.handleWriteOpResult(callback));
2523
- };
2541
+ });
2524
2542
 
2525
2543
  /**
2526
2544
  * Declare and/or execute this query as a `deleteMany()` operation. Works like
@@ -2568,10 +2586,10 @@ Query.prototype.deleteMany = function(filter, callback) {
2568
2586
  };
2569
2587
 
2570
2588
  /*!
2571
- * ignore
2589
+ * Internal thunk around `deleteMany()`
2572
2590
  */
2573
2591
 
2574
- Query.prototype._deleteMany = function(callback) {
2592
+ Query.prototype._deleteMany = wrapThunk(function(callback) {
2575
2593
  this._castConditions();
2576
2594
 
2577
2595
  if (this.error() != null) {
@@ -2582,7 +2600,7 @@ Query.prototype._deleteMany = function(callback) {
2582
2600
  callback = _wrapThunkCallback(this, callback);
2583
2601
 
2584
2602
  return Query.base.deleteMany.call(this, helpers.handleWriteOpResult(callback));
2585
- };
2603
+ });
2586
2604
 
2587
2605
  /*!
2588
2606
  * hydrates a document
@@ -2762,13 +2780,13 @@ Query.prototype.findOneAndUpdate = function(criteria, doc, options, callback) {
2762
2780
  * @api private
2763
2781
  */
2764
2782
 
2765
- Query.prototype._findOneAndUpdate = function(callback) {
2783
+ Query.prototype._findOneAndUpdate = wrapThunk(function(callback) {
2766
2784
  if (this.error() != null) {
2767
2785
  return callback(this.error());
2768
2786
  }
2769
2787
 
2770
2788
  this._findAndModify('update', callback);
2771
- };
2789
+ });
2772
2790
 
2773
2791
  /**
2774
2792
  * Issues a mongodb [findAndModify](http://www.mongodb.org/display/DOCS/findAndModify+Command) remove command.
@@ -2938,7 +2956,7 @@ Query.prototype.findOneAndDelete = function(conditions, options, callback) {
2938
2956
  * @return {Query} this
2939
2957
  * @api private
2940
2958
  */
2941
- Query.prototype._findOneAndDelete = function(callback) {
2959
+ Query.prototype._findOneAndDelete = wrapThunk(function(callback) {
2942
2960
  this._castConditions();
2943
2961
 
2944
2962
  if (this.error() != null) {
@@ -2968,7 +2986,7 @@ Query.prototype._findOneAndDelete = function(callback) {
2968
2986
 
2969
2987
  return this._completeOne(doc, res, callback);
2970
2988
  }));
2971
- };
2989
+ });
2972
2990
 
2973
2991
  /**
2974
2992
  * Issues a MongoDB [findOneAndReplace](https://docs.mongodb.com/manual/reference/method/db.collection.findOneAndReplace/) command.
@@ -3053,7 +3071,7 @@ Query.prototype.findOneAndReplace = function(conditions, options, callback) {
3053
3071
  * @return {Query} this
3054
3072
  * @api private
3055
3073
  */
3056
- Query.prototype._findOneAndReplace = function(callback) {
3074
+ Query.prototype._findOneAndReplace = wrapThunk(function(callback) {
3057
3075
  this._castConditions();
3058
3076
 
3059
3077
  if (this.error() != null) {
@@ -3083,7 +3101,7 @@ Query.prototype._findOneAndReplace = function(callback) {
3083
3101
 
3084
3102
  return this._completeOne(doc, res, callback);
3085
3103
  });
3086
- };
3104
+ });
3087
3105
 
3088
3106
  /*!
3089
3107
  * Thunk around findOneAndRemove()
@@ -3092,14 +3110,14 @@ Query.prototype._findOneAndReplace = function(callback) {
3092
3110
  * @return {Query} this
3093
3111
  * @api private
3094
3112
  */
3095
- Query.prototype._findOneAndRemove = function(callback) {
3113
+ Query.prototype._findOneAndRemove = wrapThunk(function(callback) {
3096
3114
  if (this.error() != null) {
3097
3115
  callback(this.error());
3098
3116
  return;
3099
3117
  }
3100
3118
 
3101
3119
  this._findAndModify('remove', callback);
3102
- };
3120
+ });
3103
3121
 
3104
3122
  /*!
3105
3123
  * Get options from query opts, falling back to the base mongoose object.
@@ -3142,6 +3160,8 @@ Query.prototype._findAndModify = function(type, callback) {
3142
3160
  return callback(castedQuery);
3143
3161
  }
3144
3162
 
3163
+ _castArrayFilters(this);
3164
+
3145
3165
  const opts = this._optionsForExec(model);
3146
3166
 
3147
3167
  if ('strict' in opts) {
@@ -3380,6 +3400,8 @@ function _updateThunk(op, callback) {
3380
3400
 
3381
3401
  this._castConditions();
3382
3402
 
3403
+ _castArrayFilters(this);
3404
+
3383
3405
  if (this.error() != null) {
3384
3406
  callback(this.error());
3385
3407
  return null;
@@ -3391,6 +3413,8 @@ function _updateThunk(op, callback) {
3391
3413
  let castedDoc;
3392
3414
  const options = this._optionsForExec(this.model);
3393
3415
 
3416
+ ++this._executionCount;
3417
+
3394
3418
  this._update = utils.clone(this._update, options);
3395
3419
  const isOverwriting = this.options.overwrite && !hasDollarKeys(this._update);
3396
3420
  if (isOverwriting) {
@@ -3456,9 +3480,9 @@ function _updateThunk(op, callback) {
3456
3480
  * @see Model.update #model_Model.update
3457
3481
  * @api private
3458
3482
  */
3459
- Query.prototype._execUpdate = function(callback) {
3483
+ Query.prototype._execUpdate = wrapThunk(function(callback) {
3460
3484
  return _updateThunk.call(this, 'update', callback);
3461
- };
3485
+ });
3462
3486
 
3463
3487
  /*!
3464
3488
  * Internal thunk for .updateMany()
@@ -3467,9 +3491,9 @@ Query.prototype._execUpdate = function(callback) {
3467
3491
  * @see Model.update #model_Model.update
3468
3492
  * @api private
3469
3493
  */
3470
- Query.prototype._updateMany = function(callback) {
3494
+ Query.prototype._updateMany = wrapThunk(function(callback) {
3471
3495
  return _updateThunk.call(this, 'updateMany', callback);
3472
- };
3496
+ });
3473
3497
 
3474
3498
  /*!
3475
3499
  * Internal thunk for .updateOne()
@@ -3478,9 +3502,9 @@ Query.prototype._updateMany = function(callback) {
3478
3502
  * @see Model.update #model_Model.update
3479
3503
  * @api private
3480
3504
  */
3481
- Query.prototype._updateOne = function(callback) {
3505
+ Query.prototype._updateOne = wrapThunk(function(callback) {
3482
3506
  return _updateThunk.call(this, 'updateOne', callback);
3483
- };
3507
+ });
3484
3508
 
3485
3509
  /*!
3486
3510
  * Internal thunk for .replaceOne()
@@ -3489,9 +3513,9 @@ Query.prototype._updateOne = function(callback) {
3489
3513
  * @see Model.replaceOne #model_Model.replaceOne
3490
3514
  * @api private
3491
3515
  */
3492
- Query.prototype._replaceOne = function(callback) {
3516
+ Query.prototype._replaceOne = wrapThunk(function(callback) {
3493
3517
  return _updateThunk.call(this, 'replaceOne', callback);
3494
- };
3518
+ });
3495
3519
 
3496
3520
  /**
3497
3521
  * Declare and/or execute this query as an update() operation.
@@ -3972,13 +3996,23 @@ Query.prototype.exec = function exec(op, callback) {
3972
3996
  return;
3973
3997
  }
3974
3998
 
3975
- this[this.op].call(this, (error, res) => {
3999
+ this._hooks.execPre('exec', this, [], (error) => {
3976
4000
  if (error) {
3977
- cb(error);
3978
- return;
4001
+ return cb(error);
3979
4002
  }
4003
+ this[this.op].call(this, (error, res) => {
4004
+ if (error) {
4005
+ return cb(error);
4006
+ }
4007
+
4008
+ this._hooks.execPost('exec', this, [], {}, (error) => {
4009
+ if (error) {
4010
+ return cb(error);
4011
+ }
3980
4012
 
3981
- cb(null, res);
4013
+ cb(null, res);
4014
+ });
4015
+ });
3982
4016
  });
3983
4017
  }, this.model.events);
3984
4018
  };
@@ -4033,6 +4067,24 @@ Query.prototype.catch = function(reject) {
4033
4067
  return this.exec().then(null, reject);
4034
4068
  };
4035
4069
 
4070
+ /*!
4071
+ * ignore
4072
+ */
4073
+
4074
+ Query.prototype._pre = function(fn) {
4075
+ this._hooks.pre('exec', fn);
4076
+ return this;
4077
+ };
4078
+
4079
+ /*!
4080
+ * ignore
4081
+ */
4082
+
4083
+ Query.prototype._post = function(fn) {
4084
+ this._hooks.post('exec', fn);
4085
+ return this;
4086
+ };
4087
+
4036
4088
  /*!
4037
4089
  * Casts obj for an update command.
4038
4090
  *
@@ -43,19 +43,21 @@ SchemaBoolean.prototype.constructor = SchemaBoolean;
43
43
  SchemaBoolean._cast = castBoolean;
44
44
 
45
45
  /**
46
- * Get/set the function used to cast arbitrary values to objectids.
46
+ * Get/set the function used to cast arbitrary values to booleans.
47
47
  *
48
48
  * ####Example:
49
49
  *
50
- * // Make Mongoose only try to cast strings
51
- * const original = mongoose.ObjectId.cast();
52
- * mongoose.ObjectId.cast(v => {
53
- * assert.ok(v == null || typeof v === 'string');
50
+ * // Make Mongoose cast empty string '' to false.
51
+ * const original = mongoose.Schema.Boolean.cast();
52
+ * mongoose.Schema.Boolean.cast(v => {
53
+ * if (v === '') {
54
+ * return false;
55
+ * }
54
56
  * return original(v);
55
57
  * });
56
58
  *
57
59
  * // Or disable casting entirely
58
- * mongoose.ObjectId.cast(false);
60
+ * mongoose.Schema.Boolean.cast(false);
59
61
  *
60
62
  * @param {Function} caster
61
63
  * @return {Function}
@@ -88,7 +90,7 @@ SchemaBoolean.cast = function cast(caster) {
88
90
  SchemaBoolean._checkRequired = v => v === true || v === false;
89
91
 
90
92
  /**
91
- * Override the function the required validator uses to check whether a string
93
+ * Override the function the required validator uses to check whether a boolean
92
94
  * passes the `required` check.
93
95
  *
94
96
  * @param {Function} fn
@@ -35,6 +35,10 @@ function DocumentArray(key, schema, options, schemaOptions) {
35
35
  this.schema = schema;
36
36
  this.schemaOptions = schemaOptions || {};
37
37
  this.$isMongooseDocumentArray = true;
38
+ this.Constructor = EmbeddedDocument;
39
+
40
+ EmbeddedDocument.base = schema.base;
41
+
38
42
  const fn = this.defaultValue;
39
43
 
40
44
  if (!('defaultValue' in this) || fn !== void 0) {
@@ -254,6 +258,40 @@ DocumentArray.prototype.doValidateSync = function(array, scope) {
254
258
  return resultError;
255
259
  };
256
260
 
261
+ /*!
262
+ * ignore
263
+ */
264
+
265
+ DocumentArray.prototype.getDefault = function(scope) {
266
+ let ret = typeof this.defaultValue === 'function'
267
+ ? this.defaultValue.call(scope)
268
+ : this.defaultValue;
269
+
270
+ if (ret == null) {
271
+ return ret;
272
+ }
273
+
274
+ // lazy load
275
+ MongooseDocumentArray || (MongooseDocumentArray = require('../types/documentarray'));
276
+
277
+ if (!Array.isArray(ret)) {
278
+ ret = [ret];
279
+ }
280
+
281
+ ret = new MongooseDocumentArray(ret, this.path, scope);
282
+ const _parent = ret._parent;
283
+ ret._parent = null;
284
+
285
+ for (let i = 0; i < ret.length; ++i) {
286
+ ret[i] = new this.Constructor(ret[i], ret, undefined,
287
+ undefined, i);
288
+ }
289
+
290
+ ret._parent = _parent;
291
+
292
+ return ret;
293
+ };
294
+
257
295
  /**
258
296
  * Casts contents
259
297
  *
@@ -32,6 +32,7 @@ module.exports = Embedded;
32
32
 
33
33
  function Embedded(schema, path, options) {
34
34
  this.caster = _createConstructor(schema);
35
+ this.caster.path = path;
35
36
  this.caster.prototype.$basePath = path;
36
37
  this.schema = schema;
37
38
  this.$isSingleNested = true;