mongoose 4.10.4 → 4.10.8

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/.npmignore CHANGED
@@ -15,3 +15,4 @@ bin/
15
15
  karma.*.js
16
16
  format_deps.js
17
17
  tools/31*
18
+ *.key
package/CONTRIBUTING.md CHANGED
@@ -49,7 +49,13 @@ To contribute to the [API documentation](http://mongoosejs.com/docs/api.html) ju
49
49
 
50
50
  To contribute to the [guide](http://mongoosejs.com/docs/guide.html) or [quick start](http://mongoosejs.com/docs/index.html) docs, make your changes to the appropriate `.jade` files in the [docs](https://github.com/Automattic/mongoose/tree/master/docs) directory of the master branch and submit a pull request. Again, the [Edit](https://github.com/blog/844-forking-with-the-edit-button) button might work for you here.
51
51
 
52
- If you'd like to preview your documentation changes, first commit your changes to your local master branch, then execute `make docs` from the project root, which switches to the gh-pages branch, merges from the master branch and builds all the static pages for you. Now execute `node static.js` from the project root which will launch a local webserver where you can browse the documentation site locally. If all looks good, submit a [pull request](https://help.github.com/articles/using-pull-requests/) to the master branch with your changes.
52
+ If you'd like to preview your documentation changes, first commit your changes to your local master branch, then execute:
53
+
54
+ * `make docclean`
55
+ * `make gendocs`
56
+ * `node static.js`
57
+
58
+ Visit `http://localhost:8088` and you should see the docs with your local changes. Make sure you `git reset --hard` before commiting, because changes to `docs/*` should **not** be in PRs.
53
59
 
54
60
  ### Plugins website
55
61
 
package/History.md CHANGED
@@ -1,3 +1,41 @@
1
+ 4.10.8 / 2017-06-21
2
+ ===================
3
+ * docs: fix small formatting typo on schematypes #5374 [gianpaj](https://github.com/gianpaj)
4
+ * fix(model): allow null as an _id #5370
5
+ * fix(populate): don't throw async uncaught exception if model not found in populate #5364
6
+ * fix: correctly cast decimals in update #5361
7
+ * fix(error): don't use custom getter for ValidationError message #5359
8
+ * fix(query): handle runSettersOnQuery in built-in _id setter #5351
9
+ * fix(document): ensure consistent context for nested doc custom validators #5347
10
+
11
+ 4.10.7 / 2017-06-18
12
+ ===================
13
+ * docs(validation): show overriding custom validator error with 2nd cb arg #5358
14
+ * fix: `parseOption` mutates user passed option map #5357 [igwejk](https://github.com/igwejk)
15
+ * docs: fix guide.jade typo #5356 [CalebAnderson2014](https://github.com/CalebAnderson2014)
16
+ * fix(populate): don't set populate virtual to ids when match fails #5336
17
+ * fix(query): callback with cast error if remove and delete* args have a cast error #5323
18
+
19
+ 4.10.6 / 2017-06-12
20
+ ===================
21
+ * fix(cursor): handle custom model option for populate #5334
22
+ * fix(populate): handle empty virtual populate with Model.populate #5331
23
+ * fix(model): make ensureIndexes() run with autoIndex: false unless called internally #5328 #5324 #5317
24
+ * fix: wait for all connections to close before resolving disconnect() promise #5316
25
+ * fix(document): handle setting populated path with custom typeKey in schema #5313
26
+ * fix(error): add toJSON helper to ValidationError so `message` shows up with JSON.stringify #5309
27
+ * feat: add `getPromiseConstructor()` to prevent need for `mongoose.Promise.ES6` #5305
28
+ * fix(document): handle conditional required with undefined props #5296
29
+ * fix(model): clone options before inserting in save() #5294
30
+ * docs(populate): clarify that multiple populate() calls on same path overwrite #5274
31
+
32
+ 4.10.5 / 2017-06-06
33
+ ===================
34
+ * chore: improve contrib guide for building docs #5312
35
+ * fix(populate): handle init-ing nested virtuals properly #5311
36
+ * fix(update): report update validator error if required path under single nested doc not set
37
+ * fix(schema): remove default validate pre hook that was causing issues with jest #4943
38
+
1
39
  4.10.4 / 2017-05-29
2
40
  ===================
3
41
  * chore: dont store test data in same directory #5303
package/lib/cast.js CHANGED
@@ -4,6 +4,7 @@
4
4
 
5
5
  var StrictModeError = require('./error/strict');
6
6
  var Types = require('./schema/index');
7
+ var util = require('util');
7
8
  var utils = require('./utils');
8
9
 
9
10
  var ALLOWED_GEOWITHIN_GEOJSON_TYPES = ['Polygon', 'MultiPolygon'];
@@ -17,15 +18,19 @@ var ALLOWED_GEOWITHIN_GEOJSON_TYPES = ['Polygon', 'MultiPolygon'];
17
18
  * @api private
18
19
  */
19
20
  module.exports = function cast(schema, obj, options) {
20
- var paths = Object.keys(obj),
21
- i = paths.length,
22
- _keys,
23
- any$conditionals,
24
- schematype,
25
- nested,
26
- path,
27
- type,
28
- val;
21
+ if (Array.isArray(obj)) {
22
+ throw new Error('Query filter must be an object, got an array ', util.inspect(obj));
23
+ }
24
+
25
+ var paths = Object.keys(obj);
26
+ var i = paths.length;
27
+ var _keys;
28
+ var any$conditionals;
29
+ var schematype;
30
+ var nested;
31
+ var path;
32
+ var type;
33
+ var val;
29
34
 
30
35
  while (i--) {
31
36
  path = paths[i];
@@ -2,9 +2,9 @@
2
2
  * Module dependencies.
3
3
  */
4
4
 
5
- var PromiseProvider = require('./promise_provider');
5
+ var PromiseProvider = require('../promise_provider');
6
6
  var Readable = require('stream').Readable;
7
- var helpers = require('./queryhelpers');
7
+ var helpers = require('../queryhelpers');
8
8
  var util = require('util');
9
9
 
10
10
  /**
@@ -283,9 +283,6 @@ function _next(ctx, cb) {
283
283
 
284
284
  var pop = helpers.preparePopulationOptionsMQ(ctx.query,
285
285
  ctx.query._mongooseOptions);
286
- pop.forEach(function(option) {
287
- delete option.model;
288
- });
289
286
  pop.__noPromise = true;
290
287
  ctx.query.model.populate(doc, pop, function(err, doc) {
291
288
  if (err) {
package/lib/document.js CHANGED
@@ -724,14 +724,14 @@ Document.prototype.set = function(path, val, type, options) {
724
724
 
725
725
  var popOpts;
726
726
  if (schema.options &&
727
- Array.isArray(schema.options.type) &&
728
- schema.options.type.length &&
729
- schema.options.type[0].ref &&
727
+ Array.isArray(schema.options[this.schema.options.typeKey]) &&
728
+ schema.options[this.schema.options.typeKey].length &&
729
+ schema.options[this.schema.options.typeKey][0].ref &&
730
730
  Array.isArray(val) &&
731
731
  val.length > 0 &&
732
732
  val[0] instanceof Document &&
733
733
  val[0].constructor.modelName &&
734
- (schema.options.type[0].ref === val[0].constructor.baseModelName || schema.options.type[0].ref === val[0].constructor.modelName)) {
734
+ (schema.options[this.schema.options.typeKey][0].ref === val[0].constructor.baseModelName || schema.options[this.schema.options.typeKey][0].ref === val[0].constructor.modelName)) {
735
735
  if (this.ownerDocument) {
736
736
  popOpts = { model: val[0].constructor };
737
737
  this.ownerDocument().populated(this.$__fullPath(path),
@@ -845,7 +845,7 @@ Document.prototype.$__set = function(pathToMark, path, constructing, parts, sche
845
845
  var _this = this;
846
846
 
847
847
  if (shouldModify) {
848
- this.markModified(pathToMark, val);
848
+ this.markModified(pathToMark);
849
849
 
850
850
  // handle directly setting arrays (gh-1126)
851
851
  MongooseArray || (MongooseArray = require('./types/array'));
@@ -958,9 +958,7 @@ Document.prototype.get = function(path, type) {
958
958
  obj = adhoc.cast(obj);
959
959
  }
960
960
 
961
- // Check if this path is populated - don't apply getters if it is,
962
- // because otherwise its a nested object. See gh-3357
963
- if (schema && !this.populated(path)) {
961
+ if (schema) {
964
962
  obj = schema.applyGetters(obj, this);
965
963
  }
966
964
 
@@ -998,11 +996,15 @@ Document.prototype.$__path = function(path) {
998
996
  * doc.save() // changes to mixed.type are now persisted
999
997
  *
1000
998
  * @param {String} path the path to mark modified
999
+ * @param {Document} [scope] the scope to run validators with
1001
1000
  * @api public
1002
1001
  */
1003
1002
 
1004
- Document.prototype.markModified = function(path) {
1003
+ Document.prototype.markModified = function(path, scope) {
1005
1004
  this.$__.activePaths.modify(path);
1005
+ if (scope != null && !this.ownerDocument) {
1006
+ this.$__.pathsToScopes[path] = scope;
1007
+ }
1006
1008
  };
1007
1009
 
1008
1010
  /**
@@ -1020,6 +1022,7 @@ Document.prototype.markModified = function(path) {
1020
1022
 
1021
1023
  Document.prototype.unmarkModified = function(path) {
1022
1024
  this.$__.activePaths.init(path);
1025
+ delete this.$__.pathsToScopes[path];
1023
1026
  };
1024
1027
 
1025
1028
  /**
@@ -1461,12 +1464,15 @@ Document.prototype.$__validate = function(callback) {
1461
1464
  }
1462
1465
 
1463
1466
  var val = _this.getValue(path);
1467
+ var scope = path in _this.$__.pathsToScopes ?
1468
+ _this.$__.pathsToScopes[path] :
1469
+ _this;
1464
1470
  p.doValidate(val, function(err) {
1465
1471
  if (err) {
1466
1472
  _this.invalidate(path, err, undefined, true);
1467
1473
  }
1468
1474
  --total || complete();
1469
- }, _this);
1475
+ }, scope);
1470
1476
  });
1471
1477
  };
1472
1478
 
@@ -1611,7 +1617,7 @@ Document.prototype.invalidate = function(path, err, val, kind) {
1611
1617
  return this.$__.validationError;
1612
1618
  }
1613
1619
 
1614
- this.$__.validationError.errors[path] = err;
1620
+ this.$__.validationError.addError(path, err);
1615
1621
  return this.$__.validationError;
1616
1622
  };
1617
1623
 
@@ -245,7 +245,8 @@ NativeConnection.prototype.doClose = function(fn) {
245
245
  */
246
246
 
247
247
  NativeConnection.prototype.parseOptions = function(passed, connStrOpts) {
248
- var o = passed || {};
248
+ var o = passed ? require('../../utils').clone(passed) : {};
249
+
249
250
  o.db || (o.db = {});
250
251
  o.auth || (o.auth = {});
251
252
  o.server || (o.server = {});
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  var MongooseError = require('../error.js');
6
+ var utils = require('../utils');
6
7
 
7
8
  /**
8
9
  * Document Validation Error
@@ -40,13 +41,6 @@ function ValidationError(instance) {
40
41
  ValidationError.prototype = Object.create(MongooseError.prototype);
41
42
  ValidationError.prototype.constructor = MongooseError;
42
43
 
43
- Object.defineProperty(ValidationError.prototype, 'message', {
44
- get: function() {
45
- return this._message + ': ' + _generateMessage(this);
46
- },
47
- enumerable: true
48
- });
49
-
50
44
  /**
51
45
  * Console.log helper
52
46
  */
@@ -60,7 +54,24 @@ ValidationError.prototype.toString = function() {
60
54
  */
61
55
 
62
56
  ValidationError.prototype.inspect = function() {
63
- return Object.assign(new Error(this.message), this);
57
+ return utils.assign(new Error(this.message), this);
58
+ };
59
+
60
+ /*!
61
+ * Helper for JSON.stringify
62
+ */
63
+
64
+ ValidationError.prototype.toJSON = function() {
65
+ return utils.assign({}, this, { message: this.message });
66
+ };
67
+
68
+ /*!
69
+ * add message
70
+ */
71
+
72
+ ValidationError.prototype.addError = function(path, error) {
73
+ this.errors[path] = error;
74
+ this.message = this._message + ': ' + _generateMessage(this);
64
75
  };
65
76
 
66
77
  /*!
package/lib/index.js CHANGED
@@ -269,26 +269,29 @@ Mongoose.prototype.connect.$hasSideEffects = true;
269
269
  */
270
270
 
271
271
  Mongoose.prototype.disconnect = function(fn) {
272
- var error;
273
- this.connections.forEach(function(conn) {
274
- conn.close(function(err) {
275
- if (error) {
276
- return;
277
- }
278
- if (err) {
279
- error = err;
280
- }
281
- });
282
- });
272
+ var _this = this;
283
273
 
284
274
  var Promise = PromiseProvider.get();
285
275
  return new MongooseThenable(this, new Promise.ES6(function(resolve, reject) {
286
- fn && fn(error);
287
- if (error) {
288
- reject(error);
276
+ var remaining = _this.connections.length;
277
+ if (remaining <= 0) {
278
+ fn && fn();
279
+ resolve();
289
280
  return;
290
281
  }
291
- resolve();
282
+ _this.connections.forEach(function(conn) {
283
+ conn.close(function(error) {
284
+ if (error) {
285
+ fn && fn(error);
286
+ reject(error);
287
+ return;
288
+ }
289
+ if (!--remaining) {
290
+ fn && fn();
291
+ resolve();
292
+ }
293
+ });
294
+ });
292
295
  }));
293
296
  };
294
297
  Mongoose.prototype.disconnect.$hasSideEffects = true;
@@ -688,6 +691,19 @@ Object.defineProperty(Mongoose.prototype, 'Promise', {
688
691
  }
689
692
  });
690
693
 
694
+ /**
695
+ * Returns the current ES6-style promise constructor. In Mongoose 4.x,
696
+ * equivalent to `mongoose.Promise.ES6`, but will change once we get rid
697
+ * of the `.ES6` bit.
698
+ *
699
+ * @method Promise
700
+ * @api public
701
+ */
702
+
703
+ Mongoose.prototype.getPromiseConstructor = function() {
704
+ return PromiseProvider.get().ES6;
705
+ };
706
+
691
707
  /**
692
708
  * Storage layer for mongoose promises
693
709
  *
package/lib/internal.js CHANGED
@@ -24,6 +24,7 @@ function InternalCache() {
24
24
  this.wasPopulated = false; // if this doc was the result of a population
25
25
  this.scope = undefined;
26
26
  this.activePaths = new ActiveRoster;
27
+ this.pathsToScopes = {};
27
28
 
28
29
  // embedded docs
29
30
  this.ownerDocument = undefined;
package/lib/model.js CHANGED
@@ -114,6 +114,7 @@ Model.prototype.$__handleSave = function(options, callback) {
114
114
  if (typeof options.safe === 'boolean') {
115
115
  options.safe = null;
116
116
  }
117
+ var safe = options.safe ? utils.clone(options.safe, { retainKeyOrder: true }) : options.safe;
117
118
 
118
119
  if (this.isNew) {
119
120
  // send entire doc
@@ -127,7 +128,7 @@ Model.prototype.$__handleSave = function(options, callback) {
127
128
 
128
129
  var obj = this.toObject(toObjectOptions);
129
130
 
130
- if ((obj || {})._id == null) {
131
+ if ((obj || {})._id === void 0) {
131
132
  // documents must have an _id else mongoose won't know
132
133
  // what to update later if more changes are made. the user
133
134
  // wouldn't know what _id was generated by mongodb either
@@ -140,7 +141,7 @@ Model.prototype.$__handleSave = function(options, callback) {
140
141
  }
141
142
 
142
143
  this.$__version(true, obj);
143
- this.collection.insert(obj, options.safe, function(err, ret) {
144
+ this.collection.insert(obj, safe, function(err, ret) {
144
145
  if (err) {
145
146
  _this.isNew = true;
146
147
  _this.emit('isNew', true);
@@ -185,7 +186,7 @@ Model.prototype.$__handleSave = function(options, callback) {
185
186
  }
186
187
  }
187
188
 
188
- this.collection.update(where, delta[1], options.safe, function(err, ret) {
189
+ this.collection.update(where, delta[1], safe, function(err, ret) {
189
190
  if (err) {
190
191
  callback(err);
191
192
  return;
@@ -956,22 +957,24 @@ function _ensureIndexes(model, options, callback) {
956
957
  };
957
958
 
958
959
  var create = function() {
959
- if (model.schema.options.autoIndex === false ||
960
- (model.schema.options.autoIndex == null && model.db.config.autoIndex === false)) {
961
- return done();
960
+ if (options && options._automatic) {
961
+ if (model.schema.options.autoIndex === false ||
962
+ (model.schema.options.autoIndex == null && model.db.config.autoIndex === false)) {
963
+ return done();
964
+ }
962
965
  }
963
966
 
964
967
  var index = indexes.shift();
965
968
  if (!index) return done();
966
969
 
967
970
  var indexFields = index[0];
968
- var options = index[1];
971
+ var indexOptions = index[1];
969
972
  _handleSafe(options);
970
973
 
971
974
  indexSingleStart(indexFields, options);
972
975
 
973
- model.collection.ensureIndex(indexFields, options, utils.tick(function(err, name) {
974
- indexSingleDone(err, indexFields, options, name);
976
+ model.collection.ensureIndex(indexFields, indexOptions, utils.tick(function(err, name) {
977
+ indexSingleDone(err, indexFields, indexOptions, name);
975
978
  if (err) {
976
979
  return done(err);
977
980
  }
@@ -1080,13 +1083,13 @@ Model.remove = function remove(conditions, callback) {
1080
1083
  }
1081
1084
 
1082
1085
  // get the mongodb collection object
1083
- var mq = new this.Query(conditions, {}, this, this.collection);
1086
+ var mq = new this.Query({}, {}, this, this.collection);
1084
1087
 
1085
1088
  if (callback) {
1086
1089
  callback = this.$wrapCallback(callback);
1087
1090
  }
1088
1091
 
1089
- return mq.remove(callback);
1092
+ return mq.remove(conditions, callback);
1090
1093
  };
1091
1094
 
1092
1095
  /**
@@ -3037,10 +3040,10 @@ function populate(model, docs, options, callback) {
3037
3040
  var subPopulate = mod.options.populate;
3038
3041
  var query = mod.Model.find(match, select, mod.options.options);
3039
3042
 
3040
- /* If we're doing virtual populate and projection is inclusive and foreign
3041
- * field is not selected, automatically select it because mongoose needs it.
3042
- * If projection is exclusive and client explicitly unselected the foreign
3043
- * field, that's the client's fault. */
3043
+ // If we're doing virtual populate and projection is inclusive and foreign
3044
+ // field is not selected, automatically select it because mongoose needs it.
3045
+ // If projection is exclusive and client explicitly unselected the foreign
3046
+ // field, that's the client's fault.
3044
3047
  if (mod.foreignField !== '_id' && query.selectedInclusively() &&
3045
3048
  !isPathSelectedInclusive(query._fields, mod.foreignField)) {
3046
3049
  query.select(mod.foreignField);
@@ -3184,10 +3187,14 @@ function assignVals(o) {
3184
3187
  }
3185
3188
 
3186
3189
  if (o.isVirtual && !o.justOne && !Array.isArray(rawIds[i])) {
3187
- rawIds[i] = [rawIds[i]];
3190
+ if (rawIds[i] == null) {
3191
+ rawIds[i] = [];
3192
+ } else {
3193
+ rawIds[i] = [rawIds[i]];
3194
+ }
3188
3195
  }
3189
3196
 
3190
- if (o.isVirtual && docs[i].constructor.name === 'model' && docs[i].$init) {
3197
+ if (o.isVirtual && docs[i].constructor.name === 'model') {
3191
3198
  // If virtual populate and doc is already init-ed, need to walk through
3192
3199
  // the actual doc to set rather than setting `_doc` directly
3193
3200
  mpath.set(o.path, rawIds[i], docs[i]);
@@ -3331,7 +3338,12 @@ function getModelsMapForPopulate(model, docs, options) {
3331
3338
  modelForFindSchema = utils.getValue(discriminatorKey, doc);
3332
3339
 
3333
3340
  if (modelForFindSchema) {
3334
- modelForCurrentDoc = model.db.model(modelForFindSchema);
3341
+ try {
3342
+ modelForCurrentDoc = model.db.model(modelForFindSchema);
3343
+ } catch (error) {
3344
+ return error;
3345
+ }
3346
+
3335
3347
  schemaForCurrentDoc = modelForCurrentDoc._getSchema(options.path);
3336
3348
 
3337
3349
  if (schemaForCurrentDoc && schemaForCurrentDoc.caster) {
@@ -3396,9 +3408,13 @@ function getModelsMapForPopulate(model, docs, options) {
3396
3408
  modelName = modelNames[k];
3397
3409
  var _doc = Array.isArray(doc) && isRefPathArray ? doc[k] : doc;
3398
3410
  var _ret = Array.isArray(ret) && isRefPathArray ? ret[k] : ret;
3399
- Model = originalModel && originalModel.modelName ?
3400
- originalModel :
3401
- model.db.model(modelName);
3411
+ try {
3412
+ Model = originalModel && originalModel.modelName ?
3413
+ originalModel :
3414
+ model.db.model(modelName);
3415
+ } catch (error) {
3416
+ return error;
3417
+ }
3402
3418
 
3403
3419
  if (!available[modelName]) {
3404
3420
  currentOptions = {
package/lib/query.js CHANGED
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  var PromiseProvider = require('./promise_provider');
6
- var QueryCursor = require('./querycursor');
6
+ var QueryCursor = require('./cursor/QueryCursor');
7
7
  var QueryStream = require('./querystream');
8
8
  var cast = require('./cast');
9
9
  var castUpdate = require('./services/query/castUpdate');
@@ -186,7 +186,10 @@ Query.prototype.toConstructor = function toConstructor() {
186
186
  p.op = this.op;
187
187
  p._conditions = utils.clone(this._conditions, { retainKeyOrder: true });
188
188
  p._fields = utils.clone(this._fields);
189
- p._update = utils.clone(this._update);
189
+ p._update = utils.clone(this._update, {
190
+ flattenDecimals: false,
191
+ retainKeyOrder: true
192
+ });
190
193
  p._path = this._path;
191
194
  p._distinct = this._distinct;
192
195
  p._collection = this._collection;
@@ -1591,7 +1594,7 @@ Query.prototype.sort = function(arg) {
1591
1594
  * query.remove(fn) // executes
1592
1595
  * query.remove()
1593
1596
  *
1594
- * @param {Object|Query} [criteria] mongodb selector
1597
+ * @param {Object|Query} [filter] mongodb selector
1595
1598
  * @param {Function} [callback] optional params are (error, writeOpResult)
1596
1599
  * @return {Query} this
1597
1600
  * @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
@@ -1599,22 +1602,41 @@ Query.prototype.sort = function(arg) {
1599
1602
  * @api public
1600
1603
  */
1601
1604
 
1602
- Query.prototype.remove = function(cond, callback) {
1603
- if (typeof cond === 'function') {
1604
- callback = cond;
1605
- cond = null;
1605
+ Query.prototype.remove = function(filter, callback) {
1606
+ if (typeof filter === 'function') {
1607
+ callback = filter;
1608
+ filter = null;
1606
1609
  }
1607
1610
 
1608
- var cb = typeof callback === 'function';
1611
+ filter = utils.toObject(filter, { retainKeyOrder: true });
1609
1612
 
1610
1613
  try {
1611
- this.cast(this.model);
1614
+ this.cast(this.model, filter);
1615
+ this.merge(filter);
1612
1616
  } catch (err) {
1613
- if (cb) return process.nextTick(callback.bind(null, err));
1617
+ this._castError = err;
1618
+ }
1619
+
1620
+ prepareDiscriminatorCriteria(this);
1621
+
1622
+ if (!callback) {
1623
+ return Query.base.remove.call(this);
1624
+ }
1625
+
1626
+ return this._remove(callback);
1627
+ };
1628
+
1629
+ /*!
1630
+ * ignore
1631
+ */
1632
+
1633
+ Query.prototype._remove = function(callback) {
1634
+ if (this._castError) {
1635
+ callback(this._castError);
1614
1636
  return this;
1615
1637
  }
1616
1638
 
1617
- return Query.base.remove.call(this, cond, callback);
1639
+ return Query.base.remove.call(this, callback);
1618
1640
  };
1619
1641
 
1620
1642
  /**
@@ -1627,7 +1649,7 @@ Query.prototype.remove = function(cond, callback) {
1627
1649
  * Character.deleteOne({ name: 'Eddard Stark' }, callback)
1628
1650
  * Character.deleteOne({ name: 'Eddard Stark' }).then(next)
1629
1651
  *
1630
- * @param {Object|Query} [criteria] mongodb selector
1652
+ * @param {Object|Query} [filter] mongodb selector
1631
1653
  * @param {Function} [callback] optional params are (error, writeOpResult)
1632
1654
  * @return {Query} this
1633
1655
  * @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
@@ -1635,22 +1657,41 @@ Query.prototype.remove = function(cond, callback) {
1635
1657
  * @api public
1636
1658
  */
1637
1659
 
1638
- Query.prototype.deleteOne = function(cond, callback) {
1639
- if (typeof cond === 'function') {
1640
- callback = cond;
1641
- cond = null;
1660
+ Query.prototype.deleteOne = function(filter, callback) {
1661
+ if (typeof filter === 'function') {
1662
+ callback = filter;
1663
+ filter = null;
1642
1664
  }
1643
1665
 
1644
- var cb = typeof callback === 'function';
1666
+ filter = utils.toObject(filter, { retainKeyOrder: true });
1645
1667
 
1646
1668
  try {
1647
- this.cast(this.model);
1669
+ this.cast(this.model, filter);
1670
+ this.merge(filter);
1648
1671
  } catch (err) {
1649
- if (cb) return process.nextTick(callback.bind(null, err));
1672
+ this._castError = err;
1673
+ }
1674
+
1675
+ prepareDiscriminatorCriteria(this);
1676
+
1677
+ if (!callback) {
1678
+ return Query.base.deleteOne.call(this);
1679
+ }
1680
+
1681
+ return this._deleteOne.call(this, callback);
1682
+ };
1683
+
1684
+ /*!
1685
+ * ignore
1686
+ */
1687
+
1688
+ Query.prototype._deleteOne = function(callback) {
1689
+ if (this._castError) {
1690
+ callback(this._castError);
1650
1691
  return this;
1651
1692
  }
1652
1693
 
1653
- return Query.base.deleteOne.call(this, cond, callback);
1694
+ return Query.base.deleteOne.call(this, callback);
1654
1695
  };
1655
1696
 
1656
1697
  /**
@@ -1663,7 +1704,7 @@ Query.prototype.deleteOne = function(cond, callback) {
1663
1704
  * Character.deleteMany({ name: /Stark/, age: { $gte: 18 } }, callback)
1664
1705
  * Character.deleteMany({ name: /Stark/, age: { $gte: 18 } }).then(next)
1665
1706
  *
1666
- * @param {Object|Query} [criteria] mongodb selector
1707
+ * @param {Object|Query} [filter] mongodb selector
1667
1708
  * @param {Function} [callback] optional params are (error, writeOpResult)
1668
1709
  * @return {Query} this
1669
1710
  * @see writeOpResult http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#~WriteOpResult
@@ -1671,22 +1712,41 @@ Query.prototype.deleteOne = function(cond, callback) {
1671
1712
  * @api public
1672
1713
  */
1673
1714
 
1674
- Query.prototype.deleteMany = function(cond, callback) {
1675
- if (typeof cond === 'function') {
1676
- callback = cond;
1677
- cond = null;
1715
+ Query.prototype.deleteMany = function(filter, callback) {
1716
+ if (typeof filter === 'function') {
1717
+ callback = filter;
1718
+ filter = null;
1678
1719
  }
1679
1720
 
1680
- var cb = typeof callback === 'function';
1721
+ filter = utils.toObject(filter, { retainKeyOrder: true });
1681
1722
 
1682
1723
  try {
1683
- this.cast(this.model);
1724
+ this.cast(this.model, filter);
1725
+ this.merge(filter);
1684
1726
  } catch (err) {
1685
- if (cb) return process.nextTick(callback.bind(null, err));
1727
+ this._castError = err;
1728
+ }
1729
+
1730
+ prepareDiscriminatorCriteria(this);
1731
+
1732
+ if (!callback) {
1733
+ return Query.base.deleteMany.call(this);
1734
+ }
1735
+
1736
+ return this._deleteMany.call(this, callback);
1737
+ };
1738
+
1739
+ /*!
1740
+ * ignore
1741
+ */
1742
+
1743
+ Query.prototype._deleteMany = function(callback) {
1744
+ if (this._castError) {
1745
+ callback(this._castError);
1686
1746
  return this;
1687
1747
  }
1688
1748
 
1689
- return Query.base.deleteMany.call(this, cond, callback);
1749
+ return Query.base.deleteMany.call(this, callback);
1690
1750
  };
1691
1751
 
1692
1752
  /*!
@@ -104,10 +104,14 @@ Decimal128.prototype.cast = function(value, doc, init) {
104
104
  return ret;
105
105
  }
106
106
 
107
- if (value === null || value === undefined) {
107
+ if (value == null) {
108
108
  return value;
109
109
  }
110
110
 
111
+ if (typeof value === 'object' && typeof value.$numberDecimal === 'string') {
112
+ return Decimal128Type.fromString(value.$numberDecimal);
113
+ }
114
+
111
115
  if (value instanceof Decimal128Type) {
112
116
  return value;
113
117
  }
@@ -83,7 +83,7 @@ function Embedded(schema, path, options) {
83
83
 
84
84
  Embedded.prototype = Object.create(SchemaType.prototype);
85
85
 
86
- /**
86
+ /*!
87
87
  * Special case for when users use a common location schema to represent
88
88
  * locations for use with $geoWithin.
89
89
  * https://docs.mongodb.org/manual/reference/operator/query/geoWithin/
@@ -92,7 +92,7 @@ Embedded.prototype = Object.create(SchemaType.prototype);
92
92
  * @api private
93
93
  */
94
94
 
95
- Embedded.prototype.$conditionalHandlers.$geoWithin = function(val) {
95
+ Embedded.prototype.$conditionalHandlers.$geoWithin = function handle$geoWithin(val) {
96
96
  return { $geometry: this.castForQuery(val.$geometry) };
97
97
  };
98
98
 
@@ -198,10 +198,15 @@ function defaultId() {
198
198
  }
199
199
 
200
200
  function resetId(v) {
201
- if (v == null) {
201
+ Document || (Document = require('./../document'));
202
+
203
+ if (v === void 0) {
202
204
  return new oid();
203
205
  }
204
- this.$__._id = null;
206
+
207
+ if (this instanceof Document) {
208
+ delete this.$__._id;
209
+ }
205
210
  return v;
206
211
  }
207
212
 
package/lib/schema.js CHANGED
@@ -10,6 +10,7 @@ var MongooseTypes;
10
10
  var Kareem = require('kareem');
11
11
  var each = require('async/each');
12
12
  var SchemaType = require('./schematype');
13
+ var mpath = require('mpath');
13
14
 
14
15
  var IS_KAREEM_HOOK = {
15
16
  count: true,
@@ -202,16 +203,6 @@ Object.defineProperty(Schema.prototype, '_defaultMiddleware', {
202
203
  enumerable: false,
203
204
  writable: false,
204
205
  value: [
205
- {
206
- kind: 'pre',
207
- hook: 'validate',
208
- isAsync: true,
209
- fn: function(next, done) {
210
- // Hack to ensure that we always wrap validate() in a promise
211
- next();
212
- done();
213
- }
214
- },
215
206
  {
216
207
  kind: 'pre',
217
208
  hook: 'remove',
@@ -1473,22 +1464,23 @@ Schema.prototype.virtual = function(name, options) {
1473
1464
  }
1474
1465
 
1475
1466
  this.pre('init', function(next, obj) {
1476
- if (name in obj) {
1467
+ if (mpath.has(name, obj)) {
1468
+ var _v = mpath.get(name, obj);
1477
1469
  if (!this.$$populatedVirtuals) {
1478
1470
  this.$$populatedVirtuals = {};
1479
1471
  }
1480
1472
 
1481
1473
  if (options.justOne) {
1482
- this.$$populatedVirtuals[name] = Array.isArray(obj[name]) ?
1483
- obj[name][0] :
1484
- obj[name];
1474
+ this.$$populatedVirtuals[name] = Array.isArray(_v) ?
1475
+ _v[0] :
1476
+ _v;
1485
1477
  } else {
1486
- this.$$populatedVirtuals[name] = Array.isArray(obj[name]) ?
1487
- obj[name] :
1488
- obj[name] == null ? [] : [obj[name]];
1478
+ this.$$populatedVirtuals[name] = Array.isArray(_v) ?
1479
+ _v :
1480
+ _v == null ? [] : [_v];
1489
1481
  }
1490
1482
 
1491
- delete obj[name];
1483
+ mpath.unset(name, obj);
1492
1484
  }
1493
1485
  if (this.ownerDocument) {
1494
1486
  next();
@@ -1510,11 +1502,28 @@ Schema.prototype.virtual = function(name, options) {
1510
1502
  }
1511
1503
  return null;
1512
1504
  }).
1513
- set(function(v) {
1505
+ set(function(_v) {
1514
1506
  if (!this.$$populatedVirtuals) {
1515
1507
  this.$$populatedVirtuals = {};
1516
1508
  }
1517
- this.$$populatedVirtuals[name] = v;
1509
+
1510
+ if (options.justOne) {
1511
+ this.$$populatedVirtuals[name] = Array.isArray(_v) ?
1512
+ _v[0] :
1513
+ _v;
1514
+
1515
+ if (typeof this.$$populatedVirtuals[name] !== 'object') {
1516
+ this.$$populatedVirtuals[name] = null;
1517
+ }
1518
+ } else {
1519
+ this.$$populatedVirtuals[name] = Array.isArray(_v) ?
1520
+ _v :
1521
+ _v == null ? [] : [_v];
1522
+
1523
+ this.$$populatedVirtuals[name] = this.$$populatedVirtuals[name].filter(function(doc) {
1524
+ return doc && typeof doc === 'object';
1525
+ });
1526
+ }
1518
1527
  });
1519
1528
  }
1520
1529
 
package/lib/schematype.js CHANGED
@@ -762,7 +762,7 @@ SchemaType.prototype.doValidate = function(value, fn, scope) {
762
762
  if (validator instanceof RegExp) {
763
763
  validate(validator.test(value), validatorProperties);
764
764
  } else if (typeof validator === 'function') {
765
- if (value === undefined && !_this.isRequired) {
765
+ if (value === undefined && validator !== _this.requiredValidator) {
766
766
  validate(true, validatorProperties);
767
767
  return;
768
768
  }
@@ -86,6 +86,8 @@ function applyHooks(model, schema) {
86
86
  delete toWrap.set;
87
87
  }
88
88
 
89
+ toWrap.validate = toWrap.validate || { pre: [], post: [] };
90
+
89
91
  keys = Object.keys(toWrap);
90
92
  len = keys.length;
91
93
  for (i = 0; i < len; ++i) {
@@ -286,6 +286,5 @@ function castUpdateVal(schema, val, op, $conditional) {
286
286
  if (/^\$/.test($conditional)) {
287
287
  return schema.castForQuery($conditional, val);
288
288
  }
289
-
290
289
  return schema.castForQuery(val);
291
290
  }
@@ -146,7 +146,7 @@ module.exports = function(query, schema, castedDoc, options) {
146
146
  if (validationErrors.length) {
147
147
  var err = new ValidationError(null);
148
148
  for (var i = 0; i < validationErrors.length; ++i) {
149
- err.errors[validationErrors[i].path] = validationErrors[i];
149
+ err.addError(validationErrors[i].path, validationErrors[i]);
150
150
  }
151
151
  return callback(err);
152
152
  }
@@ -154,7 +154,7 @@ MongooseArray.mixin = {
154
154
  }
155
155
  }
156
156
 
157
- parent.markModified(dirtyPath);
157
+ parent.markModified(dirtyPath, elem);
158
158
  }
159
159
 
160
160
  return this;
@@ -196,7 +196,12 @@ EmbeddedDocument.prototype.update = function() {
196
196
  */
197
197
 
198
198
  EmbeddedDocument.prototype.inspect = function() {
199
- return this.toObject({ transform: false, retainKeyOrder: true, virtuals: false });
199
+ return this.toObject({
200
+ transform: false,
201
+ retainKeyOrder: true,
202
+ virtuals: false,
203
+ flattenDecimals: false
204
+ });
200
205
  };
201
206
 
202
207
  /**
@@ -51,6 +51,7 @@ Subdocument.prototype.$isValid = function(path) {
51
51
  if (this.$parent) {
52
52
  return this.$parent.$isValid([this.$basePath, path].join('.'));
53
53
  }
54
+ return Document.prototype.$isValid.call(this, path);
54
55
  };
55
56
 
56
57
  Subdocument.prototype.markModified = function(path) {
package/lib/utils.js CHANGED
@@ -289,6 +289,26 @@ exports.clone = function clone(obj, options) {
289
289
  };
290
290
  var clone = exports.clone;
291
291
 
292
+ /*!
293
+ * TODO: replace with Object.assign() in 5.0
294
+ */
295
+
296
+ exports.assign = function(target) {
297
+ for (var i = 1; i < arguments.length; ++i) {
298
+ var nextSource = arguments[i];
299
+
300
+ if (nextSource != null) {
301
+ for (var nextKey in nextSource) {
302
+ if (nextSource.hasOwnProperty(nextKey)) {
303
+ target[nextKey] = nextSource[nextKey];
304
+ }
305
+ }
306
+ }
307
+ }
308
+
309
+ return target;
310
+ };
311
+
292
312
  /*!
293
313
  * ignore
294
314
  */
@@ -841,7 +861,10 @@ exports.mergeClone = function(to, fromObj) {
841
861
  if (typeof to[key] === 'undefined') {
842
862
  // make sure to retain key order here because of a bug handling the $each
843
863
  // operator in mongodb 2.4.4
844
- to[key] = exports.clone(fromObj[key], {retainKeyOrder: 1});
864
+ to[key] = exports.clone(fromObj[key], {
865
+ retainKeyOrder: 1,
866
+ flattenDecimals: false
867
+ });
845
868
  } else {
846
869
  if (exports.isObject(fromObj[key])) {
847
870
  var obj = fromObj[key];
@@ -855,7 +878,10 @@ exports.mergeClone = function(to, fromObj) {
855
878
  } else {
856
879
  // make sure to retain key order here because of a bug handling the
857
880
  // $each operator in mongodb 2.4.4
858
- to[key] = exports.clone(fromObj[key], {retainKeyOrder: 1});
881
+ to[key] = exports.clone(fromObj[key], {
882
+ retainKeyOrder: 1,
883
+ flattenDecimals: false
884
+ });
859
885
  }
860
886
  }
861
887
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "4.10.4",
4
+ "version": "4.10.8",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
@@ -24,7 +24,7 @@
24
24
  "hooks-fixed": "2.0.0",
25
25
  "kareem": "1.4.1",
26
26
  "mongodb": "2.2.27",
27
- "mpath": "0.2.1",
27
+ "mpath": "0.3.0",
28
28
  "mpromise": "0.5.5",
29
29
  "mquery": "2.3.1",
30
30
  "ms": "2.0.0",
@@ -36,7 +36,7 @@
36
36
  "acquit": "0.4.1",
37
37
  "acquit-ignore": "0.0.3",
38
38
  "benchmark": "2.1.2",
39
- "bluebird": "3.4.6",
39
+ "bluebird": "3.5.0",
40
40
  "co": "4.6.0",
41
41
  "dox": "0.3.1",
42
42
  "eslint": "2.4.0",
package/mongodb-cert.key DELETED
File without changes