mongoose 5.0.17 → 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/.travis.yml CHANGED
@@ -1,6 +1,7 @@
1
1
  language: node_js
2
2
  sudo: false
3
3
  node_js:
4
+ - "10"
4
5
  - "9"
5
6
  - "8"
6
7
  - "7"
@@ -8,11 +9,11 @@ node_js:
8
9
  - "5"
9
10
  - "4"
10
11
  before_script:
11
- - wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.0.15.tgz
12
- - tar -zxvf mongodb-linux-x86_64-3.0.15.tgz
12
+ - wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.6.4.tgz
13
+ - tar -zxvf mongodb-linux-x86_64-3.6.4.tgz
13
14
  - mkdir -p ./data/db/27017
14
15
  - mkdir -p ./data/db/27000
15
- - ./mongodb-linux-x86_64-3.0.15/bin/mongod --storageEngine mmapv1 --fork --nopreallocj --dbpath ./data/db/27017 --syslog --port 27017
16
+ - ./mongodb-linux-x86_64-3.6.4/bin/mongod --fork --nopreallocj --dbpath ./data/db/27017 --syslog --port 27017
16
17
  script:
17
18
  - npm test
18
19
  - npm run lint
package/History.md CHANGED
@@ -1,3 +1,64 @@
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
+
22
+ 5.1.1 / 2018-05-14
23
+ ==================
24
+ * docs(schema): add notes in api and guide about schema.methods object #6470 #6440 [lineus](https://github.com/lineus)
25
+ * fix(error): add modified paths to VersionError #6464 #6433 [paglias](https://github.com/paglias)
26
+ * fix(populate): only call populate with full param signature when match is not present #6458 #6451 [lineus](https://github.com/lineus)
27
+ * docs: fix geoNear link in migration guide #6450 [kawache](https://github.com/kawache)
28
+ * fix(discriminator): throw readable error when `create()` with a non-existent discriminator key #6434
29
+ * fix(populate): add `retainNullValues` option to avoid stripping out null keys #6432
30
+ * fix(populate): handle populate in embedded discriminators underneath nested paths #6411
31
+ * docs(model): add change streams and ToC, make terminology more consistent #5888
32
+
33
+ 5.1.0 / 2018-05-10
34
+ ==================
35
+ * feat(ObjectId): add `_id` getter so you can get a usable id whether or not the path is populated #6415 #6115
36
+ * feat(model): add Model.startSession() #6362
37
+ * feat(document): add doc.$session() and set session on doc after query #6362
38
+ * feat: add Map type that supports arbitrary keys #6287 #681
39
+ * feat: add `cloneSchemas` option to mongoose global to opt in to always cloning schemas before use #6274
40
+ * feat(model): add `findOneAndDelete()` and `findByIdAndDelete()` #6164
41
+ * feat(document): support `$ignore()` on single nested and array subdocs #6152
42
+ * feat(document): add warning about calling `save()` on subdocs #6152
43
+ * fix(model): make `save()` use `updateOne()` instead of `update()` #6031
44
+ * feat(error): add version number to VersionError #5966
45
+ * fix(query): allow `[]` as a value for `$in` when casting #5913
46
+ * fix(document): avoid running validators on single nested paths if only a child path is modified #5885
47
+ * feat(schema): print warning if method conflicts with mongoose internals #5860
48
+
49
+ 5.0.18 / 2018-05-09
50
+ ===================
51
+ * fix(update): stop clobbering $in when casting update #6441 #6339 [lineus](https://github.com/lineus)
52
+ * fix: upgrade mongodb driver -> 3.0.8 to fix session issue #6437 #6357 [simllll](https://github.com/simllll)
53
+ * fix: upgrade bson -> 1.0.5 re: https://snyk.io/vuln/npm:bson:20180225 #6423 [ChristianMurphy](https://github.com/ChristianMurphy)
54
+ * fix: look for `valueOf()` when casting to Decimal128 #6419 #6418 [lineus](https://github.com/lineus)
55
+ * fix: populate array of objects with space separated paths #6414 [lineus](https://github.com/lineus)
56
+ * test: add coverage for `mongoose.pluralize()` #6412 [FastDeath](https://github.com/FastDeath)
57
+ * fix(document): avoid running default functions on init() if path has value #6410
58
+ * fix(document): allow saving document with `null` id #6406
59
+ * fix: prevent casting of populated docs in document.init #6390 [lineus](https://github.com/lineus)
60
+ * fix: remove `toHexString()` helper that was added in 5.0.15 #6359
61
+
1
62
  5.0.17 / 2018-04-30
2
63
  ===================
3
64
  * docs(migration): certain chars in passwords may cause connection failures #6401 [markstos](https://github.com/markstos)
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
@@ -94,7 +94,7 @@ function Document(obj, fields, skipId, options) {
94
94
  $__hasIncludedChildren(fields) :
95
95
  {};
96
96
 
97
- this.$__buildDoc(obj, fields, skipId, exclude, hasIncludedChildren);
97
+ this.$__buildDoc(obj, fields, skipId, exclude, hasIncludedChildren, false);
98
98
 
99
99
  // By default, defaults get applied **before** setting initial values
100
100
  // Re: gh-6155
@@ -115,7 +115,7 @@ function Document(obj, fields, skipId, options) {
115
115
  // Function defaults get applied **after** setting initial values so they
116
116
  // see the full doc rather than an empty one, unless they opt out.
117
117
  // Re: gh-3781, gh-6155
118
- $__applyDefaults(this, fields, skipId, exclude, hasIncludedChildren, false);
118
+ $__applyDefaults(this, fields, skipId, exclude, hasIncludedChildren, false, options.skipDefaults);
119
119
 
120
120
  this.$__._id = this._id;
121
121
 
@@ -218,7 +218,7 @@ function $__hasIncludedChildren(fields) {
218
218
  * ignore
219
219
  */
220
220
 
221
- function $__applyDefaults(doc, fields, skipId, exclude, hasIncludedChildren, isBeforeSetters) {
221
+ function $__applyDefaults(doc, fields, skipId, exclude, hasIncludedChildren, isBeforeSetters, pathsToSkip) {
222
222
  const paths = Object.keys(doc.schema.paths);
223
223
  const plen = paths.length;
224
224
 
@@ -274,6 +274,10 @@ function $__applyDefaults(doc, fields, skipId, exclude, hasIncludedChildren, isB
274
274
  continue;
275
275
  }
276
276
 
277
+ if (pathsToSkip && pathsToSkip[curPath]) {
278
+ break;
279
+ }
280
+
277
281
  if (fields && exclude !== null) {
278
282
  if (exclude === true) {
279
283
  // apply defaults to all non-excluded fields
@@ -322,7 +326,10 @@ function $__applyDefaults(doc, fields, skipId, exclude, hasIncludedChildren, isB
322
326
  Document.prototype.$__buildDoc = function(obj, fields, skipId, exclude, hasIncludedChildren) {
323
327
  const doc = {};
324
328
 
325
- const paths = Object.keys(this.schema.paths);
329
+ const paths = Object.keys(this.schema.paths).
330
+ // Don't build up any paths that are underneath a map, we don't know
331
+ // what the keys will be
332
+ filter(p => !p.includes('$*'));
326
333
  const plen = paths.length;
327
334
  let ii = 0;
328
335
 
@@ -486,7 +493,9 @@ function init(self, obj, doc, prefix) {
486
493
  if (obj[i] === null) {
487
494
  doc[i] = null;
488
495
  } else if (obj[i] !== undefined) {
489
- if (schema) {
496
+ let intCache = obj[i].$__ || {};
497
+ let wasPopulated = intCache.wasPopulated || null;
498
+ if (schema && !wasPopulated) {
490
499
  try {
491
500
  doc[i] = schema.cast(obj[i], self, true);
492
501
  } catch (e) {
@@ -535,6 +544,26 @@ Document.prototype.update = function update() {
535
544
  return this.constructor.update.apply(this.constructor, args);
536
545
  };
537
546
 
547
+ /**
548
+ * Getter/setter around the session associated with this document. Used to
549
+ * automatically set `session` if you `save()` a doc that you got from a
550
+ * query with an associated session.
551
+ *
552
+ * @param {ClientSession} [session] overwrite the current session
553
+ * @return {ClientSession}
554
+ * @method $session
555
+ * @api public
556
+ * @memberOf Document
557
+ */
558
+
559
+ Document.prototype.$session = function $session(session) {
560
+ if (arguments.length === 0) {
561
+ return this.$__.session;
562
+ }
563
+ this.$__.session = session;
564
+ return session;
565
+ };
566
+
538
567
  /**
539
568
  * Alias for `set()`, used internally to avoid conflicts
540
569
  *
@@ -972,7 +1001,11 @@ Document.prototype.$__set = function(pathToMark, path, constructing, parts, sche
972
1001
  cur += (cur ? '.' + parts[i] : parts[i]);
973
1002
 
974
1003
  if (last) {
975
- obj[parts[i]] = val;
1004
+ if (obj instanceof Map) {
1005
+ obj.set(parts[i], val);
1006
+ } else {
1007
+ obj[parts[i]] = val;
1008
+ }
976
1009
  } else {
977
1010
  if (obj[parts[i]] && utils.getFunctionName(obj[parts[i]].constructor) === 'Object') {
978
1011
  obj = obj[parts[i]];
@@ -1049,9 +1082,13 @@ Document.prototype.get = function(path, type, options) {
1049
1082
  }
1050
1083
 
1051
1084
  for (var i = 0, l = pieces.length; i < l; i++) {
1052
- obj = obj === null || obj === void 0
1053
- ? undefined
1054
- : obj[pieces[i]];
1085
+ if (obj == null) {
1086
+ obj = void 0;
1087
+ } else if (obj instanceof Map) {
1088
+ obj = obj.get(pieces[i]);
1089
+ } else {
1090
+ obj = obj[pieces[i]];
1091
+ }
1055
1092
  }
1056
1093
 
1057
1094
  if (adhoc) {
@@ -1479,6 +1516,7 @@ Document.prototype.validate = function(options, callback) {
1479
1516
  function _getPathsToValidate(doc) {
1480
1517
  var i;
1481
1518
  var len;
1519
+ var skipSchemaValidators = {};
1482
1520
 
1483
1521
  // only validate required fields when necessary
1484
1522
  var paths = Object.keys(doc.$__.activePaths.states.require).filter(function(path) {
@@ -1511,6 +1549,7 @@ function _getPathsToValidate(doc) {
1511
1549
  return p != null && p.indexOf(subdoc.$basePath + '.') !== 0;
1512
1550
  });
1513
1551
  paths.push(subdoc.$basePath);
1552
+ skipSchemaValidators[subdoc.$basePath] = true;
1514
1553
  }
1515
1554
  }
1516
1555
  }
@@ -1557,7 +1596,24 @@ function _getPathsToValidate(doc) {
1557
1596
  }
1558
1597
  }
1559
1598
 
1560
- return paths;
1599
+ len = paths.length;
1600
+ for (i = 0; i < len; ++i) {
1601
+ const path = paths[i];
1602
+ const _pathType = doc.schema.path(path);
1603
+ if (!_pathType || !_pathType.$isSchemaMap) {
1604
+ continue;
1605
+ }
1606
+
1607
+ const val = doc.getValue(path);
1608
+ if (val == null) {
1609
+ continue;
1610
+ }
1611
+ for (let key of val.keys()) {
1612
+ paths.push(path + '.' + key);
1613
+ }
1614
+ }
1615
+
1616
+ return [paths, skipSchemaValidators];
1561
1617
  }
1562
1618
 
1563
1619
  /*!
@@ -1584,7 +1640,9 @@ Document.prototype.$__validate = function(callback) {
1584
1640
  };
1585
1641
 
1586
1642
  // only validate required fields when necessary
1587
- const paths = _getPathsToValidate(this);
1643
+ const pathDetails = _getPathsToValidate(this);
1644
+ const paths = pathDetails[0];
1645
+ const skipSchemaValidators = pathDetails[1];
1588
1646
 
1589
1647
  if (paths.length === 0) {
1590
1648
  return process.nextTick(function() {
@@ -1621,6 +1679,7 @@ Document.prototype.$__validate = function(callback) {
1621
1679
 
1622
1680
  process.nextTick(function() {
1623
1681
  const p = _this.schema.path(path);
1682
+
1624
1683
  if (!p) {
1625
1684
  return --total || complete();
1626
1685
  }
@@ -1641,7 +1700,7 @@ Document.prototype.$__validate = function(callback) {
1641
1700
  _this.invalidate(path, err, undefined, true);
1642
1701
  }
1643
1702
  --total || complete();
1644
- }, scope);
1703
+ }, scope, { skipSchemaValidators: skipSchemaValidators[path] });
1645
1704
  });
1646
1705
  };
1647
1706
 
@@ -1673,14 +1732,16 @@ Document.prototype.$__validate = function(callback) {
1673
1732
  */
1674
1733
 
1675
1734
  Document.prototype.validateSync = function(pathsToValidate) {
1676
- var _this = this;
1735
+ const _this = this;
1677
1736
 
1678
1737
  if (typeof pathsToValidate === 'string') {
1679
1738
  pathsToValidate = pathsToValidate.split(' ');
1680
1739
  }
1681
1740
 
1682
1741
  // only validate required fields when necessary
1683
- var paths = _getPathsToValidate(this);
1742
+ const pathDetails = _getPathsToValidate(this);
1743
+ let paths = pathDetails[0];
1744
+ const skipSchemaValidators = pathDetails[1];
1684
1745
 
1685
1746
  if (pathsToValidate && pathsToValidate.length) {
1686
1747
  var tmp = [];
@@ -1710,7 +1771,9 @@ Document.prototype.validateSync = function(pathsToValidate) {
1710
1771
  }
1711
1772
 
1712
1773
  var val = _this.getValue(path);
1713
- var err = p.doValidateSync(val, _this);
1774
+ var err = p.doValidateSync(val, _this, {
1775
+ skipSchemaValidators: skipSchemaValidators[path]
1776
+ });
1714
1777
  if (err) {
1715
1778
  _this.invalidate(path, err, undefined, true);
1716
1779
  }
@@ -1940,7 +2003,7 @@ Document.prototype.$__dirty = function() {
1940
2003
  // gh-2558: if we had to set a default and the value is not undefined,
1941
2004
  // we have to save as well
1942
2005
  all = all.concat(this.$__.activePaths.map('default', function(path) {
1943
- if (path === '_id' || !_this.getValue(path)) {
2006
+ if (path === '_id' || _this.getValue(path) == null) {
1944
2007
  return;
1945
2008
  }
1946
2009
  return {
@@ -2617,7 +2680,6 @@ Document.prototype.populate = function populate() {
2617
2680
  if (fn) {
2618
2681
  var paths = utils.object.vals(pop);
2619
2682
  this.$__.populate = undefined;
2620
- paths.__noPromise = true;
2621
2683
  var topLevelModel = this.constructor;
2622
2684
  if (this.$__isNested) {
2623
2685
  topLevelModel = this.$__.scope.constructor;
@@ -2685,7 +2747,6 @@ Document.prototype.execPopulate = function() {
2685
2747
 
2686
2748
  Document.prototype.populated = function(path, val, options) {
2687
2749
  // val and options are internal
2688
-
2689
2750
  if (val === null || val === void 0) {
2690
2751
  if (!this.$__.populated) {
2691
2752
  return undefined;
@@ -7,6 +7,18 @@
7
7
 
8
8
  var ObjectId = require('bson').ObjectID;
9
9
 
10
+ /*!
11
+ * Getter for convenience with populate, see gh-6115
12
+ */
13
+
14
+ Object.defineProperty(ObjectId.prototype, '_id', {
15
+ enumerable: false,
16
+ configurable: true,
17
+ get: function() {
18
+ return this;
19
+ }
20
+ });
21
+
10
22
  /*!
11
23
  * ignore
12
24
  */
@@ -1,10 +1,13 @@
1
+ 'use strict';
2
+
1
3
  /*!
2
4
  * Module dependencies.
3
5
  */
4
6
 
5
- var MongooseCollection = require('../../collection');
6
- var Collection = require('mongodb').Collection;
7
- var utils = require('../../utils');
7
+ const MongooseCollection = require('../../collection');
8
+ const Collection = require('mongodb').Collection;
9
+ const get = require('lodash.get');
10
+ const utils = require('../../utils');
8
11
 
9
12
  /**
10
13
  * A [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) collection implementation.
@@ -217,44 +220,52 @@ function format(obj, sub) {
217
220
  if (obj && typeof obj.toBSON === 'function') {
218
221
  obj = obj.toBSON();
219
222
  }
223
+ if (obj == null) {
224
+ return obj;
225
+ }
226
+
220
227
  var x = utils.clone(obj, {transform: false});
221
228
  var representation;
222
229
 
223
- if (x != null) {
224
- if (x.constructor.name === 'Binary') {
225
- x = 'BinData(' + x.sub_type + ', "' + x.toString('base64') + '")';
226
- } else if (x.constructor.name === 'ObjectID') {
227
- representation = 'ObjectId("' + x.toHexString() + '")';
228
- x = {inspect: function() { return representation; }};
229
- } else if (x.constructor.name === 'Date') {
230
- representation = 'new Date("' + x.toUTCString() + '")';
231
- x = {inspect: function() { return representation; }};
232
- } else if (x.constructor.name === 'Object') {
233
- var keys = Object.keys(x);
234
- var numKeys = keys.length;
235
- var key;
236
- for (var i = 0; i < numKeys; ++i) {
237
- key = keys[i];
238
- if (x[key]) {
239
- if (typeof x[key].toBSON === 'function') {
240
- x[key] = x[key].toBSON();
241
- }
242
- if (x[key].constructor.name === 'Binary') {
243
- x[key] = 'BinData(' + x[key].sub_type + ', "' +
244
- x[key].buffer.toString('base64') + '")';
245
- } else if (x[key].constructor.name === 'Object') {
246
- x[key] = format(x[key], true);
247
- } else if (x[key].constructor.name === 'ObjectID') {
248
- formatObjectId(x, key);
249
- } else if (x[key].constructor.name === 'Date') {
250
- formatDate(x, key);
251
- } else if (Array.isArray(x[key])) {
252
- x[key] = x[key].map(map);
253
- }
230
+ if (x.constructor.name === 'Binary') {
231
+ x = 'BinData(' + x.sub_type + ', "' + x.toString('base64') + '")';
232
+ } else if (x.constructor.name === 'ObjectID') {
233
+ representation = 'ObjectId("' + x.toHexString() + '")';
234
+ x = {inspect: function() { return representation; }};
235
+ } else if (x.constructor.name === 'Date') {
236
+ representation = 'new Date("' + x.toUTCString() + '")';
237
+ x = {inspect: function() { return representation; }};
238
+ } else if (x.constructor.name === 'Object') {
239
+ var keys = Object.keys(x);
240
+ var numKeys = keys.length;
241
+ var key;
242
+ for (var i = 0; i < numKeys; ++i) {
243
+ key = keys[i];
244
+ if (x[key]) {
245
+ if (typeof x[key].toBSON === 'function') {
246
+ x[key] = x[key].toBSON();
247
+ }
248
+ if (x[key].constructor.name === 'Binary') {
249
+ x[key] = 'BinData(' + x[key].sub_type + ', "' +
250
+ x[key].buffer.toString('base64') + '")';
251
+ } else if (x[key].constructor.name === 'Object') {
252
+ x[key] = format(x[key], true);
253
+ } else if (x[key].constructor.name === 'ObjectID') {
254
+ formatObjectId(x, key);
255
+ } else if (x[key].constructor.name === 'Date') {
256
+ formatDate(x, key);
257
+ } else if (x[key].constructor.name === 'ClientSession') {
258
+ representation = 'ClientSession("' +
259
+ get(x[key], 'id.id.buffer', '').toString('hex') + '")';
260
+ x[key] = {inspect: function() { return representation; }};
261
+ } else if (Array.isArray(x[key])) {
262
+ x[key] = x[key].map(map);
254
263
  }
255
264
  }
256
265
  }
257
- if (sub) return x;
266
+ }
267
+ if (sub) {
268
+ return x;
258
269
  }
259
270
 
260
271
  return require('util')
@@ -13,10 +13,12 @@ var MongooseError = require('./');
13
13
  * @api private
14
14
  */
15
15
 
16
- function VersionError(doc) {
16
+ function VersionError(doc, currentVersion, modifiedPaths) {
17
17
  MongooseError.call(this, 'No matching document found for id "' + doc._id +
18
- '"');
18
+ '" version ' + currentVersion);
19
19
  this.name = 'VersionError';
20
+ this.version = currentVersion;
21
+ this.modifiedPaths = modifiedPaths;
20
22
  }
21
23
 
22
24
  /*!
package/lib/index.js CHANGED
@@ -80,6 +80,7 @@ Mongoose.prototype.STATES = STATES;
80
80
  * - 'debug': prints the operations mongoose sends to MongoDB to the console
81
81
  * - 'bufferCommands': enable/disable mongoose's buffering mechanism for all connections and models
82
82
  * - 'useFindAndModify': true by default. Set to `false` to make `findOneAndUpdate()` and `findOneAndRemove()` use native `findOneAndUpdate()` rather than `findAndModify()`.
83
+ * - 'cloneSchemas': false by default. Set to `true` to `clone()` all schemas before compiling into a model.
83
84
  *
84
85
  * @param {String} key
85
86
  * @param {String|Function|Boolean} value
@@ -237,8 +238,8 @@ Mongoose.prototype.disconnect = function(callback) {
237
238
  /**
238
239
  * Getter/setter around function for pluralizing collection names.
239
240
  *
240
- * @param {Function|null} [fn] overwrites the function used to pluralize connection names
241
- * @return {Function|null} the current function used to pluralize connection names, `undefined` by default.
241
+ * @param {Function|null} [fn] overwrites the function used to pluralize collection names
242
+ * @return {Function|null} the current function used to pluralize collection names, defaults to the legacy function from `mongoose-legacy-pluralize`.
242
243
  * @api public
243
244
  */
244
245
 
@@ -291,7 +292,7 @@ Mongoose.prototype.pluralize = function(fn) {
291
292
  */
292
293
 
293
294
  Mongoose.prototype.model = function(name, schema, collection, skipInit) {
294
- var model;
295
+ let model;
295
296
  if (typeof name === 'function') {
296
297
  model = name;
297
298
  name = model.name;
@@ -319,7 +320,7 @@ Mongoose.prototype.model = function(name, schema, collection, skipInit) {
319
320
  }
320
321
 
321
322
  // handle internal options from connection.model()
322
- var options;
323
+ let options;
323
324
  if (skipInit && utils.isObject(skipInit)) {
324
325
  options = skipInit;
325
326
  skipInit = true;
@@ -337,16 +338,20 @@ Mongoose.prototype.model = function(name, schema, collection, skipInit) {
337
338
  }
338
339
  }
339
340
 
341
+ const originalSchema = schema;
340
342
  if (schema) {
343
+ if (this.get('cloneSchemas')) {
344
+ schema = schema.clone();
345
+ }
341
346
  this._applyPlugins(schema);
342
347
  }
343
348
 
344
- var sub;
349
+ let sub;
345
350
 
346
351
  // connection.model() may be passing a different schema for
347
352
  // an existing model name. in this case don't read from cache.
348
353
  if (this.models[name] && options.cache !== false) {
349
- if (schema && schema.instanceOfSchema && schema !== this.models[name].schema) {
354
+ if (originalSchema && originalSchema.instanceOfSchema && originalSchema !== this.models[name].schema) {
350
355
  throw new mongoose.Error.OverwriteModelError(name);
351
356
  }
352
357
 
@@ -380,7 +385,7 @@ Mongoose.prototype.model = function(name, schema, collection, skipInit) {
380
385
  utils.toCollectionName(name, this.pluralize());
381
386
  }
382
387
 
383
- var connection = options.connection || this.connection;
388
+ const connection = options.connection || this.connection;
384
389
  model = this.Model.compile(model || name, schema, collection, connection, this);
385
390
 
386
391
  if (!skipInit) {
package/lib/internal.js CHANGED
@@ -25,6 +25,7 @@ function InternalCache() {
25
25
  this.scope = undefined;
26
26
  this.activePaths = new ActiveRoster;
27
27
  this.pathsToScopes = {};
28
+ this.session = null;
28
29
 
29
30
  // embedded docs
30
31
  this.ownerDocument = undefined;