mongoose 5.5.0 → 5.5.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/schematype.js CHANGED
@@ -51,6 +51,21 @@ function SchemaType(path, options, instance) {
51
51
  if (this[prop] && typeof this[prop] === 'function') {
52
52
  // { unique: true, index: true }
53
53
  if (prop === 'index' && this._index) {
54
+ if (options.index === false) {
55
+ const index = this._index;
56
+ if (typeof index === 'object' && index != null) {
57
+ if (index.unique) {
58
+ throw new Error('Path "' + this.path + '" may not have `index` ' +
59
+ 'set to false and `unique` set to true');
60
+ }
61
+ if (index.sparse) {
62
+ throw new Error('Path "' + this.path + '" may not have `index` ' +
63
+ 'set to false and `sparse` set to true');
64
+ }
65
+ }
66
+
67
+ this._index = false;
68
+ }
54
69
  continue;
55
70
  }
56
71
 
@@ -263,6 +278,14 @@ SchemaType.prototype.unique = function(bool) {
263
278
  */
264
279
 
265
280
  SchemaType.prototype.text = function(bool) {
281
+ if (this._index === false) {
282
+ if (!bool) {
283
+ return;
284
+ }
285
+ throw new Error('Path "' + this.path + '" may not have `index` set to ' +
286
+ 'false and `text` set to true');
287
+ }
288
+
266
289
  if (this._index === null || this._index === undefined ||
267
290
  typeof this._index === 'boolean') {
268
291
  this._index = {};
@@ -288,8 +311,15 @@ SchemaType.prototype.text = function(bool) {
288
311
  */
289
312
 
290
313
  SchemaType.prototype.sparse = function(bool) {
291
- if (this._index === null || this._index === undefined ||
292
- typeof this._index === 'boolean') {
314
+ if (this._index === false) {
315
+ if (!bool) {
316
+ return;
317
+ }
318
+ throw new Error('Path "' + this.path + '" may not have `index` set to ' +
319
+ 'false and `sparse` set to true');
320
+ }
321
+
322
+ if (this._index == null || typeof this._index === 'boolean') {
293
323
  this._index = {};
294
324
  } else if (typeof this._index === 'string') {
295
325
  this._index = {type: this._index};
@@ -13,6 +13,8 @@ const internalToObjectOptions = require('../options').internalToObjectOptions;
13
13
  const utils = require('../utils');
14
14
  const util = require('util');
15
15
 
16
+ const arrayParentSymbol = require('../helpers/symbols').arrayParentSymbol;
17
+ const arraySchemaSymbol = require('../helpers/symbols').arraySchemaSymbol;
16
18
  const isMongooseObject = utils.isMongooseObject;
17
19
 
18
20
  /**
@@ -43,7 +45,7 @@ function MongooseArray(values, path, doc) {
43
45
  arr.isMongooseArray = true;
44
46
  arr.validators = [];
45
47
  arr._atomics = {};
46
- arr._schema = void 0;
48
+ arr[arraySchemaSymbol] = void 0;
47
49
  if (util.inspect.custom) {
48
50
  arr[util.inspect.custom] = arr.inspect;
49
51
  }
@@ -53,8 +55,8 @@ function MongooseArray(values, path, doc) {
53
55
  // RB Jun 17, 2015 updated to check for presence of expected paths instead
54
56
  // to make more proof against unusual node environments
55
57
  if (doc && doc instanceof Document) {
56
- arr._parent = doc;
57
- arr._schema = doc.schema.path(path);
58
+ arr[arrayParentSymbol] = doc;
59
+ arr[arraySchemaSymbol] = doc.schema.path(path);
58
60
  }
59
61
 
60
62
  return arr;
@@ -77,15 +79,21 @@ MongooseArray.mixin = {
77
79
 
78
80
  _atomics: undefined,
79
81
 
80
- /**
81
- * Parent owner document
82
- *
83
- * @property _parent
84
- * @api private
85
- * @memberOf MongooseArray
82
+ /*!
83
+ * ignore
86
84
  */
87
85
 
88
- _parent: undefined,
86
+ $parent: function() {
87
+ return this[arrayParentSymbol];
88
+ },
89
+
90
+ /*!
91
+ * ignore
92
+ */
93
+
94
+ $schema: function() {
95
+ return this[arraySchemaSymbol];
96
+ },
89
97
 
90
98
  /**
91
99
  * Casts a member based on this arrays schema.
@@ -101,8 +109,8 @@ MongooseArray.mixin = {
101
109
  let populated = false;
102
110
  let Model;
103
111
 
104
- if (this._parent) {
105
- populated = this._parent.populated(this._path, true);
112
+ if (this[arrayParentSymbol]) {
113
+ populated = this[arrayParentSymbol].populated(this._path, true);
106
114
  }
107
115
 
108
116
  if (populated && value !== null && value !== undefined) {
@@ -123,10 +131,10 @@ MongooseArray.mixin = {
123
131
  if (!isDisc) {
124
132
  value = new Model(value);
125
133
  }
126
- return this._schema.caster.applySetters(value, this._parent, true);
134
+ return this[arraySchemaSymbol].caster.applySetters(value, this[arrayParentSymbol], true);
127
135
  }
128
136
 
129
- return this._schema.caster.applySetters(value, this._parent, false);
137
+ return this[arraySchemaSymbol].caster.applySetters(value, this[arrayParentSymbol], false);
130
138
  },
131
139
 
132
140
  /**
@@ -142,7 +150,7 @@ MongooseArray.mixin = {
142
150
  */
143
151
 
144
152
  _markModified: function(elem, embeddedPath) {
145
- const parent = this._parent;
153
+ const parent = this[arrayParentSymbol];
146
154
  let dirtyPath;
147
155
 
148
156
  if (parent) {
@@ -179,7 +187,7 @@ MongooseArray.mixin = {
179
187
  // $set takes precedence over all other ops.
180
188
  // mark entire array modified.
181
189
  this._atomics = {$set: val};
182
- cleanModifiedSubpaths(this._parent, this._path);
190
+ cleanModifiedSubpaths(this[arrayParentSymbol], this._path);
183
191
  this._markModified();
184
192
  return this;
185
193
  }
@@ -189,7 +197,7 @@ MongooseArray.mixin = {
189
197
  // reset pop/shift after save
190
198
  if (op === '$pop' && !('$pop' in atomics)) {
191
199
  const _this = this;
192
- this._parent.once('save', function() {
200
+ this[arrayParentSymbol].once('save', function() {
193
201
  _this._popped = _this._shifted = null;
194
202
  });
195
203
  }
@@ -322,7 +330,7 @@ MongooseArray.mixin = {
322
330
  push: function() {
323
331
  _checkManualPopulation(this, arguments);
324
332
  let values = [].map.call(arguments, this._mapCast, this);
325
- values = this._schema.applySetters(values, this._parent, undefined,
333
+ values = this[arraySchemaSymbol].applySetters(values, this[arrayParentSymbol], undefined,
326
334
  undefined, { skipDocumentArrayCast: true });
327
335
  const ret = [].push.apply(this, values);
328
336
 
@@ -527,7 +535,7 @@ MongooseArray.mixin = {
527
535
 
528
536
  pull: function() {
529
537
  const values = [].map.call(arguments, this._cast, this);
530
- const cur = this._parent.get(this._path);
538
+ const cur = this[arrayParentSymbol].get(this._path);
531
539
  let i = cur.length;
532
540
  let mem;
533
541
 
@@ -559,7 +567,7 @@ MongooseArray.mixin = {
559
567
  // `doc.children[1].name = 'test';` followed by
560
568
  // `doc.children.remove(doc.children[0]);`. In this case we fall back
561
569
  // to a `$set` on the whole array. See #3511
562
- if (cleanModifiedSubpaths(this._parent, this._path) > 0) {
570
+ if (cleanModifiedSubpaths(this[arrayParentSymbol], this._path) > 0) {
563
571
  this._registerAtomic('$set', this);
564
572
  }
565
573
 
@@ -613,7 +621,7 @@ MongooseArray.mixin = {
613
621
  _checkManualPopulation(this, arguments);
614
622
 
615
623
  let values = [].map.call(arguments, this._cast, this);
616
- values = this._schema.applySetters(values, this._parent);
624
+ values = this[arraySchemaSymbol].applySetters(values, this[arrayParentSymbol]);
617
625
  [].unshift.apply(this, values);
618
626
  this._registerAtomic('$set', this);
619
627
  this._markModified();
@@ -659,7 +667,7 @@ MongooseArray.mixin = {
659
667
  _checkManualPopulation(this, arguments);
660
668
 
661
669
  let values = [].map.call(arguments, this._mapCast, this);
662
- values = this._schema.applySetters(values, this._parent);
670
+ values = this[arraySchemaSymbol].applySetters(values, this[arrayParentSymbol]);
663
671
  const added = [];
664
672
  let type = '';
665
673
  if (values[0] instanceof EmbeddedDocument) {
@@ -787,6 +795,20 @@ MongooseArray.mixin = {
787
795
  }
788
796
  }
789
797
  return -1;
798
+ },
799
+
800
+ /**
801
+ * Return whether or not the `obj` is included in the array.
802
+ *
803
+ * @param {Object} obj the item to check
804
+ * @return {Boolean}
805
+ * @api public
806
+ * @method includes
807
+ * @memberOf MongooseArray
808
+ */
809
+
810
+ includes: function includes(obj) {
811
+ return this.indexOf(obj) !== -1;
790
812
  }
791
813
  };
792
814
 
@@ -831,11 +853,13 @@ function _isAllSubdocs(docs, ref) {
831
853
  */
832
854
 
833
855
  function _checkManualPopulation(arr, docs) {
834
- const ref = get(arr, '_schema.caster.options.ref', null);
856
+ const ref = arr == null ?
857
+ null :
858
+ get(arr[arraySchemaSymbol], 'caster.options.ref', null);
835
859
  if (arr.length === 0 &&
836
860
  docs.length > 0) {
837
861
  if (_isAllSubdocs(docs, ref)) {
838
- arr._parent.populated(arr._path, [], { model: docs[0].constructor });
862
+ arr[arrayParentSymbol].populated(arr._path, [], { model: docs[0].constructor });
839
863
  }
840
864
  }
841
865
  }
@@ -8,12 +8,13 @@ const Document = require('../document');
8
8
  const MongooseArray = require('./array');
9
9
  const ObjectId = require('./objectid');
10
10
  const castObjectId = require('../cast/objectid');
11
- const get = require('../helpers/get');
12
11
  const getDiscriminatorByValue = require('../queryhelpers').getDiscriminatorByValue;
13
12
  const internalToObjectOptions = require('../options').internalToObjectOptions;
14
13
  const util = require('util');
15
14
  const utils = require('../utils');
16
15
 
16
+ const arrayParentSymbol = require('../helpers/symbols').arrayParentSymbol;
17
+ const arraySchemaSymbol = require('../helpers/symbols').arraySchemaSymbol;
17
18
  const documentArrayParent = require('../helpers/symbols').documentArrayParent;
18
19
 
19
20
  /*!
@@ -49,14 +50,14 @@ function MongooseDocumentArray(values, path, doc) {
49
50
  isMongooseDocumentArray: true,
50
51
  validators: [],
51
52
  _atomics: {},
52
- _schema: void 0,
53
+ [arraySchemaSymbol]: void 0,
53
54
  _handlers: void 0
54
55
  };
55
56
 
56
57
  if (Array.isArray(values)) {
57
58
  if (values instanceof CoreMongooseArray &&
58
59
  values._path === path &&
59
- values._parent === doc) {
60
+ values[arrayParentSymbol] === doc) {
60
61
  props._atomics = Object.assign({}, values._atomics);
61
62
  }
62
63
  values.forEach(v => {
@@ -93,22 +94,24 @@ function MongooseDocumentArray(values, path, doc) {
93
94
  // RB Jun 17, 2015 updated to check for presence of expected paths instead
94
95
  // to make more proof against unusual node environments
95
96
  if (doc && doc instanceof Document) {
96
- arr._parent = doc;
97
- arr._schema = doc.schema.path(path);
97
+ arr[arrayParentSymbol] = doc;
98
+ arr[arraySchemaSymbol] = doc.schema.path(path);
98
99
 
99
100
  // `schema.path()` doesn't drill into nested arrays properly yet, see
100
101
  // gh-6398, gh-6602. This is a workaround because nested arrays are
101
102
  // always plain non-document arrays, so once you get to a document array
102
103
  // nesting is done. Matryoshka code.
103
- while (get(arr, '_schema.$isMongooseArray') &&
104
- !get(arr, '_schema.$isMongooseDocumentArray')) {
105
- arr._schema = arr._schema.casterConstructor;
104
+ while (arr != null &&
105
+ arr[arraySchemaSymbol] != null &&
106
+ arr[arraySchemaSymbol].$isMongooseArray &&
107
+ !arr[arraySchemaSymbol].$isMongooseDocumentArray) {
108
+ arr[arraySchemaSymbol] = arr[arraySchemaSymbol].casterConstructor;
106
109
  }
107
110
 
108
111
  // Tricky but this may be a document array embedded in a normal array,
109
112
  // in which case `path` would point to the embedded array. See #6405, #6398
110
- if (arr._schema && !arr._schema.$isMongooseDocumentArray) {
111
- arr._schema = arr._schema.casterConstructor;
113
+ if (arr[arraySchemaSymbol] && !arr[arraySchemaSymbol].$isMongooseDocumentArray) {
114
+ arr[arraySchemaSymbol] = arr[arraySchemaSymbol].casterConstructor;
112
115
  }
113
116
 
114
117
  arr._handlers = {
@@ -144,7 +147,7 @@ MongooseDocumentArray.mixin = {
144
147
  */
145
148
 
146
149
  _cast: function(value, index) {
147
- let Constructor = this._schema.casterConstructor;
150
+ let Constructor = this[arraySchemaSymbol].casterConstructor;
148
151
  const isInstance = Constructor.$isMongooseDocumentArray ?
149
152
  value && value.isMongooseDocumentArray :
150
153
  value instanceof Constructor;
@@ -153,7 +156,7 @@ MongooseDocumentArray.mixin = {
153
156
  (value && value.constructor && value.constructor.baseCasterConstructor === Constructor)) {
154
157
  if (!(value[documentArrayParent] && value.__parentArray)) {
155
158
  // value may have been created using array.create()
156
- value[documentArrayParent] = this._parent;
159
+ value[documentArrayParent] = this[arrayParentSymbol];
157
160
  value.__parentArray = this;
158
161
  }
159
162
  value.$setIndex(index);
@@ -293,7 +296,7 @@ MongooseDocumentArray.mixin = {
293
296
  */
294
297
 
295
298
  create: function(obj) {
296
- let Constructor = this._schema.casterConstructor;
299
+ let Constructor = this[arraySchemaSymbol].casterConstructor;
297
300
  if (obj &&
298
301
  Constructor.discriminators &&
299
302
  Constructor.schema &&
@@ -30,7 +30,7 @@ const validatorErrorSymbol = require('../helpers/symbols').validatorErrorSymbol;
30
30
  function EmbeddedDocument(obj, parentArr, skipId, fields, index) {
31
31
  if (parentArr) {
32
32
  this.__parentArray = parentArr;
33
- this[documentArrayParent] = parentArr._parent;
33
+ this[documentArrayParent] = parentArr.$parent();
34
34
  } else {
35
35
  this.__parentArray = undefined;
36
36
  this[documentArrayParent] = undefined;
package/lib/types/map.js CHANGED
@@ -83,6 +83,11 @@ class MongooseMap extends Map {
83
83
  }
84
84
  }
85
85
 
86
+ delete(key) {
87
+ this.set(key, undefined);
88
+ super.delete(key);
89
+ }
90
+
86
91
  toBSON() {
87
92
  return new Map(this);
88
93
  }
@@ -18,13 +18,30 @@ module.exports = Subdocument;
18
18
 
19
19
  function Subdocument(value, fields, parent, skipId, options) {
20
20
  this.$isSingleNested = true;
21
+
22
+ const hasPriorDoc = options != null && options.priorDoc;
23
+ let initedPaths = null;
24
+ if (hasPriorDoc) {
25
+ this._doc = Object.assign({}, options.priorDoc._doc);
26
+ delete this._doc[this.schema.options.discriminatorKey];
27
+ initedPaths = Object.keys(options.priorDoc._doc || {}).
28
+ filter(key => key !== this.schema.options.discriminatorKey);
29
+ }
21
30
  if (parent != null) {
22
31
  // If setting a nested path, should copy isNew from parent re: gh-7048
23
32
  options = Object.assign({}, options, { isNew: parent.isNew });
24
33
  }
25
34
  Document.call(this, value, fields, skipId, options);
26
35
 
27
- delete this.$__.$options.priorDoc;
36
+ if (hasPriorDoc) {
37
+ for (const key of initedPaths) {
38
+ if (!this.$__.activePaths.states.modify[key] &&
39
+ !this.$__.activePaths.states.default[key] &&
40
+ !this.$__.$setCalled.has(key)) {
41
+ delete this._doc[key];
42
+ }
43
+ }
44
+ }
28
45
  }
29
46
 
30
47
  Subdocument.prototype = Object.create(Document.prototype);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "5.5.0",
4
+ "version": "5.5.4",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
@@ -25,7 +25,7 @@
25
25
  "mongodb": "3.2.2",
26
26
  "mongodb-core": "3.2.2",
27
27
  "mongoose-legacy-pluralize": "1.0.2",
28
- "mpath": "0.5.1",
28
+ "mpath": "0.5.2",
29
29
  "mquery": "3.2.0",
30
30
  "ms": "2.1.1",
31
31
  "regexp-clone": "0.0.1",