mongoose 6.2.0 → 6.2.1

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.
Files changed (41) hide show
  1. package/.eslintrc.json +150 -0
  2. package/CHANGELOG.md +21 -0
  3. package/dist/browser.umd.js +113 -112
  4. package/lib/aggregate.js +1 -1
  5. package/lib/document.js +83 -64
  6. package/lib/helpers/clone.js +40 -27
  7. package/lib/helpers/common.js +2 -2
  8. package/lib/helpers/getFunctionName.js +6 -4
  9. package/lib/helpers/isMongooseObject.js +9 -8
  10. package/lib/helpers/isObject.js +4 -4
  11. package/lib/helpers/path/parentPaths.js +10 -5
  12. package/lib/helpers/populate/assignRawDocsToIdStructure.js +4 -2
  13. package/lib/helpers/populate/assignVals.js +8 -4
  14. package/lib/helpers/populate/getModelsMapForPopulate.js +4 -4
  15. package/lib/helpers/populate/markArraySubdocsPopulated.js +3 -1
  16. package/lib/helpers/populate/modelNamesFromRefPath.js +4 -3
  17. package/lib/helpers/query/castUpdate.js +6 -2
  18. package/lib/helpers/schema/getPath.js +4 -2
  19. package/lib/helpers/timestamps/setupTimestamps.js +3 -8
  20. package/lib/index.js +2 -0
  21. package/lib/internal.js +1 -1
  22. package/lib/model.js +22 -8
  23. package/lib/plugins/trackTransaction.js +4 -3
  24. package/lib/query.js +3 -2
  25. package/lib/queryhelpers.js +1 -1
  26. package/lib/schema/array.js +17 -15
  27. package/lib/schema/documentarray.js +5 -8
  28. package/lib/schema/objectid.js +1 -1
  29. package/lib/schematype.js +29 -26
  30. package/lib/types/ArraySubdocument.js +2 -1
  31. package/lib/types/DocumentArray/index.js +9 -26
  32. package/lib/types/DocumentArray/isMongooseDocumentArray.js +5 -0
  33. package/lib/types/DocumentArray/methods/index.js +15 -3
  34. package/lib/types/array/index.js +21 -20
  35. package/lib/types/array/isMongooseArray.js +5 -0
  36. package/lib/types/array/methods/index.js +12 -12
  37. package/lib/utils.js +7 -0
  38. package/package.json +18 -147
  39. package/tools/repl.js +1 -1
  40. package/tsconfig.json +10 -0
  41. package/{index.d.ts → types/index.d.ts} +84 -75
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ const utils = require('../../utils');
4
+
3
5
  /*!
4
6
  * If populating a path within a document array, make sure each
5
7
  * subdoc within the array knows its subpaths are populated.
@@ -29,7 +31,7 @@ module.exports = function markArraySubdocsPopulated(doc, populated) {
29
31
  continue;
30
32
  }
31
33
 
32
- if (val.isMongooseDocumentArray) {
34
+ if (utils.isMongooseDocumentArray(val)) {
33
35
  for (let j = 0; j < val.length; ++j) {
34
36
  val[j].populated(rest, item._docs[id] == null ? void 0 : item._docs[id][j], item);
35
37
  }
@@ -7,6 +7,8 @@ const mpath = require('mpath');
7
7
  const util = require('util');
8
8
  const utils = require('../../utils');
9
9
 
10
+ const hasNumericPropRE = /(\.\d+$|\.\d+\.)/g;
11
+
10
12
  module.exports = function modelNamesFromRefPath(refPath, doc, populatedPath, modelSchema, queryProjection) {
11
13
  if (refPath == null) {
12
14
  return [];
@@ -20,10 +22,9 @@ module.exports = function modelNamesFromRefPath(refPath, doc, populatedPath, mod
20
22
  // If populated path has numerics, the end `refPath` should too. For example,
21
23
  // if populating `a.0.b` instead of `a.b` and `b` has `refPath = a.c`, we
22
24
  // should return `a.0.c` for the refPath.
23
- const hasNumericProp = /(\.\d+$|\.\d+\.)/g;
24
25
 
25
- if (hasNumericProp.test(populatedPath)) {
26
- const chunks = populatedPath.split(hasNumericProp);
26
+ if (hasNumericPropRE.test(populatedPath)) {
27
+ const chunks = populatedPath.split(hasNumericPropRE);
27
28
 
28
29
  if (chunks[chunks.length - 1] === '') {
29
30
  throw new Error('Can\'t populate individual element in an array');
@@ -41,9 +41,10 @@ module.exports = function castUpdate(schema, obj, options, context, filter) {
41
41
  }
42
42
  return obj;
43
43
  }
44
+
44
45
  if (schema.options.strict === 'throw' && obj.hasOwnProperty(schema.options.discriminatorKey)) {
45
46
  throw new StrictModeError(schema.options.discriminatorKey);
46
- } else if (context._mongooseOptions != null && !context._mongooseOptions.overwriteDiscriminatorKey) {
47
+ } else if (!options.overwriteDiscriminatorKey) {
47
48
  delete obj[schema.options.discriminatorKey];
48
49
  }
49
50
  if (options.upsert) {
@@ -353,7 +354,10 @@ function walkUpdatePath(schema, obj, op, options, context, filter, pref) {
353
354
  }
354
355
 
355
356
  if (Array.isArray(obj[key]) && (op === '$addToSet' || op === '$push') && key !== '$each') {
356
- if (schematype && schematype.caster && !schematype.caster.$isMongooseArray) {
357
+ if (schematype &&
358
+ schematype.caster &&
359
+ !schematype.caster.$isMongooseArray &&
360
+ !schematype.caster[schemaMixedSymbol]) {
357
361
  obj[key] = { $each: obj[key] };
358
362
  }
359
363
  }
@@ -5,6 +5,8 @@
5
5
  * needing to put `.0.`, so `getPath(schema, 'docArr.elProp')` works.
6
6
  */
7
7
 
8
+ const numberRE = /^\d+$/;
9
+
8
10
  module.exports = function getPath(schema, path) {
9
11
  let schematype = schema.path(path);
10
12
  if (schematype != null) {
@@ -16,7 +18,7 @@ module.exports = function getPath(schema, path) {
16
18
  let isArray = false;
17
19
 
18
20
  for (const piece of pieces) {
19
- if (/^\d+$/.test(piece) && isArray) {
21
+ if (isArray && numberRE.test(piece)) {
20
22
  continue;
21
23
  }
22
24
  cur = cur.length === 0 ? piece : cur + '.' + piece;
@@ -25,7 +27,7 @@ module.exports = function getPath(schema, path) {
25
27
  if (schematype != null && schematype.schema) {
26
28
  schema = schematype.schema;
27
29
  cur = '';
28
- if (schematype.$isMongooseDocumentArray) {
30
+ if (!isArray && schematype.$isMongooseDocumentArray) {
29
31
  isArray = true;
30
32
  }
31
33
  }
@@ -47,20 +47,15 @@ module.exports = function setupTimestamps(schema, timestamps) {
47
47
  const defaultTimestamp = currentTime != null ?
48
48
  currentTime() :
49
49
  this.ownerDocument().constructor.base.now();
50
- const auto_id = this._id && this._id.auto;
51
50
 
52
51
  if (!skipCreatedAt && this.isNew && createdAt && !this.$__getValue(createdAt) && this.$__isSelected(createdAt)) {
53
- this.$set(createdAt, auto_id ? this._id.getTimestamp() : defaultTimestamp);
52
+ this.$set(createdAt, defaultTimestamp);
54
53
  }
55
54
 
56
55
  if (!skipUpdatedAt && updatedAt && (this.isNew || this.$isModified())) {
57
56
  let ts = defaultTimestamp;
58
- if (this.isNew) {
59
- if (createdAt != null) {
60
- ts = this.$__getValue(createdAt);
61
- } else if (auto_id) {
62
- ts = this._id.getTimestamp();
63
- }
57
+ if (this.isNew && createdAt != null) {
58
+ ts = this.$__getValue(createdAt);
64
59
  }
65
60
  this.$set(updatedAt, ts);
66
61
  }
package/lib/index.js CHANGED
@@ -951,6 +951,8 @@ Mongoose.prototype.ObjectId = SchemaTypes.ObjectId;
951
951
  * mongoose.isValidObjectId({ test: 42 }); // false
952
952
  *
953
953
  * @method isValidObjectId
954
+ * @param {Any} value
955
+ * @returns {boolean} true if it is a valid ObjectId
954
956
  * @api public
955
957
  */
956
958
 
package/lib/internal.js CHANGED
@@ -10,7 +10,7 @@ const ActiveRoster = StateMachine.ctor('require', 'modify', 'init', 'default', '
10
10
  module.exports = exports = InternalCache;
11
11
 
12
12
  function InternalCache() {
13
- this.activePaths = new ActiveRoster;
13
+ this.activePaths = new ActiveRoster();
14
14
  this.strictMode = undefined;
15
15
  }
16
16
 
package/lib/model.js CHANGED
@@ -380,7 +380,12 @@ Model.prototype.$__save = function(options, callback) {
380
380
  });
381
381
  }
382
382
  let numAffected = 0;
383
- if (get(options, 'safe.w') !== 0 && get(options, 'w') !== 0) {
383
+ const writeConcern = options != null ?
384
+ options.writeConcern != null ?
385
+ options.writeConcern.w :
386
+ options.w :
387
+ 0;
388
+ if (writeConcern !== 0) {
384
389
  // Skip checking if write succeeded if writeConcern is set to
385
390
  // unacknowledged writes, because otherwise `numAffected` will always be 0
386
391
  if (result != null) {
@@ -392,8 +397,10 @@ Model.prototype.$__save = function(options, callback) {
392
397
  numAffected = result;
393
398
  }
394
399
  }
400
+
401
+ const versionBump = this.$__.version || this.$__schema.options.optimisticConcurrency;
395
402
  // was this an update that required a version bump?
396
- if (this.$__.version && !this.$__.inserting) {
403
+ if (versionBump && !this.$__.inserting) {
397
404
  const doIncrement = VERSION_INC === (VERSION_INC & this.$__.version);
398
405
  this.$__.version = undefined;
399
406
  const key = this.$__schema.options.versionKey;
@@ -741,7 +748,7 @@ Model.prototype.$__delta = function() {
741
748
  operand(this, where, delta, data, 1, '$unset');
742
749
  } else if (value === null) {
743
750
  operand(this, where, delta, data, null);
744
- } else if (value.isMongooseArray && value.$path() && value[arrayAtomicsSymbol]) {
751
+ } else if (utils.isMongooseArray(value) && value.$path() && value[arrayAtomicsSymbol]) {
745
752
  // arrays and other custom types (support plugins etc)
746
753
  handleAtomics(this, where, delta, data, value);
747
754
  } else if (value[MongooseBuffer.pathSymbol] && Buffer.isBuffer(value)) {
@@ -793,7 +800,7 @@ function checkDivergentArray(doc, path, array) {
793
800
  }
794
801
  }
795
802
 
796
- if (!(pop && array && array.isMongooseArray)) return;
803
+ if (!(pop && utils.isMongooseArray(array))) return;
797
804
 
798
805
  // If the array was populated using options that prevented all
799
806
  // documents from being returned (match, skip, limit) or they
@@ -3374,7 +3381,7 @@ Model.$__insertMany = function(arr, options, callback) {
3374
3381
  return doc != null;
3375
3382
  });
3376
3383
  // Quickly escape while there aren't any valid docAttributes
3377
- if (docAttributes.length < 1) {
3384
+ if (docAttributes.length === 0) {
3378
3385
  if (rawResult) {
3379
3386
  const res = {
3380
3387
  mongoose: {
@@ -4456,9 +4463,16 @@ const excludeIdRegGlobal = /\s?-_id\s?/g;
4456
4463
 
4457
4464
  function populate(model, docs, options, callback) {
4458
4465
  const populateOptions = { ...options };
4459
- if (model.base.options.strictPopulate != null && options.strictPopulate == null) {
4460
- populateOptions.strictPopulate = model.base.options.strictPopulate;
4466
+ if (options.strictPopulate == null) {
4467
+ if (options._localModel != null && options._localModel.schema._userProvidedOptions.strictPopulate != null) {
4468
+ populateOptions.strictPopulate = options._localModel.schema._userProvidedOptions.strictPopulate;
4469
+ } else if (options._localModel != null && model.base.options.strictPopulate != null) {
4470
+ populateOptions.strictPopulate = model.base.options.strictPopulate;
4471
+ } else if (model.base.options.strictPopulate != null) {
4472
+ populateOptions.strictPopulate = model.base.options.strictPopulate;
4473
+ }
4461
4474
  }
4475
+
4462
4476
  // normalize single / multiple docs passed
4463
4477
  if (!Array.isArray(docs)) {
4464
4478
  docs = [docs];
@@ -4529,7 +4543,7 @@ function populate(model, docs, options, callback) {
4529
4543
  }
4530
4544
  if (!hasOne) {
4531
4545
  // If models but no docs, skip further deep populate.
4532
- if (modelsMap.length > 0) {
4546
+ if (modelsMap.length !== 0) {
4533
4547
  return callback();
4534
4548
  }
4535
4549
  // If no models to populate but we have a nested populate,
@@ -2,6 +2,7 @@
2
2
 
3
3
  const arrayAtomicsSymbol = require('../helpers/symbols').arrayAtomicsSymbol;
4
4
  const sessionNewDocuments = require('../helpers/symbols').sessionNewDocuments;
5
+ const utils = require('../utils');
5
6
 
6
7
  module.exports = function trackTransaction(schema) {
7
8
  schema.pre('save', function() {
@@ -47,10 +48,10 @@ function _getAtomics(doc, previous) {
47
48
  const val = doc.$__getValue(path);
48
49
  if (val != null &&
49
50
  val instanceof Array &&
50
- val.isMongooseDocumentArray &&
51
+ utils.isMongooseDocumentArray(val) &&
51
52
  val.length &&
52
53
  val[arrayAtomicsSymbol] != null &&
53
- Object.keys(val[arrayAtomicsSymbol]).length > 0) {
54
+ Object.keys(val[arrayAtomicsSymbol]).length !== 0) {
54
55
  const existing = previous.get(path) || {};
55
56
  pathToAtomics.set(path, mergeAtomics(existing, val[arrayAtomicsSymbol]));
56
57
  }
@@ -61,7 +62,7 @@ function _getAtomics(doc, previous) {
61
62
  const path = dirt.path;
62
63
 
63
64
  const val = dirt.value;
64
- if (val != null && val[arrayAtomicsSymbol] != null && Object.keys(val[arrayAtomicsSymbol]).length > 0) {
65
+ if (val != null && val[arrayAtomicsSymbol] != null && Object.keys(val[arrayAtomicsSymbol]).length !== 0) {
65
66
  const existing = previous.get(path) || {};
66
67
  pathToAtomics.set(path, mergeAtomics(existing, val[arrayAtomicsSymbol]));
67
68
  }
package/lib/query.js CHANGED
@@ -120,7 +120,7 @@ function Query(conditions, options, model, collection) {
120
120
  * inherit mquery
121
121
  */
122
122
 
123
- Query.prototype = new mquery;
123
+ Query.prototype = new mquery();
124
124
  Query.prototype.constructor = Query;
125
125
  Query.base = mquery.prototype;
126
126
 
@@ -4848,7 +4848,8 @@ Query.prototype._castUpdate = function _castUpdate(obj, overwrite) {
4848
4848
  overwrite: overwrite,
4849
4849
  strict: this._mongooseOptions.strict,
4850
4850
  upsert: upsert,
4851
- arrayFilters: this.options.arrayFilters
4851
+ arrayFilters: this.options.arrayFilters,
4852
+ overwriteDiscriminatorKey: this._mongooseOptions.overwriteDiscriminatorKey
4852
4853
  }, this, this._conditions);
4853
4854
  };
4854
4855
 
@@ -212,7 +212,7 @@ exports.applyPaths = function applyPaths(fields, schema) {
212
212
 
213
213
  let addedPath = analyzePath(path, type);
214
214
  // arrays
215
- if (addedPath == null && type.$isMongooseArray && !type.$isMongooseDocumentArray) {
215
+ if (addedPath == null && !Array.isArray(type) && type.$isMongooseArray && !type.$isMongooseDocumentArray) {
216
216
  addedPath = analyzePath(path, type.caster);
217
217
  }
218
218
  if (addedPath != null) {
@@ -112,14 +112,12 @@ function SchemaArray(key, cast, options, schemaOptions) {
112
112
 
113
113
  if (!('defaultValue' in this) || this.defaultValue !== void 0) {
114
114
  const defaultFn = function() {
115
- let arr = [];
116
- if (fn) {
117
- arr = defaultArr.call(this);
118
- } else if (defaultArr != null) {
119
- arr = arr.concat(defaultArr);
120
- }
121
115
  // Leave it up to `cast()` to convert the array
122
- return arr;
116
+ return fn
117
+ ? defaultArr.call(this)
118
+ : defaultArr != null
119
+ ? [].concat(defaultArr)
120
+ : [];
123
121
  };
124
122
  defaultFn.$runBeforeSetters = !fn;
125
123
  this.default(defaultFn);
@@ -275,7 +273,7 @@ SchemaArray.prototype.applyGetters = function(value, scope) {
275
273
 
276
274
  const ret = SchemaType.prototype.applyGetters.call(this, value, scope);
277
275
  if (Array.isArray(ret)) {
278
- const rawValue = ret.isMongooseArrayProxy ? ret.__array : ret;
276
+ const rawValue = utils.isMongooseArray(ret) ? ret.__array : ret;
279
277
  const len = rawValue.length;
280
278
  for (let i = 0; i < len; ++i) {
281
279
  rawValue[i] = this.caster.applyGetters(rawValue[i], scope);
@@ -299,7 +297,7 @@ SchemaArray.prototype._applySetters = function(value, scope, init, priorVal) {
299
297
  }
300
298
 
301
299
  // No need to wrap empty arrays
302
- if (value != null && value.length > 0) {
300
+ if (value != null && value.length !== 0) {
303
301
  const valueDepth = arrayDepth(value);
304
302
  if (valueDepth.min === valueDepth.max && valueDepth.max < depth && valueDepth.containsNonArrayItem) {
305
303
  for (let i = valueDepth.max; i < depth; ++i) {
@@ -357,7 +355,7 @@ SchemaArray.prototype.cast = function(value, doc, init, prev, options) {
357
355
 
358
356
  options = options || emptyOpts;
359
357
 
360
- let rawValue = value.isMongooseArrayProxy ? value.__array : value;
358
+ let rawValue = utils.isMongooseArray(value) ? value.__array : value;
361
359
  value = MongooseArray(rawValue, options.path || this._arrayPath || this.path, doc, this);
362
360
  rawValue = value.__array;
363
361
 
@@ -557,12 +555,16 @@ function cast$all(val) {
557
555
  }
558
556
 
559
557
  val = val.map(function(v) {
560
- if (utils.isObject(v)) {
561
- const o = {};
562
- o[this.path] = v;
563
- return cast(this.casterConstructor.schema, o)[this.path];
558
+ if (!utils.isObject(v)) {
559
+ return v;
560
+ }
561
+ if (v.$elemMatch != null) {
562
+ return { $elemMatch: cast(this.casterConstructor.schema, v.$elemMatch) };
564
563
  }
565
- return v;
564
+
565
+ const o = {};
566
+ o[this.path] = v;
567
+ return cast(this.casterConstructor.schema, o)[this.path];
566
568
  }, this);
567
569
 
568
570
  return this.castForQuery(val);
@@ -228,7 +228,7 @@ DocumentArrayPath.prototype.doValidate = function(array, fn, scope, options) {
228
228
  if (options && options.updateValidator) {
229
229
  return fn();
230
230
  }
231
- if (!array.isMongooseDocumentArray) {
231
+ if (!utils.isMongooseDocumentArray(array)) {
232
232
  array = new MongooseDocumentArray(array, _this.path, scope);
233
233
  }
234
234
 
@@ -398,12 +398,9 @@ DocumentArrayPath.prototype.cast = function(value, doc, init, prev, options) {
398
398
  return this.cast([value], doc, init, prev, options);
399
399
  }
400
400
 
401
- if (!(value && value.isMongooseDocumentArray) &&
402
- !options.skipDocumentArrayCast) {
403
- value = new MongooseDocumentArray(value, this.path, doc);
404
- } else if (value && value.isMongooseDocumentArray) {
405
- // We need to create a new array, otherwise change tracking will
406
- // update the old doc (gh-4449)
401
+ // We need to create a new array, otherwise change tracking will
402
+ // update the old doc (gh-4449)
403
+ if (!options.skipDocumentArrayCast || utils.isMongooseDocumentArray(value)) {
407
404
  value = new MongooseDocumentArray(value, this.path, doc);
408
405
  }
409
406
 
@@ -415,7 +412,7 @@ DocumentArrayPath.prototype.cast = function(value, doc, init, prev, options) {
415
412
  value[arrayPathSymbol] = this.path + '.' + options.arrayPathIndex;
416
413
  }
417
414
 
418
- const rawArray = value.isMongooseDocumentArrayProxy ? value.__array : value;
415
+ const rawArray = utils.isMongooseDocumentArray(value) ? value.__array : value;
419
416
 
420
417
  const len = rawArray.length;
421
418
  const initDocumentOptions = { skipId: true, willInit: true };
@@ -281,7 +281,7 @@ function resetId(v) {
281
281
 
282
282
  if (this instanceof Document) {
283
283
  if (v === void 0) {
284
- const _v = new oid;
284
+ const _v = new oid();
285
285
  this.$__._id = _v;
286
286
  return _v;
287
287
  }
package/lib/schematype.js CHANGED
@@ -1125,7 +1125,7 @@ SchemaType.prototype.getDefault = function(scope, init) {
1125
1125
  }
1126
1126
 
1127
1127
  const casted = this.applySetters(ret, scope, init);
1128
- if (casted && casted.$isSingleNested) {
1128
+ if (casted && !Array.isArray(casted) && casted.$isSingleNested) {
1129
1129
  casted.$__parent = scope;
1130
1130
  }
1131
1131
  return casted;
@@ -1328,6 +1328,16 @@ SchemaType.prototype.doValidate = function(value, fn, scope, options) {
1328
1328
  }
1329
1329
  };
1330
1330
 
1331
+
1332
+ function _validate(ok, validatorProperties) {
1333
+ if (ok !== undefined && !ok) {
1334
+ const ErrorConstructor = validatorProperties.ErrorConstructor || ValidatorError;
1335
+ const err = new ErrorConstructor(validatorProperties);
1336
+ err[validatorErrorSymbol] = true;
1337
+ return err;
1338
+ }
1339
+ }
1340
+
1331
1341
  /**
1332
1342
  * Performs a validation of `value` using the validators declared for this SchemaType.
1333
1343
  *
@@ -1351,7 +1361,7 @@ SchemaType.prototype.doValidateSync = function(value, scope, options) {
1351
1361
 
1352
1362
  let validators = this.validators;
1353
1363
  if (value === void 0) {
1354
- if (this.validators.length > 0 && this.validators[0].type === 'required') {
1364
+ if (this.validators.length !== 0 && this.validators[0].type === 'required') {
1355
1365
  validators = [this.validators[0]];
1356
1366
  } else {
1357
1367
  return null;
@@ -1359,34 +1369,35 @@ SchemaType.prototype.doValidateSync = function(value, scope, options) {
1359
1369
  }
1360
1370
 
1361
1371
  let err = null;
1362
- validators.forEach(function(v) {
1363
- if (err) {
1364
- return;
1365
- }
1372
+ let i = 0;
1373
+ const len = validators.length;
1374
+ for (i = 0; i < len; ++i) {
1375
+
1376
+ const v = validators[i];
1366
1377
 
1367
1378
  if (v == null || typeof v !== 'object') {
1368
- return;
1379
+ continue;
1369
1380
  }
1370
1381
 
1371
1382
  const validator = v.validator;
1372
1383
  const validatorProperties = utils.clone(v);
1373
1384
  validatorProperties.path = options && options.path ? options.path : path;
1374
1385
  validatorProperties.value = value;
1375
- let ok;
1386
+ let ok = false;
1376
1387
 
1377
1388
  // Skip any explicit async validators. Validators that return a promise
1378
1389
  // will still run, but won't trigger any errors.
1379
1390
  if (isAsyncFunction(validator)) {
1380
- return;
1391
+ continue;
1381
1392
  }
1382
1393
 
1383
1394
  if (validator instanceof RegExp) {
1384
- validate(validator.test(value), validatorProperties);
1385
- return;
1395
+ err = _validate(validator.test(value), validatorProperties);
1396
+ continue;
1386
1397
  }
1387
1398
 
1388
1399
  if (typeof validator !== 'function') {
1389
- return;
1400
+ continue;
1390
1401
  }
1391
1402
 
1392
1403
  try {
@@ -1403,23 +1414,15 @@ SchemaType.prototype.doValidateSync = function(value, scope, options) {
1403
1414
  // Skip any validators that return a promise, we can't handle those
1404
1415
  // synchronously
1405
1416
  if (ok != null && typeof ok.then === 'function') {
1406
- return;
1417
+ continue;
1407
1418
  }
1408
- validate(ok, validatorProperties);
1409
- });
1410
-
1411
- return err;
1412
-
1413
- function validate(ok, validatorProperties) {
1419
+ err = _validate(ok, validatorProperties);
1414
1420
  if (err) {
1415
- return;
1416
- }
1417
- if (ok !== undefined && !ok) {
1418
- const ErrorConstructor = validatorProperties.ErrorConstructor || ValidatorError;
1419
- err = new ErrorConstructor(validatorProperties);
1420
- err[validatorErrorSymbol] = true;
1421
+ break;
1421
1422
  }
1422
1423
  }
1424
+
1425
+ return err;
1423
1426
  };
1424
1427
 
1425
1428
  /**
@@ -1630,7 +1633,7 @@ SchemaType.prototype._castForQuery = function(val) {
1630
1633
  */
1631
1634
 
1632
1635
  SchemaType.checkRequired = function(fn) {
1633
- if (arguments.length > 0) {
1636
+ if (arguments.length !== 0) {
1634
1637
  this._checkRequired = fn;
1635
1638
  }
1636
1639
 
@@ -6,6 +6,7 @@
6
6
 
7
7
  const EventEmitter = require('events').EventEmitter;
8
8
  const Subdocument = require('./subdocument');
9
+ const utils = require('../utils');
9
10
 
10
11
  const documentArrayParent = require('../helpers/symbols').documentArrayParent;
11
12
 
@@ -20,7 +21,7 @@ const documentArrayParent = require('../helpers/symbols').documentArrayParent;
20
21
  */
21
22
 
22
23
  function ArraySubdocument(obj, parentArr, skipId, fields, index) {
23
- if (parentArr != null && parentArr.isMongooseDocumentArray) {
24
+ if (utils.isMongooseDocumentArray(parentArr)) {
24
25
  this.__parentArray = parentArr;
25
26
  this[documentArrayParent] = parentArr.$parent();
26
27
  } else {
@@ -15,7 +15,7 @@ const arrayPathSymbol = require('../../helpers/symbols').arrayPathSymbol;
15
15
  const arraySchemaSymbol = require('../../helpers/symbols').arraySchemaSymbol;
16
16
 
17
17
  const _basePush = Array.prototype.push;
18
-
18
+ const numberRE = /^\d+$/;
19
19
  /**
20
20
  * DocumentArray constructor
21
21
  *
@@ -29,7 +29,7 @@ const _basePush = Array.prototype.push;
29
29
  */
30
30
 
31
31
  function MongooseDocumentArray(values, path, doc) {
32
- const arr = [];
32
+ const __array = [];
33
33
 
34
34
  const internals = {
35
35
  [arrayAtomicsSymbol]: {},
@@ -45,10 +45,11 @@ function MongooseDocumentArray(values, path, doc) {
45
45
  internals[arrayAtomicsSymbol] = Object.assign({}, values[arrayAtomicsSymbol]);
46
46
  }
47
47
  values.forEach(v => {
48
- _basePush.call(arr, v);
48
+ _basePush.call(__array, v);
49
49
  });
50
50
  }
51
51
  internals[arrayPathSymbol] = path;
52
+ internals.__array = __array;
52
53
 
53
54
  // Because doc comes from the context of another function, doc === global
54
55
  // can happen if there was a null somewhere up the chain (see #3020 && #3034)
@@ -69,7 +70,7 @@ function MongooseDocumentArray(values, path, doc) {
69
70
  }
70
71
  }
71
72
 
72
- const proxy = new Proxy(arr, {
73
+ const proxy = new Proxy(__array, {
73
74
  get: function(target, prop) {
74
75
  if (prop === 'isMongooseArray' ||
75
76
  prop === 'isMongooseArrayProxy' ||
@@ -77,12 +78,6 @@ function MongooseDocumentArray(values, path, doc) {
77
78
  prop === 'isMongooseDocumentArrayProxy') {
78
79
  return true;
79
80
  }
80
- if (prop === '__array') {
81
- return arr;
82
- }
83
- if (prop === 'set') {
84
- return set;
85
- }
86
81
  if (internals.hasOwnProperty(prop)) {
87
82
  return internals[prop];
88
83
  }
@@ -93,15 +88,15 @@ function MongooseDocumentArray(values, path, doc) {
93
88
  return ArrayMethods[prop];
94
89
  }
95
90
 
96
- return arr[prop];
91
+ return __array[prop];
97
92
  },
98
93
  set: function(target, prop, value) {
99
- if (typeof prop === 'string' && /^\d+$/.test(prop)) {
100
- set.call(proxy, prop, value);
94
+ if (typeof prop === 'string' && numberRE.test(prop)) {
95
+ DocumentArrayMethods.set.call(proxy, prop, value, false);
101
96
  } else if (internals.hasOwnProperty(prop)) {
102
97
  internals[prop] = value;
103
98
  } else {
104
- arr[prop] = value;
99
+ __array[prop] = value;
105
100
  }
106
101
 
107
102
  return true;
@@ -111,18 +106,6 @@ function MongooseDocumentArray(values, path, doc) {
111
106
  return proxy;
112
107
  }
113
108
 
114
- function set(i, val, skipModified) {
115
- const arr = this.__array;
116
- if (skipModified) {
117
- arr[i] = val;
118
- return arr;
119
- }
120
- const value = DocumentArrayMethods._cast.call(this, val, i);
121
- arr[i] = value;
122
- DocumentArrayMethods._markModified.call(this, i);
123
- return arr;
124
- }
125
-
126
109
  /*!
127
110
  * Module exports.
128
111
  */
@@ -0,0 +1,5 @@
1
+ 'use strict';
2
+
3
+ exports.isMongooseDocumentArray = function(mongooseDocumentArray) {
4
+ return Array.isArray(mongooseDocumentArray) && mongooseDocumentArray.isMongooseDocumentArray;
5
+ };
@@ -36,7 +36,7 @@ const methods = {
36
36
  }
37
37
  let Constructor = this[arraySchemaSymbol].casterConstructor;
38
38
  const isInstance = Constructor.$isMongooseDocumentArray ?
39
- value && value.isMongooseDocumentArray :
39
+ utils.isMongooseDocumentArray(value) :
40
40
  value instanceof Constructor;
41
41
  if (isInstance ||
42
42
  // Hack re: #5001, see #5005
@@ -295,7 +295,7 @@ const methods = {
295
295
  break;
296
296
  }
297
297
 
298
- if (_arr[i].isMongooseArray) {
298
+ if (utils.isMongooseArray(_arr[i])) {
299
299
  notify(val, _arr[i]);
300
300
  } else if (_arr[i]) {
301
301
  _arr[i].emit(event, val);
@@ -304,6 +304,18 @@ const methods = {
304
304
  };
305
305
  },
306
306
 
307
+ set(i, val, skipModified) {
308
+ const arr = this.__array;
309
+ if (skipModified) {
310
+ arr[i] = val;
311
+ return this;
312
+ }
313
+ const value = methods._cast.call(this, val, i);
314
+ arr[i] = value;
315
+ methods._markModified.call(this, i);
316
+ return this;
317
+ },
318
+
307
319
  _markModified(elem, embeddedPath) {
308
320
  const parent = this[arrayParentSymbol];
309
321
  let dirtyPath;
@@ -326,7 +338,7 @@ const methods = {
326
338
  return this;
327
339
  }
328
340
 
329
- parent.markModified(dirtyPath, arguments.length > 0 ? elem : parent);
341
+ parent.markModified(dirtyPath, arguments.length !== 0 ? elem : parent);
330
342
  }
331
343
 
332
344
  return this;