mongoose 6.1.9 → 6.2.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.
Files changed (76) hide show
  1. package/.eslintrc.json +154 -0
  2. package/CHANGELOG.md +59 -0
  3. package/dist/browser.umd.js +233 -222
  4. package/index.js +5 -1
  5. package/lib/aggregate.js +23 -28
  6. package/lib/browserDocument.js +1 -1
  7. package/lib/cast/number.js +2 -3
  8. package/lib/cast.js +9 -7
  9. package/lib/connection.js +76 -24
  10. package/lib/cursor/AggregationCursor.js +12 -7
  11. package/lib/cursor/QueryCursor.js +11 -6
  12. package/lib/document.js +107 -107
  13. package/lib/drivers/node-mongodb-native/collection.js +12 -4
  14. package/lib/drivers/node-mongodb-native/connection.js +11 -0
  15. package/lib/error/cast.js +3 -2
  16. package/lib/error/index.js +11 -0
  17. package/lib/error/syncIndexes.js +30 -0
  18. package/lib/helpers/clone.js +51 -29
  19. package/lib/helpers/common.js +2 -2
  20. package/lib/helpers/cursor/eachAsync.js +18 -15
  21. package/lib/helpers/document/compile.js +7 -4
  22. package/lib/helpers/getFunctionName.js +6 -4
  23. package/lib/helpers/isMongooseObject.js +9 -8
  24. package/lib/helpers/isObject.js +4 -4
  25. package/lib/helpers/model/discriminator.js +2 -1
  26. package/lib/helpers/path/parentPaths.js +10 -5
  27. package/lib/helpers/populate/assignRawDocsToIdStructure.js +4 -2
  28. package/lib/helpers/populate/assignVals.js +8 -4
  29. package/lib/helpers/populate/getModelsMapForPopulate.js +4 -4
  30. package/lib/helpers/populate/markArraySubdocsPopulated.js +3 -1
  31. package/lib/helpers/populate/modelNamesFromRefPath.js +4 -3
  32. package/lib/helpers/printJestWarning.js +2 -2
  33. package/lib/helpers/projection/applyProjection.js +77 -0
  34. package/lib/helpers/projection/hasIncludedChildren.js +36 -0
  35. package/lib/helpers/projection/isExclusive.js +5 -2
  36. package/lib/helpers/projection/isInclusive.js +5 -1
  37. package/lib/helpers/query/cast$expr.js +279 -0
  38. package/lib/helpers/query/castUpdate.js +6 -2
  39. package/lib/helpers/query/isOperator.js +5 -2
  40. package/lib/helpers/schema/applyPlugins.js +11 -0
  41. package/lib/helpers/schema/getPath.js +4 -2
  42. package/lib/helpers/timestamps/setupTimestamps.js +3 -8
  43. package/lib/index.js +28 -26
  44. package/lib/internal.js +1 -1
  45. package/lib/model.js +161 -122
  46. package/lib/options/SchemaTypeOptions.js +1 -1
  47. package/lib/plugins/trackTransaction.js +5 -4
  48. package/lib/query.js +159 -146
  49. package/lib/queryhelpers.js +10 -10
  50. package/lib/schema/SubdocumentPath.js +4 -3
  51. package/lib/schema/array.js +30 -21
  52. package/lib/schema/buffer.js +1 -1
  53. package/lib/schema/date.js +1 -1
  54. package/lib/schema/decimal128.js +1 -1
  55. package/lib/schema/documentarray.js +9 -11
  56. package/lib/schema/number.js +1 -1
  57. package/lib/schema/objectid.js +2 -2
  58. package/lib/schema/string.js +4 -4
  59. package/lib/schema.js +9 -8
  60. package/lib/schematype.js +77 -30
  61. package/lib/types/ArraySubdocument.js +2 -1
  62. package/lib/types/DocumentArray/index.js +10 -27
  63. package/lib/types/DocumentArray/isMongooseDocumentArray.js +5 -0
  64. package/lib/types/DocumentArray/methods/index.js +15 -3
  65. package/lib/types/array/index.js +22 -21
  66. package/lib/types/array/isMongooseArray.js +5 -0
  67. package/lib/types/array/methods/index.js +22 -23
  68. package/lib/types/buffer.js +3 -3
  69. package/lib/types/map.js +2 -3
  70. package/lib/utils.js +10 -7
  71. package/package.json +19 -151
  72. package/tools/repl.js +1 -1
  73. package/tsconfig.json +8 -0
  74. package/types/PipelineStage.d.ts +272 -0
  75. package/{index.d.ts → types/index.d.ts} +156 -357
  76. package/lib/types/array/ArrayWrapper.js +0 -981
@@ -26,9 +26,9 @@ exports.preparePopulationOptions = function preparePopulationOptions(query, opti
26
26
 
27
27
  // lean options should trickle through all queries
28
28
  if (options.lean != null) {
29
- pop.
30
- filter(p => get(p, 'options.lean') == null).
31
- forEach(makeLean(options.lean));
29
+ pop
30
+ .filter(p => (p && p.options && p.options.lean) == null)
31
+ .forEach(makeLean(options.lean));
32
32
  }
33
33
 
34
34
  pop.forEach(opts => {
@@ -53,12 +53,12 @@ exports.preparePopulationOptionsMQ = function preparePopulationOptionsMQ(query,
53
53
 
54
54
  // lean options should trickle through all queries
55
55
  if (options.lean != null) {
56
- pop.
57
- filter(p => get(p, 'options.lean') == null).
58
- forEach(makeLean(options.lean));
56
+ pop
57
+ .filter(p => (p && p.options && p.options.lean) == null)
58
+ .forEach(makeLean(options.lean));
59
59
  }
60
60
 
61
- const session = get(query, 'options.session', null);
61
+ const session = query && query.options && query.options.session || null;
62
62
  if (session != null) {
63
63
  pop.forEach(path => {
64
64
  if (path.options == null) {
@@ -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) {
@@ -272,7 +272,7 @@ exports.applyPaths = function applyPaths(fields, schema) {
272
272
  // Special case: if user has included a parent path of a discriminator key,
273
273
  // don't explicitly project in the discriminator key because that will
274
274
  // project out everything else under the parent path
275
- if (!exclude && get(type, 'options.$skipDiscriminatorCheck', false)) {
275
+ if (!exclude && (type && type.options && type.options.$skipDiscriminatorCheck || false)) {
276
276
  let cur = '';
277
277
  for (let i = 0; i < pieces.length; ++i) {
278
278
  cur += (cur.length === 0 ? '' : '.') + pieces[i];
@@ -319,7 +319,7 @@ exports.handleDeleteWriteOpResult = function handleDeleteWriteOpResult(callback)
319
319
  return callback(error);
320
320
  }
321
321
  const mongooseResult = Object.assign({}, res.result);
322
- if (get(res, 'result.n', null) != null) {
322
+ if ((res && res.result && res.result.n || null) != null) {
323
323
  mongooseResult.deletedCount = res.result.n;
324
324
  }
325
325
  if (res.deletedCount != null) {
@@ -13,7 +13,6 @@ const $exists = require('./operators/exists');
13
13
  const castToNumber = require('./operators/helpers').castToNumber;
14
14
  const discriminator = require('../helpers/model/discriminator');
15
15
  const geospatial = require('./operators/geospatial');
16
- const get = require('../helpers/get');
17
16
  const getConstructor = require('../helpers/discriminator/getConstructor');
18
17
  const handleIdOption = require('../helpers/schema/handleIdOption');
19
18
  const internalToObjectOptions = require('../options').internalToObjectOptions;
@@ -164,7 +163,7 @@ SubdocumentPath.prototype.cast = function(val, doc, init, priorVal, options) {
164
163
  let subdoc;
165
164
 
166
165
  // Only pull relevant selected paths and pull out the base path
167
- const parentSelected = get(doc, '$__.selected', {});
166
+ const parentSelected = doc && doc.$__ && doc.$__.selected || {};
168
167
  const path = this.path;
169
168
  const selected = Object.keys(parentSelected).reduce((obj, key) => {
170
169
  if (key.startsWith(path + '.')) {
@@ -301,7 +300,9 @@ SubdocumentPath.prototype.doValidateSync = function(value, scope, options) {
301
300
  SubdocumentPath.prototype.discriminator = function(name, schema, options) {
302
301
  options = options || {};
303
302
  const value = utils.isPOJO(options) ? options.value : options;
304
- const clone = get(options, 'clone', true);
303
+ const clone = typeof options.clone === 'boolean'
304
+ ? options.clone
305
+ : true;
305
306
 
306
307
  if (schema.instanceOfSchema && clone) {
307
308
  schema = schema.clone();
@@ -13,7 +13,6 @@ const CastError = SchemaType.CastError;
13
13
  const Mixed = require('./mixed');
14
14
  const arrayDepth = require('../helpers/arrayDepth');
15
15
  const cast = require('../cast');
16
- const get = require('../helpers/get');
17
16
  const isOperator = require('../helpers/query/isOperator');
18
17
  const util = require('util');
19
18
  const utils = require('../utils');
@@ -112,14 +111,12 @@ function SchemaArray(key, cast, options, schemaOptions) {
112
111
 
113
112
  if (!('defaultValue' in this) || this.defaultValue !== void 0) {
114
113
  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
114
  // Leave it up to `cast()` to convert the array
122
- return arr;
115
+ return fn
116
+ ? defaultArr.call(this)
117
+ : defaultArr != null
118
+ ? [].concat(defaultArr)
119
+ : [];
123
120
  };
124
121
  defaultFn.$runBeforeSetters = !fn;
125
122
  this.default(defaultFn);
@@ -220,7 +217,7 @@ SchemaArray.prototype.checkRequired = function checkRequired(value, doc) {
220
217
 
221
218
  // `require('util').inherits()` does **not** copy static properties, and
222
219
  // plugins like mongoose-float use `inherits()` for pre-ES6.
223
- const _checkRequired = typeof this.constructor.checkRequired == 'function' ?
220
+ const _checkRequired = typeof this.constructor.checkRequired === 'function' ?
224
221
  this.constructor.checkRequired() :
225
222
  SchemaArray.checkRequired();
226
223
 
@@ -238,7 +235,9 @@ SchemaArray.prototype.checkRequired = function checkRequired(value, doc) {
238
235
  SchemaArray.prototype.enum = function() {
239
236
  let arr = this;
240
237
  while (true) {
241
- const instance = get(arr, 'caster.instance');
238
+ const instance = arr &&
239
+ arr.caster &&
240
+ arr.caster.instance;
242
241
  if (instance === 'Array') {
243
242
  arr = arr.caster;
244
243
  continue;
@@ -275,7 +274,7 @@ SchemaArray.prototype.applyGetters = function(value, scope) {
275
274
 
276
275
  const ret = SchemaType.prototype.applyGetters.call(this, value, scope);
277
276
  if (Array.isArray(ret)) {
278
- const rawValue = ret.isMongooseArrayProxy ? ret.__array : ret;
277
+ const rawValue = utils.isMongooseArray(ret) ? ret.__array : ret;
279
278
  const len = rawValue.length;
280
279
  for (let i = 0; i < len; ++i) {
281
280
  rawValue[i] = this.caster.applyGetters(rawValue[i], scope);
@@ -299,7 +298,7 @@ SchemaArray.prototype._applySetters = function(value, scope, init, priorVal) {
299
298
  }
300
299
 
301
300
  // No need to wrap empty arrays
302
- if (value != null && value.length > 0) {
301
+ if (value != null && value.length !== 0) {
303
302
  const valueDepth = arrayDepth(value);
304
303
  if (valueDepth.min === valueDepth.max && valueDepth.max < depth && valueDepth.containsNonArrayItem) {
305
304
  for (let i = valueDepth.max; i < depth; ++i) {
@@ -357,7 +356,7 @@ SchemaArray.prototype.cast = function(value, doc, init, prev, options) {
357
356
 
358
357
  options = options || emptyOpts;
359
358
 
360
- let rawValue = value.isMongooseArrayProxy ? value.__array : value;
359
+ let rawValue = utils.isMongooseArray(value) ? value.__array : value;
361
360
  value = MongooseArray(rawValue, options.path || this._arrayPath || this.path, doc, this);
362
361
  rawValue = value.__array;
363
362
 
@@ -557,12 +556,16 @@ function cast$all(val) {
557
556
  }
558
557
 
559
558
  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];
559
+ if (!utils.isObject(v)) {
560
+ return v;
561
+ }
562
+ if (v.$elemMatch != null) {
563
+ return { $elemMatch: cast(this.casterConstructor.schema, v.$elemMatch) };
564
564
  }
565
- return v;
565
+
566
+ const o = {};
567
+ o[this.path] = v;
568
+ return cast(this.casterConstructor.schema, o)[this.path];
566
569
  }, this);
567
570
 
568
571
  return this.castForQuery(val);
@@ -581,9 +584,15 @@ function cast$elemMatch(val) {
581
584
 
582
585
  // Is this an embedded discriminator and is the discriminator key set?
583
586
  // If so, use the discriminator schema. See gh-7449
584
- const discriminatorKey = get(this,
585
- 'casterConstructor.schema.options.discriminatorKey');
586
- const discriminators = get(this, 'casterConstructor.schema.discriminators', {});
587
+ const discriminatorKey = this &&
588
+ this.casterConstructor &&
589
+ this.casterConstructor.schema &&
590
+ this.casterConstructor.schema.options &&
591
+ this.casterConstructor.schema.options.discriminatorKey;
592
+ const discriminators = this &&
593
+ this.casterConstructor &&
594
+ this.casterConstructor.schema &&
595
+ this.casterConstructor.schema.discriminators || {};
587
596
  if (discriminatorKey != null &&
588
597
  val[discriminatorKey] != null &&
589
598
  discriminators[val[discriminatorKey]] != null) {
@@ -202,7 +202,7 @@ SchemaBuffer.prototype.cast = function(value, doc, init) {
202
202
 
203
203
  /**
204
204
  * Sets the default [subtype](https://studio3t.com/whats-new/best-practices-uuid-mongodb/)
205
- * for this buffer. You can find a [list of allowed subtypes here](http://api.mongodb.com/python/current/api/bson/binary.html).
205
+ * for this buffer. You can find a [list of allowed subtypes here](https://api.mongodb.com/python/current/api/bson/binary.html).
206
206
  *
207
207
  * ####Example:
208
208
  *
@@ -201,7 +201,7 @@ SchemaDate.prototype.checkRequired = function(value, doc) {
201
201
 
202
202
  // `require('util').inherits()` does **not** copy static properties, and
203
203
  // plugins like mongoose-float use `inherits()` for pre-ES6.
204
- const _checkRequired = typeof this.constructor.checkRequired == 'function' ?
204
+ const _checkRequired = typeof this.constructor.checkRequired === 'function' ?
205
205
  this.constructor.checkRequired() :
206
206
  SchemaDate.checkRequired();
207
207
  return _checkRequired(value);
@@ -146,7 +146,7 @@ Decimal128.prototype.checkRequired = function checkRequired(value, doc) {
146
146
 
147
147
  // `require('util').inherits()` does **not** copy static properties, and
148
148
  // plugins like mongoose-float use `inherits()` for pre-ES6.
149
- const _checkRequired = typeof this.constructor.checkRequired == 'function' ?
149
+ const _checkRequired = typeof this.constructor.checkRequired === 'function' ?
150
150
  this.constructor.checkRequired() :
151
151
  Decimal128.checkRequired();
152
152
 
@@ -11,7 +11,6 @@ const SchemaDocumentArrayOptions =
11
11
  require('../options/SchemaDocumentArrayOptions');
12
12
  const SchemaType = require('../schematype');
13
13
  const discriminator = require('../helpers/model/discriminator');
14
- const get = require('../helpers/get');
15
14
  const handleIdOption = require('../helpers/schema/handleIdOption');
16
15
  const util = require('util');
17
16
  const utils = require('../utils');
@@ -68,7 +67,9 @@ function DocumentArrayPath(key, schema, options, schemaOptions) {
68
67
 
69
68
  const parentSchemaType = this;
70
69
  this.$embeddedSchemaType = new SchemaType(key + '.$', {
71
- required: get(this, 'schemaOptions.required', false)
70
+ required: this &&
71
+ this.schemaOptions &&
72
+ this.schemaOptions.required || false
72
73
  });
73
74
  this.$embeddedSchemaType.cast = function(value, doc, init) {
74
75
  return parentSchemaType.cast(value, doc, init)[0];
@@ -173,7 +174,7 @@ DocumentArrayPath.prototype.discriminator = function(name, schema, options) {
173
174
 
174
175
  options = options || {};
175
176
  const tiedValue = utils.isPOJO(options) ? options.value : options;
176
- const clone = get(options, 'clone', true);
177
+ const clone = typeof options.clone === 'boolean' ? options.clone : true;
177
178
 
178
179
  if (schema.instanceOfSchema && clone) {
179
180
  schema = schema.clone();
@@ -228,7 +229,7 @@ DocumentArrayPath.prototype.doValidate = function(array, fn, scope, options) {
228
229
  if (options && options.updateValidator) {
229
230
  return fn();
230
231
  }
231
- if (!array.isMongooseDocumentArray) {
232
+ if (!utils.isMongooseDocumentArray(array)) {
232
233
  array = new MongooseDocumentArray(array, _this.path, scope);
233
234
  }
234
235
 
@@ -398,12 +399,9 @@ DocumentArrayPath.prototype.cast = function(value, doc, init, prev, options) {
398
399
  return this.cast([value], doc, init, prev, options);
399
400
  }
400
401
 
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)
402
+ // We need to create a new array, otherwise change tracking will
403
+ // update the old doc (gh-4449)
404
+ if (!options.skipDocumentArrayCast || utils.isMongooseDocumentArray(value)) {
407
405
  value = new MongooseDocumentArray(value, this.path, doc);
408
406
  }
409
407
 
@@ -415,7 +413,7 @@ DocumentArrayPath.prototype.cast = function(value, doc, init, prev, options) {
415
413
  value[arrayPathSymbol] = this.path + '.' + options.arrayPathIndex;
416
414
  }
417
415
 
418
- const rawArray = value.isMongooseDocumentArrayProxy ? value.__array : value;
416
+ const rawArray = utils.isMongooseDocumentArray(value) ? value.__array : value;
419
417
 
420
418
  const len = rawArray.length;
421
419
  const initDocumentOptions = { skipId: true, willInit: true };
@@ -170,7 +170,7 @@ SchemaNumber.prototype.checkRequired = function checkRequired(value, doc) {
170
170
 
171
171
  // `require('util').inherits()` does **not** copy static properties, and
172
172
  // plugins like mongoose-float use `inherits()` for pre-ES6.
173
- const _checkRequired = typeof this.constructor.checkRequired == 'function' ?
173
+ const _checkRequired = typeof this.constructor.checkRequired === 'function' ?
174
174
  this.constructor.checkRequired() :
175
175
  SchemaNumber.checkRequired();
176
176
 
@@ -204,7 +204,7 @@ ObjectId.prototype.checkRequired = function checkRequired(value, doc) {
204
204
 
205
205
  // `require('util').inherits()` does **not** copy static properties, and
206
206
  // plugins like mongoose-float use `inherits()` for pre-ES6.
207
- const _checkRequired = typeof this.constructor.checkRequired == 'function' ?
207
+ const _checkRequired = typeof this.constructor.checkRequired === 'function' ?
208
208
  this.constructor.checkRequired() :
209
209
  ObjectId.checkRequired();
210
210
 
@@ -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
  }
@@ -253,7 +253,7 @@ SchemaString.prototype.enum = function() {
253
253
  };
254
254
 
255
255
  /**
256
- * Adds a lowercase [setter](http://mongoosejs.com/docs/api.html#schematype_SchemaType-set).
256
+ * Adds a lowercase [setter](https://mongoosejs.com/docs/api.html#schematype_SchemaType-set).
257
257
  *
258
258
  * ####Example:
259
259
  *
@@ -291,7 +291,7 @@ SchemaString.prototype.lowercase = function(shouldApply) {
291
291
  };
292
292
 
293
293
  /**
294
- * Adds an uppercase [setter](http://mongoosejs.com/docs/api.html#schematype_SchemaType-set).
294
+ * Adds an uppercase [setter](https://mongoosejs.com/docs/api.html#schematype_SchemaType-set).
295
295
  *
296
296
  * ####Example:
297
297
  *
@@ -327,7 +327,7 @@ SchemaString.prototype.uppercase = function(shouldApply) {
327
327
  };
328
328
 
329
329
  /**
330
- * Adds a trim [setter](http://mongoosejs.com/docs/api.html#schematype_SchemaType-set).
330
+ * Adds a trim [setter](https://mongoosejs.com/docs/api.html#schematype_SchemaType-set).
331
331
  *
332
332
  * The string value will be [trimmed](https://masteringjs.io/tutorials/fundamentals/trim-string) when set.
333
333
  *
@@ -566,7 +566,7 @@ SchemaString.prototype.checkRequired = function checkRequired(value, doc) {
566
566
 
567
567
  // `require('util').inherits()` does **not** copy static properties, and
568
568
  // plugins like mongoose-float use `inherits()` for pre-ES6.
569
- const _checkRequired = typeof this.constructor.checkRequired == 'function' ?
569
+ const _checkRequired = typeof this.constructor.checkRequired === 'function' ?
570
570
  this.constructor.checkRequired() :
571
571
  SchemaString.checkRequired();
572
572
 
package/lib/schema.js CHANGED
@@ -75,6 +75,7 @@ let id = 0;
75
75
  * - [selectPopulatedPaths](/docs/guide.html#selectPopulatedPaths): boolean - defaults to `true`
76
76
  * - [skipVersioning](/docs/guide.html#skipVersioning): object - paths to exclude from versioning
77
77
  * - [timestamps](/docs/guide.html#timestamps): object or boolean - defaults to `false`. If true, Mongoose adds `createdAt` and `updatedAt` properties to your schema and manages those properties for you.
78
+ * - [pluginTags](/docs/guide.html#pluginTags): array of strings - defaults to `undefined`. If set and plugin called with `tags` option, will only apply that plugin to schemas with a matching tag.
78
79
  *
79
80
  * ####Options for Nested Schemas:
80
81
  * - `excludeIndexes`: bool - defaults to `false`. If `true`, skip building indexes on this schema's paths.
@@ -85,7 +86,7 @@ let id = 0;
85
86
  *
86
87
  * @param {Object|Schema|Array} [definition] Can be one of: object describing schema paths, or schema to copy, or array of objects and schemas
87
88
  * @param {Object} [options]
88
- * @inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter
89
+ * @inherits NodeJS EventEmitter https://nodejs.org/api/events.html#events_class_events_eventemitter
89
90
  * @event `init`: Emitted after the schema is compiled into a `Model`.
90
91
  * @api public
91
92
  */
@@ -424,7 +425,7 @@ Schema.prototype.pick = function(paths, options) {
424
425
 
425
426
  Schema.prototype.defaultOptions = function(options) {
426
427
  this._userProvidedOptions = options == null ? {} : utils.clone(options);
427
- const baseOptions = get(this, 'base.options', {});
428
+ const baseOptions = this.base && this.base.options || {};
428
429
 
429
430
  const strict = 'strict' in baseOptions ? baseOptions.strict : true;
430
431
  options = utils.options({
@@ -518,7 +519,7 @@ Schema.prototype.add = function add(obj, prefix) {
518
519
  if (key === '_id' && val === false) {
519
520
  continue;
520
521
  }
521
- if (val instanceof VirtualType || get(val, 'constructor.name', null) === 'VirtualType') {
522
+ if (val instanceof VirtualType || (val.constructor && val.constructor.name || null) === 'VirtualType') {
522
523
  this.virtual(val);
523
524
  continue;
524
525
  }
@@ -1035,7 +1036,7 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
1035
1036
  if (!MongooseTypes.hasOwnProperty(name)) {
1036
1037
  throw new TypeError('Invalid schema configuration: ' +
1037
1038
  `\`${name}\` is not a valid type within the array \`${path}\`.` +
1038
- 'See http://bit.ly/mongoose-schematypes for a list of valid schema types.');
1039
+ 'See https://bit.ly/mongoose-schematypes for a list of valid schema types.');
1039
1040
  }
1040
1041
  }
1041
1042
 
@@ -1075,7 +1076,7 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
1075
1076
  if (MongooseTypes[name] == null) {
1076
1077
  throw new TypeError(`Invalid schema configuration: \`${name}\` is not ` +
1077
1078
  `a valid type at path \`${path}\`. See ` +
1078
- 'http://bit.ly/mongoose-schematypes for a list of valid schema types.');
1079
+ 'https://bit.ly/mongoose-schematypes for a list of valid schema types.');
1079
1080
  }
1080
1081
 
1081
1082
  const schemaType = new MongooseTypes[name](path, obj);
@@ -1470,8 +1471,8 @@ Schema.prototype.pre = function(name) {
1470
1471
  * @param {Boolean} [options.document] If `name` is a hook for both document and query middleware, set to `true` to run on document middleware.
1471
1472
  * @param {Boolean} [options.query] If `name` is a hook for both document and query middleware, set to `true` to run on query middleware.
1472
1473
  * @param {Function} fn callback
1473
- * @see middleware http://mongoosejs.com/docs/middleware.html
1474
- * @see kareem http://npmjs.org/package/kareem
1474
+ * @see middleware https://mongoosejs.com/docs/middleware.html
1475
+ * @see kareem https://npmjs.org/package/kareem
1475
1476
  * @api public
1476
1477
  */
1477
1478
 
@@ -1618,7 +1619,7 @@ Schema.prototype.static = function(name, fn) {
1618
1619
  * schema.index({ first: 1, last: -1 })
1619
1620
  *
1620
1621
  * @param {Object} fields
1621
- * @param {Object} [options] Options to pass to [MongoDB driver's `createIndex()` function](http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#createIndex)
1622
+ * @param {Object} [options] Options to pass to [MongoDB driver's `createIndex()` function](https://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#createIndex)
1622
1623
  * @param {String | number} [options.expires=null] Mongoose-specific syntactic sugar, uses [ms](https://www.npmjs.com/package/ms) to convert `expires` option into seconds for the `expireAfterSeconds` in the above link.
1623
1624
  * @api public
1624
1625
  */
package/lib/schematype.js CHANGED
@@ -8,7 +8,6 @@ const MongooseError = require('./error/index');
8
8
  const SchemaTypeOptions = require('./options/SchemaTypeOptions');
9
9
  const $exists = require('./schema/operators/exists');
10
10
  const $type = require('./schema/operators/type');
11
- const get = require('./helpers/get');
12
11
  const handleImmutable = require('./helpers/schematype/handleImmutable');
13
12
  const isAsyncFunction = require('./helpers/isAsyncFunction');
14
13
  const immediate = require('./helpers/immediate');
@@ -128,6 +127,51 @@ function SchemaType(path, options, instance) {
128
127
 
129
128
  SchemaType.prototype.OptionsConstructor = SchemaTypeOptions;
130
129
 
130
+ /**
131
+ * The path to this SchemaType in a Schema.
132
+ *
133
+ * ####Example:
134
+ * const schema = new Schema({ name: String });
135
+ * schema.path('name').path; // 'name'
136
+ *
137
+ * @property path
138
+ * @api public
139
+ * @memberOf SchemaType
140
+ */
141
+
142
+ SchemaType.prototype.path;
143
+
144
+ /**
145
+ * The validators that Mongoose should run to validate properties at this SchemaType's path.
146
+ *
147
+ * ####Example:
148
+ * const schema = new Schema({ name: { type: String, required: true } });
149
+ * schema.path('name').validators.length; // 1, the `required` validator
150
+ *
151
+ * @property validators
152
+ * @api public
153
+ * @memberOf SchemaType
154
+ */
155
+
156
+ SchemaType.prototype.validators;
157
+
158
+ /**
159
+ * True if this SchemaType has a required validator. False otherwise.
160
+ *
161
+ * ####Example:
162
+ * const schema = new Schema({ name: { type: String, required: true } });
163
+ * schema.path('name').isRequired; // true
164
+ *
165
+ * schema.path('name').required(false);
166
+ * schema.path('name').isRequired; // false
167
+ *
168
+ * @property isRequired
169
+ * @api public
170
+ * @memberOf SchemaType
171
+ */
172
+
173
+ SchemaType.prototype.validators;
174
+
131
175
  /*!
132
176
  * ignore
133
177
  */
@@ -743,7 +787,7 @@ SchemaType.prototype.get = function(fn) {
743
787
  *
744
788
  * // make sure every value is equal to "something"
745
789
  * function validator (val) {
746
- * return val == 'something';
790
+ * return val === 'something';
747
791
  * }
748
792
  * new Schema({ name: { type: String, validate: validator }});
749
793
  *
@@ -871,7 +915,7 @@ SchemaType.prototype.validate = function(obj, message, type) {
871
915
  if (!utils.isPOJO(arg)) {
872
916
  const msg = 'Invalid validator. Received (' + typeof arg + ') '
873
917
  + arg
874
- + '. See http://mongoosejs.com/docs/api.html#schematype_SchemaType-validate';
918
+ + '. See https://mongoosejs.com/docs/api.html#schematype_SchemaType-validate';
875
919
 
876
920
  throw new Error(msg);
877
921
  }
@@ -981,7 +1025,7 @@ SchemaType.prototype.required = function(required, message) {
981
1025
  this.isRequired = true;
982
1026
 
983
1027
  this.requiredValidator = function(v) {
984
- const cachedRequired = get(this, '$__.cachedRequired');
1028
+ const cachedRequired = this && this.$__ && this.$__.cachedRequired;
985
1029
 
986
1030
  // no validation when this path wasn't selected in the query.
987
1031
  if (cachedRequired != null && !this.$__isSelected(_this.path) && !this[documentIsModified](_this.path)) {
@@ -1080,7 +1124,7 @@ SchemaType.prototype.getDefault = function(scope, init) {
1080
1124
  }
1081
1125
 
1082
1126
  const casted = this.applySetters(ret, scope, init);
1083
- if (casted && casted.$isSingleNested) {
1127
+ if (casted && !Array.isArray(casted) && casted.$isSingleNested) {
1084
1128
  casted.$__parent = scope;
1085
1129
  }
1086
1130
  return casted;
@@ -1283,6 +1327,16 @@ SchemaType.prototype.doValidate = function(value, fn, scope, options) {
1283
1327
  }
1284
1328
  };
1285
1329
 
1330
+
1331
+ function _validate(ok, validatorProperties) {
1332
+ if (ok !== undefined && !ok) {
1333
+ const ErrorConstructor = validatorProperties.ErrorConstructor || ValidatorError;
1334
+ const err = new ErrorConstructor(validatorProperties);
1335
+ err[validatorErrorSymbol] = true;
1336
+ return err;
1337
+ }
1338
+ }
1339
+
1286
1340
  /**
1287
1341
  * Performs a validation of `value` using the validators declared for this SchemaType.
1288
1342
  *
@@ -1306,7 +1360,7 @@ SchemaType.prototype.doValidateSync = function(value, scope, options) {
1306
1360
 
1307
1361
  let validators = this.validators;
1308
1362
  if (value === void 0) {
1309
- if (this.validators.length > 0 && this.validators[0].type === 'required') {
1363
+ if (this.validators.length !== 0 && this.validators[0].type === 'required') {
1310
1364
  validators = [this.validators[0]];
1311
1365
  } else {
1312
1366
  return null;
@@ -1314,34 +1368,35 @@ SchemaType.prototype.doValidateSync = function(value, scope, options) {
1314
1368
  }
1315
1369
 
1316
1370
  let err = null;
1317
- validators.forEach(function(v) {
1318
- if (err) {
1319
- return;
1320
- }
1371
+ let i = 0;
1372
+ const len = validators.length;
1373
+ for (i = 0; i < len; ++i) {
1374
+
1375
+ const v = validators[i];
1321
1376
 
1322
1377
  if (v == null || typeof v !== 'object') {
1323
- return;
1378
+ continue;
1324
1379
  }
1325
1380
 
1326
1381
  const validator = v.validator;
1327
1382
  const validatorProperties = utils.clone(v);
1328
1383
  validatorProperties.path = options && options.path ? options.path : path;
1329
1384
  validatorProperties.value = value;
1330
- let ok;
1385
+ let ok = false;
1331
1386
 
1332
1387
  // Skip any explicit async validators. Validators that return a promise
1333
1388
  // will still run, but won't trigger any errors.
1334
1389
  if (isAsyncFunction(validator)) {
1335
- return;
1390
+ continue;
1336
1391
  }
1337
1392
 
1338
1393
  if (validator instanceof RegExp) {
1339
- validate(validator.test(value), validatorProperties);
1340
- return;
1394
+ err = _validate(validator.test(value), validatorProperties);
1395
+ continue;
1341
1396
  }
1342
1397
 
1343
1398
  if (typeof validator !== 'function') {
1344
- return;
1399
+ continue;
1345
1400
  }
1346
1401
 
1347
1402
  try {
@@ -1358,23 +1413,15 @@ SchemaType.prototype.doValidateSync = function(value, scope, options) {
1358
1413
  // Skip any validators that return a promise, we can't handle those
1359
1414
  // synchronously
1360
1415
  if (ok != null && typeof ok.then === 'function') {
1361
- return;
1416
+ continue;
1362
1417
  }
1363
- validate(ok, validatorProperties);
1364
- });
1365
-
1366
- return err;
1367
-
1368
- function validate(ok, validatorProperties) {
1418
+ err = _validate(ok, validatorProperties);
1369
1419
  if (err) {
1370
- return;
1371
- }
1372
- if (ok !== undefined && !ok) {
1373
- const ErrorConstructor = validatorProperties.ErrorConstructor || ValidatorError;
1374
- err = new ErrorConstructor(validatorProperties);
1375
- err[validatorErrorSymbol] = true;
1420
+ break;
1376
1421
  }
1377
1422
  }
1423
+
1424
+ return err;
1378
1425
  };
1379
1426
 
1380
1427
  /**
@@ -1585,7 +1632,7 @@ SchemaType.prototype._castForQuery = function(val) {
1585
1632
  */
1586
1633
 
1587
1634
  SchemaType.checkRequired = function(fn) {
1588
- if (arguments.length > 0) {
1635
+ if (arguments.length !== 0) {
1589
1636
  this._checkRequired = fn;
1590
1637
  }
1591
1638
 
@@ -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 {