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