mongoose 8.20.0 → 9.0.0-rc0

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 (90) hide show
  1. package/eslint.config.mjs +198 -0
  2. package/lib/aggregate.js +17 -73
  3. package/lib/cast/bigint.js +1 -1
  4. package/lib/cast/double.js +1 -1
  5. package/lib/cast/uuid.js +5 -48
  6. package/lib/cast.js +2 -2
  7. package/lib/connection.js +0 -1
  8. package/lib/cursor/aggregationCursor.js +14 -24
  9. package/lib/cursor/queryCursor.js +7 -14
  10. package/lib/document.js +125 -121
  11. package/lib/drivers/node-mongodb-native/connection.js +3 -10
  12. package/lib/error/objectParameter.js +1 -2
  13. package/lib/error/validation.js +0 -8
  14. package/lib/helpers/clone.js +1 -1
  15. package/lib/helpers/common.js +1 -1
  16. package/lib/helpers/indexes/isIndexEqual.js +0 -1
  17. package/lib/helpers/model/applyDefaultsToPOJO.js +2 -2
  18. package/lib/helpers/model/applyHooks.js +43 -53
  19. package/lib/helpers/model/applyMethods.js +2 -2
  20. package/lib/helpers/model/applyStaticHooks.js +1 -48
  21. package/lib/helpers/model/castBulkWrite.js +1 -1
  22. package/lib/helpers/parallelLimit.js +18 -36
  23. package/lib/helpers/pluralize.js +3 -3
  24. package/lib/helpers/populate/assignRawDocsToIdStructure.js +1 -8
  25. package/lib/helpers/populate/createPopulateQueryFilter.js +1 -1
  26. package/lib/helpers/populate/getModelsMapForPopulate.js +17 -9
  27. package/lib/helpers/populate/getSchemaTypes.js +5 -5
  28. package/lib/helpers/query/cast$expr.js +8 -10
  29. package/lib/helpers/query/castFilterPath.js +1 -1
  30. package/lib/helpers/query/castUpdate.js +14 -12
  31. package/lib/helpers/query/getEmbeddedDiscriminatorPath.js +1 -1
  32. package/lib/helpers/schema/applyPlugins.js +1 -1
  33. package/lib/helpers/schema/getIndexes.js +1 -7
  34. package/lib/helpers/timestamps/setupTimestamps.js +3 -6
  35. package/lib/helpers/updateValidators.js +57 -111
  36. package/lib/model.js +419 -607
  37. package/lib/mongoose.js +41 -13
  38. package/lib/plugins/saveSubdocs.js +24 -51
  39. package/lib/plugins/sharding.js +5 -4
  40. package/lib/plugins/validateBeforeSave.js +3 -13
  41. package/lib/query.js +101 -145
  42. package/lib/queryHelpers.js +2 -2
  43. package/lib/schema/array.js +41 -84
  44. package/lib/schema/documentArray.js +57 -94
  45. package/lib/schema/documentArrayElement.js +16 -11
  46. package/lib/schema/string.js +1 -1
  47. package/lib/schema/subdocument.js +22 -28
  48. package/lib/schema/uuid.js +0 -21
  49. package/lib/schema.js +81 -39
  50. package/lib/schemaType.js +39 -57
  51. package/lib/types/array/index.js +2 -2
  52. package/lib/types/array/methods/index.js +4 -4
  53. package/lib/types/arraySubdocument.js +1 -1
  54. package/lib/types/buffer.js +10 -10
  55. package/lib/types/decimal128.js +1 -1
  56. package/lib/types/documentArray/index.js +1 -1
  57. package/lib/types/documentArray/methods/index.js +5 -3
  58. package/lib/types/double.js +1 -1
  59. package/lib/types/objectid.js +1 -1
  60. package/lib/types/subdocument.js +15 -43
  61. package/lib/types/uuid.js +1 -1
  62. package/lib/utils.js +1 -8
  63. package/lib/validOptions.js +3 -3
  64. package/package.json +11 -24
  65. package/types/connection.d.ts +20 -11
  66. package/types/document.d.ts +95 -26
  67. package/types/index.d.ts +143 -39
  68. package/types/inferhydrateddoctype.d.ts +115 -0
  69. package/types/inferrawdoctype.d.ts +99 -75
  70. package/types/inferschematype.d.ts +17 -3
  71. package/types/middlewares.d.ts +0 -2
  72. package/types/models.d.ts +131 -199
  73. package/types/mongooseoptions.d.ts +6 -5
  74. package/types/pipelinestage.d.ts +1 -1
  75. package/types/query.d.ts +71 -139
  76. package/types/schemaoptions.d.ts +1 -1
  77. package/types/schematypes.d.ts +14 -10
  78. package/types/types.d.ts +3 -4
  79. package/types/utility.d.ts +68 -48
  80. package/types/validation.d.ts +18 -14
  81. package/browser.js +0 -8
  82. package/dist/browser.umd.js +0 -2
  83. package/lib/browser.js +0 -141
  84. package/lib/browserDocument.js +0 -101
  85. package/lib/documentProvider.js +0 -30
  86. package/lib/drivers/browser/binary.js +0 -14
  87. package/lib/drivers/browser/decimal128.js +0 -7
  88. package/lib/drivers/browser/index.js +0 -13
  89. package/lib/drivers/browser/objectid.js +0 -29
  90. package/lib/helpers/promiseOrCallback.js +0 -54
@@ -28,7 +28,6 @@ const getDiscriminatorByValue = require('../helpers/discriminator/getDiscriminat
28
28
  let MongooseArray;
29
29
  let EmbeddedDoc;
30
30
 
31
- const isNestedArraySymbol = Symbol('mongoose#isNestedArray');
32
31
  const emptyOpts = Object.freeze({});
33
32
 
34
33
  /**
@@ -81,31 +80,21 @@ function SchemaArray(key, cast, options, schemaOptions, parentSchema) {
81
80
  : utils.getFunctionName(cast);
82
81
 
83
82
  const Types = require('./index.js');
84
- const caster = Types.hasOwnProperty(name) ? Types[name] : cast;
83
+ const schemaTypeDefinition = Types.hasOwnProperty(name) ? Types[name] : cast;
85
84
 
86
- this.casterConstructor = caster;
87
-
88
- if (this.casterConstructor instanceof SchemaArray) {
89
- this.casterConstructor[isNestedArraySymbol] = true;
90
- }
91
-
92
- if (typeof caster === 'function' &&
93
- !caster.$isArraySubdocument &&
94
- !caster.$isSchemaMap) {
95
- const path = this.caster instanceof EmbeddedDoc ? null : key;
96
- if (caster === SchemaArray) {
97
- this.caster = new caster(path, castOptions, schemaOptions, null, parentSchema);
85
+ if (typeof schemaTypeDefinition === 'function') {
86
+ if (schemaTypeDefinition === SchemaArray) {
87
+ this.embeddedSchemaType = new schemaTypeDefinition(key, castOptions, schemaOptions, null, parentSchema);
98
88
  } else {
99
- this.caster = new caster(path, castOptions, schemaOptions, parentSchema);
89
+ this.embeddedSchemaType = new schemaTypeDefinition(key, castOptions, schemaOptions, parentSchema);
100
90
  }
101
- } else {
102
- this.caster = caster;
103
- if (!(this.caster instanceof EmbeddedDoc)) {
104
- this.caster.path = key;
91
+ } else if (schemaTypeDefinition instanceof SchemaType) {
92
+ this.embeddedSchemaType = schemaTypeDefinition;
93
+ if (!(this.embeddedSchemaType instanceof EmbeddedDoc)) {
94
+ this.embeddedSchemaType.path = key;
105
95
  }
106
96
  }
107
97
 
108
- this.$embeddedSchemaType = this.caster;
109
98
  }
110
99
 
111
100
  this.$isMongooseArray = true;
@@ -267,10 +256,10 @@ SchemaArray.prototype.enum = function() {
267
256
  let arr = this;
268
257
  while (true) {
269
258
  const instance = arr &&
270
- arr.caster &&
271
- arr.caster.instance;
259
+ arr.embeddedSchemaType &&
260
+ arr.embeddedSchemaType.instance;
272
261
  if (instance === 'Array') {
273
- arr = arr.caster;
262
+ arr = arr.embeddedSchemaType;
274
263
  continue;
275
264
  }
276
265
  if (instance !== 'String' && instance !== 'Number') {
@@ -285,7 +274,7 @@ SchemaArray.prototype.enum = function() {
285
274
  enumArray = utils.object.vals(enumArray);
286
275
  }
287
276
 
288
- arr.caster.enum.apply(arr.caster, enumArray);
277
+ arr.embeddedSchemaType.enum.apply(arr.embeddedSchemaType, enumArray);
289
278
  return this;
290
279
  };
291
280
 
@@ -308,9 +297,8 @@ SchemaArray.prototype.applyGetters = function(value, scope) {
308
297
  };
309
298
 
310
299
  SchemaArray.prototype._applySetters = function(value, scope, init, priorVal) {
311
- if (this.casterConstructor.$isMongooseArray &&
312
- SchemaArray.options.castNonArrays &&
313
- !this[isNestedArraySymbol]) {
300
+ if (this.embeddedSchemaType.$isMongooseArray &&
301
+ SchemaArray.options.castNonArrays) {
314
302
  // Check nesting levels and wrap in array if necessary
315
303
  let depth = 0;
316
304
  let arr = this;
@@ -318,7 +306,7 @@ SchemaArray.prototype._applySetters = function(value, scope, init, priorVal) {
318
306
  arr.$isMongooseArray &&
319
307
  !arr.$isMongooseDocumentArray) {
320
308
  ++depth;
321
- arr = arr.casterConstructor;
309
+ arr = arr.embeddedSchemaType;
322
310
  }
323
311
 
324
312
  // No need to wrap empty arrays
@@ -392,9 +380,9 @@ SchemaArray.prototype.cast = function(value, doc, init, prev, options) {
392
380
  return value;
393
381
  }
394
382
 
395
- const caster = this.caster;
383
+ const caster = this.embeddedSchemaType;
396
384
  const isMongooseArray = caster.$isMongooseArray;
397
- if (caster && this.casterConstructor !== Mixed) {
385
+ if (caster && this.embeddedSchemaType.constructor !== Mixed) {
398
386
  try {
399
387
  const len = rawValue.length;
400
388
  for (i = 0; i < len; i++) {
@@ -449,19 +437,18 @@ SchemaArray.prototype._castForPopulate = function _castForPopulate(value, doc) {
449
437
  const rawValue = value.__array ? value.__array : value;
450
438
  const len = rawValue.length;
451
439
 
452
- const caster = this.caster;
453
- if (caster && this.casterConstructor !== Mixed) {
440
+ if (this.embeddedSchemaType && this.embeddedSchemaType.constructor !== Mixed) {
454
441
  try {
455
442
  for (i = 0; i < len; i++) {
456
443
  const opts = {};
457
444
  // Perf: creating `arrayPath` is expensive for large arrays.
458
445
  // We only need `arrayPath` if this is a nested array, so
459
446
  // skip if possible.
460
- if (caster.$isMongooseArray && caster._arrayParentPath != null) {
447
+ if (this.embeddedSchemaType.$isMongooseArray && this.embeddedSchemaType._arrayParentPath != null) {
461
448
  opts.arrayPathIndex = i;
462
449
  }
463
450
 
464
- rawValue[i] = caster.cast(rawValue[i], doc, false, void 0, opts);
451
+ rawValue[i] = this.embeddedSchemaType.cast(rawValue[i], doc, false, void 0, opts);
465
452
  }
466
453
  } catch (e) {
467
454
  // rethrow
@@ -484,11 +471,10 @@ SchemaArray.prototype.$toObject = SchemaArray.prototype.toObject;
484
471
  SchemaArray.prototype.discriminator = function(...args) {
485
472
  let arr = this;
486
473
  while (arr.$isMongooseArray && !arr.$isMongooseDocumentArray) {
487
- arr = arr.casterConstructor;
488
- if (arr == null || typeof arr === 'function') {
489
- throw new MongooseError('You can only add an embedded discriminator on ' +
490
- 'a document array, ' + this.path + ' is a plain array');
491
- }
474
+ arr = arr.embeddedSchemaType;
475
+ }
476
+ if (!arr.$isMongooseDocumentArray) {
477
+ throw new MongooseError('You can only add an embedded discriminator on a document array, ' + this.path + ' is a plain array');
492
478
  }
493
479
  return arr.discriminator(...args);
494
480
  };
@@ -499,7 +485,7 @@ SchemaArray.prototype.discriminator = function(...args) {
499
485
 
500
486
  SchemaArray.prototype.clone = function() {
501
487
  const options = Object.assign({}, this.options);
502
- const schematype = new this.constructor(this.path, this.caster, options, this.schemaOptions, this.parentSchema);
488
+ const schematype = new this.constructor(this.path, this.embeddedSchemaType, options, this.schemaOptions, this.parentSchema);
503
489
  schematype.validators = this.validators.slice();
504
490
  if (this.requiredValidator !== undefined) {
505
491
  schematype.requiredValidator = this.requiredValidator;
@@ -508,30 +494,21 @@ SchemaArray.prototype.clone = function() {
508
494
  };
509
495
 
510
496
  SchemaArray.prototype._castForQuery = function(val, context) {
511
- let Constructor = this.casterConstructor;
512
-
513
- if (val &&
514
- Constructor.discriminators &&
515
- Constructor.schema &&
516
- Constructor.schema.options &&
517
- Constructor.schema.options.discriminatorKey) {
518
- if (typeof val[Constructor.schema.options.discriminatorKey] === 'string' &&
519
- Constructor.discriminators[val[Constructor.schema.options.discriminatorKey]]) {
520
- Constructor = Constructor.discriminators[val[Constructor.schema.options.discriminatorKey]];
497
+ let embeddedSchemaType = this.embeddedSchemaType;
498
+ const discriminatorKey = embeddedSchemaType?.schema?.options?.discriminatorKey;
499
+ const discriminators = embeddedSchemaType?.discriminators;
500
+
501
+ if (val && discriminators && typeof discriminatorKey === 'string') {
502
+ if (discriminators[val[discriminatorKey]]) {
503
+ embeddedSchemaType = discriminators[val[discriminatorKey]];
521
504
  } else {
522
- const constructorByValue = getDiscriminatorByValue(Constructor.discriminators, val[Constructor.schema.options.discriminatorKey]);
505
+ const constructorByValue = getDiscriminatorByValue(discriminators, val[discriminatorKey]);
523
506
  if (constructorByValue) {
524
- Constructor = constructorByValue;
507
+ embeddedSchemaType = constructorByValue;
525
508
  }
526
509
  }
527
510
  }
528
511
 
529
- const proto = this.casterConstructor.prototype;
530
- const protoCastForQuery = proto && proto.castForQuery;
531
- const protoCast = proto && proto.cast;
532
- const constructorCastForQuery = Constructor.castForQuery;
533
- const caster = this.caster;
534
-
535
512
  if (Array.isArray(val)) {
536
513
  this.setters.reverse().forEach(setter => {
537
514
  val = setter.call(this, val, this);
@@ -540,30 +517,10 @@ SchemaArray.prototype._castForQuery = function(val, context) {
540
517
  if (utils.isObject(v) && v.$elemMatch) {
541
518
  return v;
542
519
  }
543
- if (protoCastForQuery) {
544
- v = protoCastForQuery.call(caster, null, v, context);
545
- return v;
546
- } else if (protoCast) {
547
- v = protoCast.call(caster, v);
548
- return v;
549
- } else if (constructorCastForQuery) {
550
- v = constructorCastForQuery.call(caster, null, v, context);
551
- return v;
552
- }
553
- if (v != null) {
554
- v = new Constructor(v);
555
- return v;
556
- }
557
- return v;
520
+ return embeddedSchemaType.castForQuery(null, v, context);
558
521
  });
559
- } else if (protoCastForQuery) {
560
- val = protoCastForQuery.call(caster, null, val, context);
561
- } else if (protoCast) {
562
- val = protoCast.call(caster, val);
563
- } else if (constructorCastForQuery) {
564
- val = constructorCastForQuery.call(caster, null, val, context);
565
- } else if (val != null) {
566
- val = new Constructor(val);
522
+ } else {
523
+ val = embeddedSchemaType.castForQuery(null, val, context);
567
524
  }
568
525
 
569
526
  return val;
@@ -629,12 +586,12 @@ function cast$all(val, context) {
629
586
  return v;
630
587
  }
631
588
  if (v.$elemMatch != null) {
632
- return { $elemMatch: cast(this.casterConstructor.schema, v.$elemMatch, null, this && this.$$context) };
589
+ return { $elemMatch: cast(this.embeddedSchemaType.schema, v.$elemMatch, null, this && this.$$context) };
633
590
  }
634
591
 
635
592
  const o = {};
636
593
  o[this.path] = v;
637
- return cast(this.casterConstructor.schema, o, null, this && this.$$context)[this.path];
594
+ return cast(this.embeddedSchemaType.schema, o, null, this && this.$$context)[this.path];
638
595
  }, this);
639
596
 
640
597
  return this.castForQuery(null, val, context);
@@ -682,7 +639,7 @@ function createLogicalQueryOperatorHandler(op) {
682
639
 
683
640
  const ret = [];
684
641
  for (const obj of val) {
685
- ret.push(cast(this.casterConstructor.schema ?? context.schema, obj, null, this && this.$$context));
642
+ ret.push(cast(this.embeddedSchemaType.schema ?? context.schema, obj, null, this && this.$$context));
686
643
  }
687
644
 
688
645
  return ret;
@@ -57,18 +57,26 @@ function SchemaDocumentArray(key, schema, options, schemaOptions, parentSchema)
57
57
  schema = handleIdOption(schema, options);
58
58
  }
59
59
 
60
- const EmbeddedDocument = _createConstructor(schema, options);
61
- EmbeddedDocument.prototype.$basePath = key;
60
+ const Constructor = _createConstructor(schema, options);
61
+ Constructor.prototype.$basePath = key;
62
+ Constructor.path = key;
62
63
 
63
- SchemaArray.call(this, key, EmbeddedDocument, options, null, parentSchema);
64
+ const $parentSchemaType = this;
65
+ const embeddedSchemaType = new DocumentArrayElement(key + '.$', schema, {
66
+ ...(schemaOptions || {}),
67
+ $parentSchemaType,
68
+ Constructor
69
+ });
70
+
71
+ SchemaArray.call(this, key, embeddedSchemaType, options, null, parentSchema);
64
72
 
65
73
  this.schema = schema;
66
74
  // EmbeddedDocument schematype options
67
75
  this.schemaOptions = schemaOptions || {};
68
76
  this.$isMongooseDocumentArray = true;
69
- this.Constructor = EmbeddedDocument;
77
+ this.Constructor = Constructor;
70
78
 
71
- EmbeddedDocument.base = schema.base;
79
+ Constructor.base = schema.base;
72
80
 
73
81
  const fn = this.defaultValue;
74
82
 
@@ -82,20 +90,6 @@ function SchemaDocumentArray(key, schema, options, schemaOptions, parentSchema)
82
90
  return arr;
83
91
  });
84
92
  }
85
-
86
- const $parentSchemaType = this;
87
- this.$embeddedSchemaType = new DocumentArrayElement(
88
- key + '.$',
89
- {
90
- ...(schemaOptions || {}),
91
- $parentSchemaType
92
- },
93
- schemaOptions,
94
- parentSchema
95
- );
96
-
97
- this.$embeddedSchemaType.caster = this.Constructor;
98
- this.$embeddedSchemaType.schema = this.schema;
99
93
  }
100
94
 
101
95
  /**
@@ -218,93 +212,62 @@ SchemaDocumentArray.prototype.discriminator = function(name, schema, options) {
218
212
  schema = schema.clone();
219
213
  }
220
214
 
221
- schema = discriminator(this.casterConstructor, name, schema, tiedValue, null, null, options?.overwriteExisting);
215
+ schema = discriminator(this.Constructor, name, schema, tiedValue, null, null, options?.overwriteExisting);
222
216
 
223
- const EmbeddedDocument = _createConstructor(schema, null, this.casterConstructor);
224
- EmbeddedDocument.baseCasterConstructor = this.casterConstructor;
217
+ const EmbeddedDocument = _createConstructor(schema, null, this.Constructor);
218
+ EmbeddedDocument.baseCasterConstructor = this.Constructor;
225
219
 
226
- try {
227
- Object.defineProperty(EmbeddedDocument, 'name', {
228
- value: name
229
- });
230
- } catch (error) {
231
- // Ignore error, only happens on old versions of node
232
- }
220
+ Object.defineProperty(EmbeddedDocument, 'name', {
221
+ value: name
222
+ });
233
223
 
234
- this.casterConstructor.discriminators[name] = EmbeddedDocument;
224
+ this.Constructor.discriminators[name] = EmbeddedDocument;
235
225
 
236
- return this.casterConstructor.discriminators[name];
226
+ return this.Constructor.discriminators[name];
237
227
  };
238
228
 
239
229
  /**
240
230
  * Performs local validations first, then validations on each embedded doc
241
231
  *
242
- * @api private
232
+ * @api public
243
233
  */
244
234
 
245
- SchemaDocumentArray.prototype.doValidate = function(array, fn, scope, options) {
235
+ SchemaDocumentArray.prototype.doValidate = async function doValidate(array, scope, options) {
246
236
  // lazy load
247
237
  MongooseDocumentArray || (MongooseDocumentArray = require('../types/documentArray'));
248
238
 
249
- const _this = this;
250
- try {
251
- SchemaType.prototype.doValidate.call(this, array, cb, scope);
252
- } catch (err) {
253
- return fn(err);
239
+ await SchemaType.prototype.doValidate.call(this, array, scope);
240
+ if (options?.updateValidator) {
241
+ return;
242
+ }
243
+ if (!utils.isMongooseDocumentArray(array)) {
244
+ array = new MongooseDocumentArray(array, this.path, scope);
254
245
  }
255
246
 
256
- function cb(err) {
257
- if (err) {
258
- return fn(err);
259
- }
260
-
261
- let count = array && array.length;
262
- let error;
263
-
264
- if (!count) {
265
- return fn();
266
- }
267
- if (options && options.updateValidator) {
268
- return fn();
269
- }
270
- if (!utils.isMongooseDocumentArray(array)) {
271
- array = new MongooseDocumentArray(array, _this.path, scope);
272
- }
273
-
247
+ const promises = [];
248
+ for (let i = 0; i < array.length; ++i) {
274
249
  // handle sparse arrays, do not use array.forEach which does not
275
250
  // iterate over sparse elements yet reports array.length including
276
251
  // them :(
277
-
278
- function callback(err) {
279
- if (err != null) {
280
- error = err;
281
- }
282
- --count || fn(error);
252
+ let doc = array[i];
253
+ if (doc == null) {
254
+ continue;
255
+ }
256
+ // If you set the array index directly, the doc might not yet be
257
+ // a full fledged mongoose subdoc, so make it into one.
258
+ if (!(doc instanceof Subdocument)) {
259
+ const Constructor = getConstructor(this.Constructor, array[i]);
260
+ doc = array[i] = new Constructor(doc, array, undefined, undefined, i);
283
261
  }
284
262
 
285
- for (let i = 0, len = count; i < len; ++i) {
286
- // sidestep sparse entries
287
- let doc = array[i];
288
- if (doc == null) {
289
- --count || fn(error);
290
- continue;
291
- }
292
-
293
- // If you set the array index directly, the doc might not yet be
294
- // a full fledged mongoose subdoc, so make it into one.
295
- if (!(doc instanceof Subdocument)) {
296
- const Constructor = getConstructor(_this.casterConstructor, array[i]);
297
- doc = array[i] = new Constructor(doc, array, undefined, undefined, i);
298
- }
299
-
300
- if (options != null && options.validateModifiedOnly && !doc.$isModified()) {
301
- --count || fn(error);
302
- continue;
303
- }
304
-
305
- doc.$__validate(null, options, callback);
263
+ if (options != null && options.validateModifiedOnly && !doc.$isModified()) {
264
+ continue;
306
265
  }
266
+
267
+ promises.push(doc.$__validate(null, options));
307
268
  }
269
+
270
+ await Promise.all(promises);
308
271
  };
309
272
 
310
273
  /**
@@ -345,7 +308,7 @@ SchemaDocumentArray.prototype.doValidateSync = function(array, scope, options) {
345
308
  // If you set the array index directly, the doc might not yet be
346
309
  // a full fledged mongoose subdoc, so make it into one.
347
310
  if (!(doc instanceof Subdocument)) {
348
- const Constructor = getConstructor(this.casterConstructor, array[i]);
311
+ const Constructor = getConstructor(this.Constructor, array[i]);
349
312
  doc = array[i] = new Constructor(doc, array, undefined, undefined, i);
350
313
  }
351
314
 
@@ -390,7 +353,7 @@ SchemaDocumentArray.prototype.getDefault = function(scope, init, options) {
390
353
  ret = new MongooseDocumentArray(ret, this.path, scope);
391
354
 
392
355
  for (let i = 0; i < ret.length; ++i) {
393
- const Constructor = getConstructor(this.casterConstructor, ret[i]);
356
+ const Constructor = getConstructor(this.Constructor, ret[i]);
394
357
  const _subdoc = new Constructor({}, ret, undefined,
395
358
  undefined, i);
396
359
  _subdoc.$init(ret[i]);
@@ -468,7 +431,7 @@ SchemaDocumentArray.prototype.cast = function(value, doc, init, prev, options) {
468
431
  continue;
469
432
  }
470
433
 
471
- const Constructor = getConstructor(this.casterConstructor, rawArray[i]);
434
+ const Constructor = getConstructor(this.Constructor, rawArray[i]);
472
435
 
473
436
  const spreadDoc = handleSpreadDoc(rawArray[i], true);
474
437
  if (rawArray[i] !== spreadDoc) {
@@ -659,21 +622,21 @@ function cast$elemMatch(val, context) {
659
622
  // Is this an embedded discriminator and is the discriminator key set?
660
623
  // If so, use the discriminator schema. See gh-7449
661
624
  const discriminatorKey = this &&
662
- this.casterConstructor &&
663
- this.casterConstructor.schema &&
664
- this.casterConstructor.schema.options &&
665
- this.casterConstructor.schema.options.discriminatorKey;
625
+ this.Constructor &&
626
+ this.Constructor.schema &&
627
+ this.Constructor.schema.options &&
628
+ this.Constructor.schema.options.discriminatorKey;
666
629
  const discriminators = this &&
667
- this.casterConstructor &&
668
- this.casterConstructor.schema &&
669
- this.casterConstructor.schema.discriminators || {};
630
+ this.Constructor &&
631
+ this.Constructor.schema &&
632
+ this.Constructor.schema.discriminators || {};
670
633
  if (discriminatorKey != null &&
671
634
  val[discriminatorKey] != null &&
672
635
  discriminators[val[discriminatorKey]] != null) {
673
636
  return cast(discriminators[val[discriminatorKey]], val, null, this && this.$$context);
674
637
  }
675
638
 
676
- const schema = this.casterConstructor.schema ?? context.schema;
639
+ const schema = this.Constructor.schema ?? context.schema;
677
640
  return cast(schema, val, null, this && this.$$context);
678
641
  }
679
642
 
@@ -10,17 +10,22 @@ const SchemaSubdocument = require('./subdocument');
10
10
  const getConstructor = require('../helpers/discriminator/getConstructor');
11
11
 
12
12
  /**
13
- * DocumentArrayElement SchemaType constructor.
13
+ * DocumentArrayElement SchemaType constructor. Mongoose calls this internally when you define a new document array in your schema.
14
+ *
15
+ * #### Example:
16
+ * const schema = new Schema({ users: [{ name: String }] });
17
+ * schema.path('users.$'); // SchemaDocumentArrayElement with schema `new Schema({ name: String })`
14
18
  *
15
19
  * @param {String} path
20
+ * @param {Schema} schema
21
+ * @param {Object} options
16
22
  * @param {Object} options
17
- * @param {Object} schemaOptions
18
23
  * @param {Schema} parentSchema
19
24
  * @inherits SchemaType
20
25
  * @api public
21
26
  */
22
27
 
23
- function SchemaDocumentArrayElement(path, options, _schemaOptions, parentSchema) {
28
+ function SchemaDocumentArrayElement(path, schema, options, parentSchema) {
24
29
  this.$parentSchemaType = options && options.$parentSchemaType;
25
30
  if (!this.$parentSchemaType) {
26
31
  throw new MongooseError('Cannot create DocumentArrayElement schematype without a parent');
@@ -30,6 +35,8 @@ function SchemaDocumentArrayElement(path, options, _schemaOptions, parentSchema)
30
35
  SchemaType.call(this, path, options, 'DocumentArrayElement', parentSchema);
31
36
 
32
37
  this.$isMongooseDocumentArrayElement = true;
38
+ this.Constructor = options && options.Constructor;
39
+ this.schema = schema;
33
40
  }
34
41
 
35
42
  /**
@@ -60,21 +67,19 @@ SchemaDocumentArrayElement.prototype.cast = function(...args) {
60
67
  };
61
68
 
62
69
  /**
63
- * Casts contents for queries.
70
+ * Async validation on this individual array element
64
71
  *
65
- * @param {String} $cond
66
- * @param {any} [val]
67
- * @api private
72
+ * @api public
68
73
  */
69
74
 
70
- SchemaDocumentArrayElement.prototype.doValidate = function(value, fn, scope, options) {
71
- const Constructor = getConstructor(this.caster, value);
75
+ SchemaDocumentArrayElement.prototype.doValidate = async function doValidate(value, scope, options) {
76
+ const Constructor = getConstructor(this.Constructor, value);
72
77
 
73
78
  if (value && !(value instanceof Constructor)) {
74
79
  value = new Constructor(value, scope, null, null, options && options.index != null ? options.index : null);
75
80
  }
76
81
 
77
- return SchemaSubdocument.prototype.doValidate.call(this, value, fn, scope, options);
82
+ return SchemaSubdocument.prototype.doValidate.call(this, value, scope, options);
78
83
  };
79
84
 
80
85
  /**
@@ -89,7 +94,7 @@ SchemaDocumentArrayElement.prototype.clone = function() {
89
94
  const ret = SchemaType.prototype.clone.apply(this, arguments);
90
95
  delete this.options.$parentSchemaType;
91
96
 
92
- ret.caster = this.caster;
97
+ ret.Constructor = this.Constructor;
93
98
  ret.schema = this.schema;
94
99
 
95
100
  return ret;
@@ -605,7 +605,7 @@ SchemaString.prototype.cast = function(value, doc, init, prev, options) {
605
605
 
606
606
  try {
607
607
  return castString(value);
608
- } catch (error) {
608
+ } catch {
609
609
  throw new CastError('string', value, this.path, null, this);
610
610
  }
611
611
  };