mongoose 5.1.1 → 5.1.2

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/History.md CHANGED
@@ -1,3 +1,24 @@
1
+ 5.1.2 / 2018-05-21
2
+ ==================
3
+ * docs(guide): add missing SchemaTypes #6490 [distancesprinter](https://github.com/distancesprinter)
4
+ * fix(map): make MongooseMap.toJSON return a serialized object #6486 #6478 [lineus](https://github.com/lineus)
5
+ * fix(query): make CustomQuery inherit from model.Query for hooks #6483 #6455 [lineus](https://github.com/lineus)
6
+ * fix(document): prevent default falses from being skipped by $__dirty #6481 #6477 [lineus](https://github.com/lineus)
7
+ * docs(connection): document `useDb()` #6480
8
+ * fix(model): skip redundant clone in insertMany #6479 [d1manson](https://github.com/d1manson)
9
+ * fix(aggregate): let replaceRoot accept objects as well as strings #6475 #6474 [lineus](https://github.com/lineus)
10
+ * docs(model): clarify `emit()` in mapReduce and how map/reduce are run #6465
11
+ * fix(populate): flatten array to handle multi-level nested `refPath` #6457
12
+ * fix(date): cast small numeric strings as years #6444 [AbdelrahmanHafez](https://github.com/AbdelrahmanHafez)
13
+ * fix(populate): remove unmatched ids when using virtual populate on already hydrated document #6435
14
+ * fix(array): use custom array class to avoid clobbered property names #6431
15
+ * fix(model): handle hooks for custom methods that return promises #6385
16
+
17
+ 4.13.13 / 2018-05-17
18
+ ====================
19
+ * fix(update): stop clobbering $in when casting update #6441 #6339
20
+ * fix: upgrade async -> 2.6.0 re: security warning
21
+
1
22
  5.1.1 / 2018-05-14
2
23
  ==================
3
24
  * docs(schema): add notes in api and guide about schema.methods object #6470 #6440 [lineus](https://github.com/lineus)
package/lib/aggregate.js CHANGED
@@ -342,23 +342,34 @@ Aggregate.prototype.unwind = function() {
342
342
  /**
343
343
  * Appends a new $replaceRoot operator to this aggregate pipeline.
344
344
  *
345
- * Note that the `$replaceRoot` operator requires the new root to start with '$'.
346
- * Mongoose will prepend '$' if the specified field doesn't start '$'.
345
+ * Note that the `$replaceRoot` operator requires field strings to start with '$'.
346
+ * If you are passing in a string Mongoose will prepend '$' if the specified field doesn't start '$'.
347
+ * If you are passing in an object the strings in your expression will not be altered.
347
348
  *
348
349
  * ####Examples:
349
350
  *
350
351
  * aggregate.replaceRoot("user");
351
352
  *
353
+ * aggregate.replaceRoot({ x: { $concat: ['$this', '$that'] } });
354
+ *
352
355
  * @see $replaceRoot https://docs.mongodb.org/manual/reference/operator/aggregation/replaceRoot
353
- * @param {String} the field which will become the new root document
356
+ * @param {String|Object} the field or document which will become the new root document
354
357
  * @return {Aggregate}
355
358
  * @api public
356
359
  */
357
360
 
358
361
  Aggregate.prototype.replaceRoot = function(newRoot) {
362
+ var ret;
363
+
364
+ if (typeof newRoot === 'string') {
365
+ ret = newRoot.startsWith('$') ? newRoot : '$' + newRoot;
366
+ } else {
367
+ ret = newRoot;
368
+ }
369
+
359
370
  return this.append({
360
371
  $replaceRoot: {
361
- newRoot: (newRoot && newRoot.charAt(0) === '$') ? newRoot : '$' + newRoot
372
+ newRoot: ret
362
373
  }
363
374
  });
364
375
  };
package/lib/connection.js CHANGED
@@ -770,6 +770,18 @@ Connection.prototype.optionsProvideAuthenticationData = function(options) {
770
770
  ((options.pass) || this.authMechanismDoesNotRequirePassword());
771
771
  };
772
772
 
773
+ /**
774
+ * Switches to a different database using the same connection pool.
775
+ *
776
+ * Returns a new connection object, with the new db.
777
+ *
778
+ * @method useDb
779
+ * @memberOf Connection
780
+ * @param {String} name The database name
781
+ * @return {Connection} New Connection Object
782
+ * @api public
783
+ */
784
+
773
785
  /*!
774
786
  * Module exports.
775
787
  */
package/lib/document.js CHANGED
@@ -2003,7 +2003,7 @@ Document.prototype.$__dirty = function() {
2003
2003
  // gh-2558: if we had to set a default and the value is not undefined,
2004
2004
  // we have to save as well
2005
2005
  all = all.concat(this.$__.activePaths.map('default', function(path) {
2006
- if (path === '_id' || !_this.getValue(path)) {
2006
+ if (path === '_id' || _this.getValue(path) == null) {
2007
2007
  return;
2008
2008
  }
2009
2009
  return {
@@ -2680,7 +2680,6 @@ Document.prototype.populate = function populate() {
2680
2680
  if (fn) {
2681
2681
  var paths = utils.object.vals(pop);
2682
2682
  this.$__.populate = undefined;
2683
- paths.__noPromise = true;
2684
2683
  var topLevelModel = this.constructor;
2685
2684
  if (this.$__isNested) {
2686
2685
  topLevelModel = this.$__.scope.constructor;
package/lib/model.js CHANGED
@@ -2365,7 +2365,9 @@ Model.$__insertMany = function(arr, options, callback) {
2365
2365
  var validationErrors = [];
2366
2366
  arr.forEach(function(doc) {
2367
2367
  toExecute.push(function(callback) {
2368
- doc = new _this(doc);
2368
+ if (!(doc instanceof _this)) {
2369
+ doc = new _this(doc);
2370
+ }
2369
2371
  doc.validate({ __noPromise: true }, function(error) {
2370
2372
  if (error) {
2371
2373
  // Option `ordered` signals that insert should be continued after reaching
@@ -2822,8 +2824,10 @@ function _update(model, op, conditions, doc, options, callback) {
2822
2824
  * ####Example:
2823
2825
  *
2824
2826
  * var o = {};
2825
- * o.map = function () { emit(this.name, 1) }
2826
- * o.reduce = function (k, vals) { return vals.length }
2827
+ * // `map()` and `reduce()` are run on the MongoDB server, not Node.js,
2828
+ * // these functions are converted to strings
2829
+ * o.map = function () { emit(this.name, 1) };
2830
+ * o.reduce = function (k, vals) { return vals.length };
2827
2831
  * User.mapReduce(o, function (err, results) {
2828
2832
  * console.log(results)
2829
2833
  * })
@@ -2853,8 +2857,10 @@ function _update(model, op, conditions, doc, options, callback) {
2853
2857
  * ####Example:
2854
2858
  *
2855
2859
  * var o = {};
2856
- * o.map = function () { emit(this.name, 1) }
2857
- * o.reduce = function (k, vals) { return vals.length }
2860
+ * // You can also define `map()` and `reduce()` as strings if your
2861
+ * // linter complains about `emit()` not being defined
2862
+ * o.map = 'function () { emit(this.name, 1) }';
2863
+ * o.reduce = 'function (k, vals) { return vals.length }';
2858
2864
  * o.out = { replace: 'createdCollectionNameForResults' }
2859
2865
  * o.verbose = true;
2860
2866
  *
@@ -3485,7 +3491,7 @@ function assignVals(o) {
3485
3491
  if (o.isVirtual && docs[i].constructor.name === 'model') {
3486
3492
  // If virtual populate and doc is already init-ed, need to walk through
3487
3493
  // the actual doc to set rather than setting `_doc` directly
3488
- mpath.set(o.path, rawIds[i], docs[i]);
3494
+ mpath.set(o.path, rawIds[i], docs[i], setValue);
3489
3495
  } else {
3490
3496
  var parts = o.path.split('.');
3491
3497
  var cur = docs[i];
@@ -3754,7 +3760,11 @@ function getModelsMapForPopulate(model, docs, options) {
3754
3760
 
3755
3761
  if (refPath) {
3756
3762
  modelNames = utils.getValue(refPath, doc);
3757
- isRefPathArray = Array.isArray(modelNames);
3763
+ isRefPathArray = false;
3764
+ if (Array.isArray(modelNames)) {
3765
+ isRefPathArray = true;
3766
+ modelNames = utils.array.flatten(modelNames);
3767
+ }
3758
3768
  } else {
3759
3769
  if (!modelNameFromQuery) {
3760
3770
  var modelForCurrentDoc = model;
@@ -3838,7 +3848,7 @@ function convertTo_id(val) {
3838
3848
  val[i] = val[i]._id;
3839
3849
  }
3840
3850
  }
3841
- if (val.isMongooseArray) {
3851
+ if (val.isMongooseArray && val._schema) {
3842
3852
  return val._schema.cast(val, val._parent);
3843
3853
  }
3844
3854
 
package/lib/query.js CHANGED
@@ -167,7 +167,7 @@ Query.prototype.toConstructor = function toConstructor() {
167
167
  Query.call(this, criteria, options || null, model, coll);
168
168
  };
169
169
 
170
- util.inherits(CustomQuery, Query);
170
+ util.inherits(CustomQuery, model.Query);
171
171
 
172
172
  // set inherited defaults
173
173
  var p = CustomQuery.prototype;
@@ -1309,7 +1309,7 @@ Query.prototype._find = function(callback) {
1309
1309
 
1310
1310
  if (this.error() != null) {
1311
1311
  callback(this.error());
1312
- return this;
1312
+ return null;
1313
1313
  }
1314
1314
 
1315
1315
  this._applyPaths();
@@ -1355,7 +1355,8 @@ Query.prototype._find = function(callback) {
1355
1355
  var options = this._optionsForExec();
1356
1356
  options.fields = this._fieldsForExec();
1357
1357
  var filter = this._conditions;
1358
- return this._collection.find(filter, options, cb);
1358
+ this._collection.find(filter, options, cb);
1359
+ return null;
1359
1360
  };
1360
1361
 
1361
1362
  /**
@@ -1517,7 +1518,8 @@ Query.prototype._findOne = function(callback) {
1517
1518
  this._castConditions();
1518
1519
 
1519
1520
  if (this.error()) {
1520
- return callback(this.error());
1521
+ callback(this.error());
1522
+ return null;
1521
1523
  }
1522
1524
 
1523
1525
  this._applyPaths();
@@ -1526,7 +1528,8 @@ Query.prototype._findOne = function(callback) {
1526
1528
  // don't pass in the conditions because we already merged them in
1527
1529
  Query.base.findOne.call(this, {}, (err, doc) => {
1528
1530
  if (err) {
1529
- return callback(err);
1531
+ callback(err);
1532
+ return null;
1530
1533
  }
1531
1534
 
1532
1535
  this._completeOne(doc, null, callback);
@@ -2161,7 +2164,6 @@ Query.prototype._findOneAndUpdate = function(callback) {
2161
2164
  }
2162
2165
 
2163
2166
  this._findAndModify('update', callback);
2164
- return this;
2165
2167
  };
2166
2168
 
2167
2169
  /**
@@ -2336,7 +2338,7 @@ Query.prototype._findOneAndDelete = function(callback) {
2336
2338
 
2337
2339
  if (this.error() != null) {
2338
2340
  callback(this.error());
2339
- return this;
2341
+ return null;
2340
2342
  }
2341
2343
 
2342
2344
  const filter = this._conditions;
@@ -2348,7 +2350,7 @@ Query.prototype._findOneAndDelete = function(callback) {
2348
2350
  fields = options.projection;
2349
2351
  if (fields instanceof Error) {
2350
2352
  callback(fields);
2351
- return this;
2353
+ return null;
2352
2354
  }
2353
2355
  }
2354
2356
 
@@ -2361,8 +2363,6 @@ Query.prototype._findOneAndDelete = function(callback) {
2361
2363
 
2362
2364
  return this._completeOne(doc, res, callback);
2363
2365
  });
2364
-
2365
- return this;
2366
2366
  };
2367
2367
 
2368
2368
  /*!
@@ -2374,12 +2374,11 @@ Query.prototype._findOneAndDelete = function(callback) {
2374
2374
  */
2375
2375
  Query.prototype._findOneAndRemove = function(callback) {
2376
2376
  if (this.error() != null) {
2377
- return callback(this.error());
2377
+ callback(this.error());
2378
+ return;
2378
2379
  }
2379
2380
 
2380
2381
  this._findAndModify('remove', callback);
2381
-
2382
- return this;
2383
2382
  };
2384
2383
 
2385
2384
  /*!
@@ -2644,7 +2643,7 @@ function _updateThunk(op, callback) {
2644
2643
 
2645
2644
  if (this.error() != null) {
2646
2645
  callback(this.error());
2647
- return this;
2646
+ return null;
2648
2647
  }
2649
2648
 
2650
2649
  var castedQuery = this._conditions;
@@ -2660,12 +2659,12 @@ function _updateThunk(op, callback) {
2660
2659
 
2661
2660
  if (castedDoc instanceof Error) {
2662
2661
  callback(castedDoc);
2663
- return this;
2662
+ return null;
2664
2663
  }
2665
2664
 
2666
2665
  if (castedDoc == null || Object.keys(castedDoc).length === 0) {
2667
2666
  callback(null, 0);
2668
- return this;
2667
+ return null;
2669
2668
  }
2670
2669
 
2671
2670
  castedDoc = setDefaultsOnInsert(this._conditions, this.model.schema,
@@ -2697,7 +2696,7 @@ function _updateThunk(op, callback) {
2697
2696
  callback(err);
2698
2697
  });
2699
2698
  }
2700
- return this;
2699
+ return null;
2701
2700
  }
2702
2701
 
2703
2702
  if (castedDoc.toBSON) {
@@ -2705,7 +2704,7 @@ function _updateThunk(op, callback) {
2705
2704
  }
2706
2705
 
2707
2706
  this._collection[op](castedQuery, castedDoc, options, callback);
2708
- return this;
2707
+ return null;
2709
2708
  }
2710
2709
 
2711
2710
  /*!
@@ -232,9 +232,12 @@ SchemaDate.prototype.cast = function(value) {
232
232
 
233
233
  if (value instanceof Number || typeof value === 'number') {
234
234
  date = new Date(value);
235
+ } else if (typeof value === 'string' && !isNaN(Number(value)) && (Number(value) >= 275761 || Number(value) < -271820)) {
236
+ // string representation of milliseconds take this path
237
+ date = new Date(Number(value));
235
238
  } else if (typeof value.valueOf === 'function') {
236
- // support for moment.js. This is also the path strings will take because strings
237
- // have a `valueOf()`
239
+ // support for moment.js. This is also the path strings will take because
240
+ // strings have a `valueOf()`
238
241
  date = new Date(value.valueOf());
239
242
  } else {
240
243
  // fallback
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ const utils = require('../../utils');
4
+
3
5
  /*!
4
6
  * ignore
5
7
  */
@@ -54,6 +56,13 @@ function applyHooks(model, schema, options) {
54
56
 
55
57
  // Support hooks for custom methods
56
58
  const customMethods = Object.keys(schema.methods);
59
+ const customMethodOptions = Object.assign({}, kareemOptions, {
60
+ // Only use `checkForPromise` for custom methods, because mongoose
61
+ // query thunks are not as consistent as I would like about returning
62
+ // a nullish value rather than the query. If a query thunk returns
63
+ // a query, `checkForPromise` causes infinite recursion
64
+ checkForPromise: true
65
+ });
57
66
  for (const method of customMethods) {
58
67
  if (!schema.s.hooks.hasHooks(method)) {
59
68
  // Don't wrap if there are no hooks for the custom method to avoid
@@ -61,7 +70,18 @@ function applyHooks(model, schema, options) {
61
70
  // so wrapping a sync method would break it.
62
71
  continue;
63
72
  }
64
- objToDecorate[method] = schema.s.hooks.
65
- createWrapper(method, objToDecorate[method], null, kareemOptions);
73
+ const originalMethod = objToDecorate[method];
74
+ objToDecorate[method] = function() {
75
+ const args = Array.prototype.slice.call(arguments);
76
+ const cb = utils.last(args);
77
+ const argsWithoutCallback = cb == null ? args :
78
+ args.slice(0, args.length - 1);
79
+ return utils.promiseOrCallback(cb, callback => {
80
+ this[`$__${method}`].apply(this,
81
+ argsWithoutCallback.concat([callback]));
82
+ });
83
+ };
84
+ objToDecorate[`$__${method}`] = schema.s.hooks.
85
+ createWrapper(method, originalMethod, null, customMethodOptions);
66
86
  }
67
87
  }
@@ -12,6 +12,18 @@ const utils = require('../utils');
12
12
  const Document = require('../document');
13
13
  const getDiscriminatorByValue = require('../queryhelpers').getDiscriminatorByValue;
14
14
 
15
+ /*!
16
+ * ignore
17
+ */
18
+
19
+ class CoreMongooseArray extends Array {
20
+ get isMongooseArray() {
21
+ return true;
22
+ }
23
+
24
+ remove() {}
25
+ }
26
+
15
27
  /**
16
28
  * DocumentArray constructor
17
29
  *
@@ -25,11 +37,13 @@ const getDiscriminatorByValue = require('../queryhelpers').getDiscriminatorByVal
25
37
  */
26
38
 
27
39
  function MongooseDocumentArray(values, path, doc) {
28
- var arr = [].concat(values);
40
+ // TODO: replace this with `new CoreMongooseArray().concat()` when we remove
41
+ // support for node 4.x and 5.x, see https://i.imgur.com/UAAHk4S.png
42
+ var arr = new CoreMongooseArray();
43
+ if (Array.isArray(values)) values.forEach(v => arr.push(v));
29
44
  arr._path = path;
30
45
 
31
46
  var props = {
32
- isMongooseArray: true,
33
47
  isMongooseDocumentArray: true,
34
48
  validators: [],
35
49
  _atomics: {},
package/lib/types/map.js CHANGED
@@ -91,7 +91,12 @@ class MongooseMap extends Map {
91
91
  }
92
92
 
93
93
  toJSON() {
94
- return new Map(this);
94
+ let ret = {};
95
+ const keys = this.keys();
96
+ for (let key of keys) {
97
+ ret[key] = this.get(key);
98
+ }
99
+ return ret;
95
100
  }
96
101
 
97
102
  inspect() {
package/lib/utils.js CHANGED
@@ -137,6 +137,17 @@ exports.deepEqual = function deepEqual(a, b) {
137
137
  return true;
138
138
  };
139
139
 
140
+ /*!
141
+ * Get the last element of an array
142
+ */
143
+
144
+ exports.last = function(arr) {
145
+ if (arr.length > 0) {
146
+ return arr[arr.length - 1];
147
+ }
148
+ return void 0;
149
+ };
150
+
140
151
  /*!
141
152
  * Object clone with Mongoose natives support.
142
153
  *
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "5.1.1",
4
+ "version": "5.1.2",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
@@ -21,7 +21,7 @@
21
21
  "dependencies": {
22
22
  "async": "2.1.4",
23
23
  "bson": "~1.0.5",
24
- "kareem": "2.0.7",
24
+ "kareem": "2.1.0",
25
25
  "lodash.get": "4.4.2",
26
26
  "mongodb": "3.0.8",
27
27
  "mongoose-legacy-pluralize": "1.0.2",
@@ -32,7 +32,7 @@
32
32
  "sliced": "1.0.1"
33
33
  },
34
34
  "devDependencies": {
35
- "acquit": "0.5.1",
35
+ "acquit": "0.6.3",
36
36
  "acquit-ignore": "0.0.3",
37
37
  "benchmark": "2.1.2",
38
38
  "bluebird": "3.5.0",