mongoose 9.3.2 → 9.4.0

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 (40) hide show
  1. package/lib/aggregate.js +1 -1
  2. package/lib/connection.js +20 -8
  3. package/lib/document.js +108 -48
  4. package/lib/drivers/node-mongodb-native/collection.js +37 -10
  5. package/lib/drivers/node-mongodb-native/connection.js +13 -0
  6. package/lib/error/index.js +1 -1
  7. package/lib/helpers/isBsonType.js +1 -1
  8. package/lib/helpers/setDefaultsOnInsert.js +1 -1
  9. package/lib/model.js +6 -3
  10. package/lib/mongoose.js +4 -4
  11. package/lib/query.js +1 -1
  12. package/lib/schema/array.js +1 -3
  13. package/lib/schema/bigint.js +1 -3
  14. package/lib/schema/boolean.js +1 -3
  15. package/lib/schema/buffer.js +1 -3
  16. package/lib/schema/date.js +1 -3
  17. package/lib/schema/decimal128.js +1 -3
  18. package/lib/schema/documentArray.js +2 -4
  19. package/lib/schema/double.js +1 -3
  20. package/lib/schema/int32.js +1 -3
  21. package/lib/schema/map.js +1 -4
  22. package/lib/schema/number.js +2 -4
  23. package/lib/schema/objectId.js +1 -3
  24. package/lib/schema/string.js +1 -3
  25. package/lib/schema/subdocument.js +1 -3
  26. package/lib/schema/union.js +50 -0
  27. package/lib/schema/uuid.js +1 -3
  28. package/lib/schema.js +5 -5
  29. package/lib/schemaType.js +46 -13
  30. package/lib/types/array/methods/index.js +4 -4
  31. package/lib/utils.js +12 -2
  32. package/package.json +6 -6
  33. package/types/document.d.ts +40 -3
  34. package/types/index.d.ts +17 -2
  35. package/types/models.d.ts +2 -2
  36. package/types/populate.d.ts +44 -0
  37. package/types/query.d.ts +26 -9
  38. package/types/utility.d.ts +3 -3
  39. package/lib/helpers/createJSONSchemaTypeDefinition.js +0 -24
  40. /package/{tstyche.config.json → tstyche.json} +0 -0
@@ -7,7 +7,6 @@
7
7
  const CastError = require('../error/cast');
8
8
  const SchemaType = require('../schemaType');
9
9
  const castDouble = require('../cast/double');
10
- const createJSONSchemaTypeDefinition = require('../helpers/createJSONSchemaTypeDefinition');
11
10
 
12
11
  /**
13
12
  * Double SchemaType constructor.
@@ -231,8 +230,7 @@ Object.defineProperty(SchemaDouble.prototype, '$conditionalHandlers', {
231
230
  */
232
231
 
233
232
  SchemaDouble.prototype.toJSONSchema = function toJSONSchema(options) {
234
- const isRequired = this.options.required && typeof this.options.required !== 'function';
235
- return createJSONSchemaTypeDefinition('number', 'double', options?.useBsonType, isRequired);
233
+ return this._createJSONSchemaTypeDefinition('number', 'double', options);
236
234
  };
237
235
 
238
236
  SchemaDouble.prototype.autoEncryptionType = function autoEncryptionType() {
@@ -7,7 +7,6 @@
7
7
  const CastError = require('../error/cast');
8
8
  const SchemaType = require('../schemaType');
9
9
  const castInt32 = require('../cast/int32');
10
- const createJSONSchemaTypeDefinition = require('../helpers/createJSONSchemaTypeDefinition');
11
10
  const handleBitwiseOperator = require('./operators/bitwise');
12
11
 
13
12
  /**
@@ -273,8 +272,7 @@ SchemaInt32.prototype.castForQuery = function($conditional, val, context) {
273
272
  */
274
273
 
275
274
  SchemaInt32.prototype.toJSONSchema = function toJSONSchema(options) {
276
- const isRequired = this.options.required && typeof this.options.required !== 'function';
277
- return createJSONSchemaTypeDefinition('number', 'int', options?.useBsonType, isRequired);
275
+ return this._createJSONSchemaTypeDefinition('number', 'int', options);
278
276
  };
279
277
 
280
278
  SchemaInt32.prototype.autoEncryptionType = function autoEncryptionType() {
package/lib/schema/map.js CHANGED
@@ -7,7 +7,6 @@
7
7
  const MongooseMap = require('../types/map');
8
8
  const SchemaMapOptions = require('../options/schemaMapOptions');
9
9
  const SchemaType = require('../schemaType');
10
- const createJSONSchemaTypeDefinition = require('../helpers/createJSONSchemaTypeDefinition');
11
10
  const MongooseError = require('../error/mongooseError');
12
11
  const Schema = require('../schema');
13
12
  const utils = require('../utils');
@@ -125,11 +124,9 @@ class SchemaMap extends SchemaType {
125
124
  */
126
125
 
127
126
  toJSONSchema(options) {
128
- const useBsonType = options?.useBsonType;
129
127
  const embeddedSchemaType = this.getEmbeddedSchemaType();
130
128
 
131
- const isRequired = this.options.required && typeof this.options.required !== 'function';
132
- const result = createJSONSchemaTypeDefinition('object', 'object', useBsonType, isRequired);
129
+ const result = this._createJSONSchemaTypeDefinition('object', 'object', options);
133
130
  result.additionalProperties = embeddedSchemaType.toJSONSchema(options);
134
131
 
135
132
  return result;
@@ -8,7 +8,6 @@ const MongooseError = require('../error/index');
8
8
  const SchemaNumberOptions = require('../options/schemaNumberOptions');
9
9
  const SchemaType = require('../schemaType');
10
10
  const castNumber = require('../cast/number');
11
- const createJSONSchemaTypeDefinition = require('../helpers/createJSONSchemaTypeDefinition');
12
11
  const handleBitwiseOperator = require('./operators/bitwise');
13
12
  const utils = require('../utils');
14
13
 
@@ -473,7 +472,7 @@ SchemaNumber.prototype.castForQuery = function($conditional, val, context) {
473
472
  if ($conditional != null) {
474
473
  handler = this.$conditionalHandlers[$conditional];
475
474
  if (!handler) {
476
- throw new CastError('number', val, this.path, null, this);
475
+ throw new MongooseError('Can\'t use ' + $conditional + ' with Number.');
477
476
  }
478
477
  return handler.call(this, val, context);
479
478
  }
@@ -499,8 +498,7 @@ SchemaNumber.prototype.castForQuery = function($conditional, val, context) {
499
498
  */
500
499
 
501
500
  SchemaNumber.prototype.toJSONSchema = function toJSONSchema(options) {
502
- const isRequired = (this.options.required && typeof this.options.required !== 'function') || this.path === '_id';
503
- return createJSONSchemaTypeDefinition('number', 'number', options?.useBsonType, isRequired);
501
+ return this._createJSONSchemaTypeDefinition('number', 'number', options);
504
502
  };
505
503
 
506
504
  /*!
@@ -7,7 +7,6 @@
7
7
  const SchemaObjectIdOptions = require('../options/schemaObjectIdOptions');
8
8
  const SchemaType = require('../schemaType');
9
9
  const castObjectId = require('../cast/objectid');
10
- const createJSONSchemaTypeDefinition = require('../helpers/createJSONSchemaTypeDefinition');
11
10
  const getConstructorName = require('../helpers/getConstructorName');
12
11
  const oid = require('../types/objectid');
13
12
  const isBsonType = require('../helpers/isBsonType');
@@ -318,8 +317,7 @@ function resetId(v) {
318
317
  */
319
318
 
320
319
  SchemaObjectId.prototype.toJSONSchema = function toJSONSchema(options) {
321
- const isRequired = (this.options.required && typeof this.options.required !== 'function') || this.path === '_id';
322
- return createJSONSchemaTypeDefinition('string', 'objectId', options?.useBsonType, isRequired);
320
+ return this._createJSONSchemaTypeDefinition('string', 'objectId', options);
323
321
  };
324
322
 
325
323
  SchemaObjectId.prototype.autoEncryptionType = function autoEncryptionType() {
@@ -8,7 +8,6 @@ const SchemaType = require('../schemaType');
8
8
  const MongooseError = require('../error/index');
9
9
  const SchemaStringOptions = require('../options/schemaStringOptions');
10
10
  const castString = require('../cast/string');
11
- const createJSONSchemaTypeDefinition = require('../helpers/createJSONSchemaTypeDefinition');
12
11
  const utils = require('../utils');
13
12
  const isBsonType = require('../helpers/isBsonType');
14
13
 
@@ -718,8 +717,7 @@ SchemaString.prototype.castForQuery = function($conditional, val, context) {
718
717
  */
719
718
 
720
719
  SchemaString.prototype.toJSONSchema = function toJSONSchema(options) {
721
- const isRequired = this.options.required && typeof this.options.required !== 'function';
722
- return createJSONSchemaTypeDefinition('string', 'string', options?.useBsonType, isRequired);
720
+ return this._createJSONSchemaTypeDefinition('string', 'string', options);
723
721
  };
724
722
 
725
723
  SchemaString.prototype.autoEncryptionType = function autoEncryptionType() {
@@ -12,7 +12,6 @@ const SchemaType = require('../schemaType');
12
12
  const applyDefaults = require('../helpers/document/applyDefaults');
13
13
  const $exists = require('./operators/exists');
14
14
  const castToNumber = require('./operators/helpers').castToNumber;
15
- const createJSONSchemaTypeDefinition = require('../helpers/createJSONSchemaTypeDefinition');
16
15
  const discriminator = require('../helpers/model/discriminator');
17
16
  const geospatial = require('./operators/geospatial');
18
17
  const getConstructor = require('../helpers/discriminator/getConstructor');
@@ -428,9 +427,8 @@ SchemaSubdocument.prototype.clone = function() {
428
427
  */
429
428
 
430
429
  SchemaSubdocument.prototype.toJSONSchema = function toJSONSchema(options) {
431
- const isRequired = this.options.required && typeof this.options.required !== 'function';
432
430
  return {
433
431
  ...this.schema.toJSONSchema(options),
434
- ...createJSONSchemaTypeDefinition('object', 'object', options?.useBsonType, isRequired)
432
+ ...this._createJSONSchemaTypeDefinition('object', 'object', options)
435
433
  };
436
434
  };
@@ -28,6 +28,7 @@ class Union extends SchemaType {
28
28
  throw new Error('Union schema type requires an array of types');
29
29
  }
30
30
  this.schemaTypes = options.of.map(obj => parentSchema.interpretAsType(key, obj, schemaOptions));
31
+ this.$isSchemaUnion = true;
31
32
  }
32
33
 
33
34
  cast(val, doc, init, prev, options) {
@@ -90,12 +91,61 @@ class Union extends SchemaType {
90
91
  throw lastError;
91
92
  }
92
93
 
94
+ async doValidate(value, scope, options) {
95
+ if (options && options.skipSchemaValidators) {
96
+ if (value != null && typeof value.validate === 'function') {
97
+ return value.validate();
98
+ }
99
+ return;
100
+ }
101
+
102
+ await super.doValidate(value, scope, options);
103
+ if (value != null && typeof value.validate === 'function') {
104
+ await value.validate();
105
+ }
106
+ }
107
+
108
+ doValidateSync(value, scope, options) {
109
+ if (!options || !options.skipSchemaValidators) {
110
+ const schemaTypeError = super.doValidateSync(value, scope, options);
111
+ if (schemaTypeError) {
112
+ return schemaTypeError;
113
+ }
114
+ }
115
+ if (value != null && typeof value.validateSync === 'function') {
116
+ return value.validateSync();
117
+ }
118
+ }
119
+
93
120
  clone() {
94
121
  const schematype = super.clone();
95
122
 
96
123
  schematype.schemaTypes = this.schemaTypes.map(schemaType => schemaType.clone());
97
124
  return schematype;
98
125
  }
126
+
127
+ /**
128
+ * Returns this schema type's representation in a JSON schema.
129
+ *
130
+ * @param {object} [options]
131
+ * @param {boolean} [options.useBsonType=false] If true, return a representation with `bsonType` for use with MongoDB's `$jsonSchema`.
132
+ * @returns {object} JSON schema properties
133
+ */
134
+ toJSONSchema(options) {
135
+ const isRequired = this.options.required && typeof this.options.required !== 'function';
136
+ const childOptions = { ...options, _overrideRequired: true };
137
+ const jsonSchemas = this.schemaTypes.map(schemaType => schemaType.toJSONSchema(childOptions));
138
+ if (isRequired) {
139
+ return { anyOf: jsonSchemas };
140
+ }
141
+
142
+ return {
143
+ anyOf: [
144
+ options?.useBsonType ? { bsonType: 'null' } : { type: 'null' },
145
+ ...jsonSchemas
146
+ ]
147
+ };
148
+ }
99
149
  }
100
150
 
101
151
  /**
@@ -7,7 +7,6 @@
7
7
  const SchemaType = require('../schemaType');
8
8
  const CastError = SchemaType.CastError;
9
9
  const castUUID = require('../cast/uuid');
10
- const createJSONSchemaTypeDefinition = require('../helpers/createJSONSchemaTypeDefinition');
11
10
  const utils = require('../utils');
12
11
  const handleBitwiseOperator = require('./operators/bitwise');
13
12
 
@@ -290,8 +289,7 @@ SchemaUUID.prototype.castForQuery = function($conditional, val, context) {
290
289
  */
291
290
 
292
291
  SchemaUUID.prototype.toJSONSchema = function toJSONSchema(options) {
293
- const isRequired = this.options.required && typeof this.options.required !== 'function';
294
- return createJSONSchemaTypeDefinition('string', 'binData', options?.useBsonType, isRequired);
292
+ return this._createJSONSchemaTypeDefinition('string', 'binData', options);
295
293
  };
296
294
 
297
295
  SchemaUUID.prototype.autoEncryptionType = function autoEncryptionType() {
package/lib/schema.js CHANGED
@@ -59,7 +59,7 @@ const numberRE = /^\d+$/;
59
59
  * - [autoIndex](https://mongoosejs.com/docs/guide.html#autoIndex): bool - defaults to null (which means use the connection's autoIndex option)
60
60
  * - [autoCreate](https://mongoosejs.com/docs/guide.html#autoCreate): bool - defaults to null (which means use the connection's autoCreate option)
61
61
  * - [bufferCommands](https://mongoosejs.com/docs/guide.html#bufferCommands): bool - defaults to true
62
- * - [bufferTimeoutMS](https://mongoosejs.com/docs/guide.html#bufferTimeoutMS): number - defaults to 10000 (10 seconds). If `bufferCommands` is enabled, the amount of time Mongoose will wait for connectivity to be restablished before erroring out.
62
+ * - [bufferTimeoutMS](https://mongoosejs.com/docs/guide.html#bufferTimeoutMS): number - defaults to 10000 (10 seconds). If `bufferCommands` is enabled, the amount of time Mongoose will wait for connectivity to be established before erroring out.
63
63
  * - [capped](https://mongoosejs.com/docs/guide.html#capped): bool | number | object - defaults to false
64
64
  * - [collection](https://mongoosejs.com/docs/guide.html#collection): string - no default
65
65
  * - [discriminatorKey](https://mongoosejs.com/docs/guide.html#discriminatorKey): string - defaults to `__t`
@@ -750,7 +750,7 @@ Schema.prototype.encryptionType = function encryptionType(encryptionType) {
750
750
  return this.options.encryptionType;
751
751
  }
752
752
  if (!(typeof encryptionType === 'string' || encryptionType === null)) {
753
- throw new MongooseError('invalid `encryptionType`: ${encryptionType}');
753
+ throw new MongooseError(`invalid \`encryptionType\`: ${encryptionType}`);
754
754
  }
755
755
  this.options.encryptionType = encryptionType;
756
756
  };
@@ -2253,7 +2253,7 @@ Schema.prototype.plugin = function(fn, opts) {
2253
2253
  *
2254
2254
  * NOTE: `Schema.method()` adds instance methods to the `Schema.methods` object. You can also add instance methods directly to the `Schema.methods` object as seen in the [guide](https://mongoosejs.com/docs/guide.html#methods)
2255
2255
  *
2256
- * @param {string|object} name The Method Name for a single function, or a Object of "string-function" pairs.
2256
+ * @param {string|object} name The Method Name for a single function, or an Object of "string-function" pairs.
2257
2257
  * @param {Function} [fn] The Function in a single-function definition.
2258
2258
  * @api public
2259
2259
  */
@@ -2298,7 +2298,7 @@ Schema.prototype.method = function(name, fn, options) {
2298
2298
  *
2299
2299
  * If a hash of name/fn pairs is passed as the only argument, each name/fn pair will be added as statics.
2300
2300
  *
2301
- * @param {string|object} name The Method Name for a single function, or a Object of "string-function" pairs.
2301
+ * @param {string|object} name The Method Name for a single function, or an Object of "string-function" pairs.
2302
2302
  * @param {Function} [fn] The Function in a single-function definition.
2303
2303
  * @api public
2304
2304
  * @see Statics https://mongoosejs.com/docs/guide.html#statics
@@ -3119,7 +3119,7 @@ Schema.prototype.toJSONSchema = function toJSONSchema(options) {
3119
3119
  for (const path of Object.keys(this.paths)) {
3120
3120
  const schemaType = this.paths[path];
3121
3121
 
3122
- // Skip Map embedded paths, maps will be handled seperately.
3122
+ // Skip Map embedded paths, maps will be handled separately.
3123
3123
  if (schemaType._presplitPath.indexOf('$*') !== -1) {
3124
3124
  continue;
3125
3125
  }
package/lib/schemaType.js CHANGED
@@ -99,11 +99,11 @@ function SchemaType(path, options, instance, parentSchema) {
99
99
  const index = this._index;
100
100
  if (typeof index === 'object' && index != null) {
101
101
  if (index.unique) {
102
- throw new Error('Path "' + this.path + '" may not have `index` ' +
102
+ throw new MongooseError('Path "' + this.path + '" may not have `index` ' +
103
103
  'set to false and `unique` set to true');
104
104
  }
105
105
  if (index.sparse) {
106
- throw new Error('Path "' + this.path + '" may not have `index` ' +
106
+ throw new MongooseError('Path "' + this.path + '" may not have `index` ' +
107
107
  'set to false and `sparse` set to true');
108
108
  }
109
109
  }
@@ -181,6 +181,39 @@ SchemaType.prototype.toJSON = function toJSON() {
181
181
  return res;
182
182
  };
183
183
 
184
+ /**
185
+ * Helper for creating `{ type: 'object' }` vs `{ bsonType: 'object' }` vs nullable variants.
186
+ *
187
+ * @param {string} type
188
+ * @param {string} bsonType
189
+ * @param {object} [options]
190
+ * @param {boolean} [options.useBsonType=false]
191
+ * @param {boolean} [options._defaultRequired=false]
192
+ * @param {boolean} [options._overrideRequired]
193
+ * @returns {object}
194
+ * @api private
195
+ */
196
+
197
+ SchemaType.prototype._createJSONSchemaTypeDefinition = function _createJSONSchemaTypeDefinition(type, bsonType, options) {
198
+ const useBsonType = options?.useBsonType;
199
+ const isRequired = options?._overrideRequired ??
200
+ (this.options.required == null ?
201
+ (options?._defaultRequired === true || this.path === '_id') :
202
+ this.options.required && typeof this.options.required !== 'function');
203
+
204
+ if (useBsonType) {
205
+ if (isRequired) {
206
+ return { bsonType };
207
+ }
208
+ return { bsonType: [bsonType, 'null'] };
209
+ }
210
+
211
+ if (isRequired) {
212
+ return { type };
213
+ }
214
+ return { type: [type, 'null'] };
215
+ };
216
+
184
217
  /**
185
218
  * The validators that Mongoose should run to validate properties at this SchemaType's path.
186
219
  *
@@ -317,7 +350,7 @@ SchemaType.prototype.castFunction = function castFunction(caster, message) {
317
350
  */
318
351
 
319
352
  SchemaType.prototype.cast = function cast() {
320
- throw new Error('Base SchemaType class does not implement a `cast()` function');
353
+ throw new MongooseError('Base SchemaType class does not implement a `cast()` function');
321
354
  };
322
355
 
323
356
  /**
@@ -380,10 +413,10 @@ SchemaType.get = function(getter) {
380
413
  * #### Example:
381
414
  *
382
415
  * // values are cast:
383
- * const schema = new Schema({ aNumber: { type: Number, default: 4.815162342 }})
416
+ * const schema = new Schema({ num: { type: Number, default: 4.815162342 }})
384
417
  * const M = db.model('M', schema)
385
418
  * const m = new M;
386
- * console.log(m.aNumber) // 4.815162342
419
+ * console.log(m.num) // 4.815162342
387
420
  *
388
421
  * // default unique objects for Mixed types:
389
422
  * const schema = new Schema({ mixed: Schema.Types.Mixed });
@@ -491,7 +524,7 @@ SchemaType.prototype.unique = function unique(value, message) {
491
524
  if (!value) {
492
525
  return;
493
526
  }
494
- throw new Error('Path "' + this.path + '" may not have `index` set to ' +
527
+ throw new MongooseError('Path "' + this.path + '" may not have `index` set to ' +
495
528
  'false and `unique` set to true');
496
529
  }
497
530
 
@@ -530,7 +563,7 @@ SchemaType.prototype.text = function(bool) {
530
563
  if (!bool) {
531
564
  return this;
532
565
  }
533
- throw new Error('Path "' + this.path + '" may not have `index` set to ' +
566
+ throw new MongooseError('Path "' + this.path + '" may not have `index` set to ' +
534
567
  'false and `text` set to true');
535
568
  }
536
569
 
@@ -567,7 +600,7 @@ SchemaType.prototype.sparse = function(bool) {
567
600
  if (!bool) {
568
601
  return this;
569
602
  }
570
- throw new Error('Path "' + this.path + '" may not have `index` set to ' +
603
+ throw new MongooseError('Path "' + this.path + '" may not have `index` set to ' +
571
604
  'false and `sparse` set to true');
572
605
  }
573
606
 
@@ -786,7 +819,7 @@ SchemaType.prototype.set = function(fn) {
786
819
  * // defining within the schema
787
820
  * const s = new Schema({ born: { type: Date, get: dob })
788
821
  *
789
- * // or by retreiving its SchemaType
822
+ * // or by retrieving its SchemaType
790
823
  * const s = new Schema({ born: Date })
791
824
  * s.path('born').get(dob)
792
825
  *
@@ -936,7 +969,7 @@ SchemaType.prototype.validateAll = function(validators) {
936
969
  * }
937
970
  * });
938
971
  *
939
- * You might use asynchronous validators to retreive other documents from the database to validate against or to meet other I/O bound validation needs.
972
+ * You might use asynchronous validators to retrieve other documents from the database to validate against or to meet other I/O bound validation needs.
940
973
  *
941
974
  * Validation occurs `pre('save')` or whenever you manually execute [document#validate](https://mongoosejs.com/docs/api/document.html#Document.prototype.validate()).
942
975
  *
@@ -1003,7 +1036,7 @@ SchemaType.prototype.validate = function(obj, message, type) {
1003
1036
  + arg
1004
1037
  + '. See https://mongoosejs.com/docs/api/schematype.html#SchemaType.prototype.validate()';
1005
1038
 
1006
- throw new Error(msg);
1039
+ throw new MongooseError(msg);
1007
1040
  }
1008
1041
  this.validate(arg.validator, arg);
1009
1042
  }
@@ -1704,7 +1737,7 @@ SchemaType.prototype.castForQuery = function($conditional, val, context) {
1704
1737
  if ($conditional != null) {
1705
1738
  handler = this.$conditionalHandlers[$conditional];
1706
1739
  if (!handler) {
1707
- throw new Error('Can\'t use ' + $conditional);
1740
+ throw new MongooseError('Can\'t use ' + $conditional);
1708
1741
  }
1709
1742
  return handler.call(this, val, context);
1710
1743
  }
@@ -1820,7 +1853,7 @@ SchemaType.prototype._duplicateKeyErrorMessage = null;
1820
1853
  */
1821
1854
 
1822
1855
  SchemaType.prototype.toJSONSchema = function toJSONSchema(_options) { // eslint-disable-line no-unused-vars
1823
- throw new Error(`Converting unsupported SchemaType to JSON Schema: ${this.instance} at path "${this.path}"`);
1856
+ throw new MongooseError(`Converting unsupported SchemaType to JSON Schema: ${this.instance} at path "${this.path}"`);
1824
1857
  };
1825
1858
 
1826
1859
  /**
@@ -572,7 +572,7 @@ const methods = {
572
572
  *
573
573
  * #### Note:
574
574
  *
575
- * _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._
575
+ * _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwriting any changes that happen between when you retrieved the object and when you save it._
576
576
  *
577
577
  * @param {...any} [args]
578
578
  * @api public
@@ -830,7 +830,7 @@ const methods = {
830
830
  *
831
831
  * #### Note:
832
832
  *
833
- * _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._
833
+ * _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwriting any changes that happen between when you retrieved the object and when you save it._
834
834
  *
835
835
  * @api public
836
836
  * @method shift
@@ -850,7 +850,7 @@ const methods = {
850
850
  *
851
851
  * #### Note:
852
852
  *
853
- * _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._
853
+ * _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwriting any changes that happen between when you retrieved the object and when you save it._
854
854
  *
855
855
  * @api public
856
856
  * @method sort
@@ -870,7 +870,7 @@ const methods = {
870
870
  *
871
871
  * #### Note:
872
872
  *
873
- * _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._
873
+ * _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwriting any changes that happen between when you retrieved the object and when you save it._
874
874
  *
875
875
  * @api public
876
876
  * @method splice
package/lib/utils.js CHANGED
@@ -119,6 +119,16 @@ exports.deepEqual = function deepEqual(a, b) {
119
119
  deepEqual(Array.from(a.values()), Array.from(b.values()));
120
120
  }
121
121
 
122
+ if (a instanceof Set || b instanceof Set) {
123
+ if (!(a instanceof Set) || !(b instanceof Set)) {
124
+ return false;
125
+ }
126
+ if (a.size !== b.size) {
127
+ return false;
128
+ }
129
+ return deepEqual(Array.from(a.values()), Array.from(b.values()));
130
+ }
131
+
122
132
  // Handle MongooseNumbers
123
133
  if (a instanceof Number && b instanceof Number) {
124
134
  return a.valueOf() === b.valueOf();
@@ -313,8 +323,8 @@ exports.merge = function merge(to, from, options, path) {
313
323
  // base schema has a given path as a single nested but discriminator schema
314
324
  // has the path as a document array, or vice versa (gh-9534)
315
325
  if (options.isDiscriminatorSchemaMerge &&
316
- (from[key].$isSingleNested && to[key].$isMongooseDocumentArray) ||
317
- (from[key].$isMongooseDocumentArray && to[key].$isSingleNested)) {
326
+ ((from[key].$isSingleNested && to[key].$isMongooseDocumentArray) ||
327
+ (from[key].$isMongooseDocumentArray && to[key].$isSingleNested))) {
318
328
  continue;
319
329
  } else if (from[key].instanceOfSchema) {
320
330
  if (to[key].instanceOfSchema) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "9.3.2",
4
+ "version": "9.4.0",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
@@ -37,11 +37,11 @@
37
37
  "acquit-require": "0.1.1",
38
38
  "ajv": "8.18.0",
39
39
  "c8": "11.0.0",
40
- "cheerio": "^1.2",
40
+ "cheerio": "1.2.0",
41
41
  "dox": "1.0.0",
42
42
  "eslint": "10.0.2",
43
43
  "eslint-plugin-mocha-no-only": "1.2.0",
44
- "express": "^4.19.2",
44
+ "express": "4.22.1",
45
45
  "fs-extra": "~11.3.0",
46
46
  "globals": "^17.4.0",
47
47
  "glob": "^13.0.6",
@@ -60,7 +60,7 @@
60
60
  "ncp": "^2.0.0",
61
61
  "pug": "3.0.3",
62
62
  "sinon": "21.0.1",
63
- "tstyche": "^6.2.0",
63
+ "tstyche": "^7.0.0-rc.0",
64
64
  "typescript": "5.9.3",
65
65
  "typescript-eslint": "^8.31.1",
66
66
  "uuid": "11.1.0"
@@ -80,7 +80,7 @@
80
80
  "docs:generate:sponsorData": "node ./scripts/loadSponsorData.js",
81
81
  "docs:test": "npm run docs:generate",
82
82
  "docs:view": "node ./scripts/static.js",
83
- "docs:prepare:publish:stable": "git checkout gh-pages && git merge master && npm run docs:generate",
83
+ "docs:prepare:publish:stable": "git checkout gh-pages && git merge master && env GENERATE_SEARCH=true npm run docs:generate",
84
84
  "docs:prepare:publish:5x": "git checkout 5.x && git merge 5.x && npm run docs:clean:stable && npm run docs:generate && npm run docs:copy:tmp && git checkout gh-pages && npm run docs:copy:tmp:5x",
85
85
  "docs:prepare:publish:6x": "git checkout 6.x && git merge 6.x && npm run docs:clean:stable && env DOCS_DEPLOY=true npm run docs:generate && mv ./docs/6.x ./tmp && git checkout gh-pages && npm run docs:copy:tmp:6x",
86
86
  "docs:prepare:publish:7x": "env DOCS_DEPLOY=true npm run docs:generate && git checkout gh-pages && rm -rf ./docs/7.x && mv ./tmp ./docs/7.x",
@@ -90,7 +90,7 @@
90
90
  "lint": "eslint .",
91
91
  "lint-js": "eslint . --ext .js --ext .cjs",
92
92
  "lint-ts": "eslint . --ext .ts",
93
- "lint-md": "markdownlint-cli2 \"**/*.md\" \"#node_modules\" \"#benchmarks\"",
93
+ "lint-md": "markdownlint-cli2 \"docs/**/*.md\" \"docs/*.md\" \"*.md\"",
94
94
  "release": "git pull && git push origin master --tags && npm publish",
95
95
  "release-5x": "git pull origin 5.x && git push origin 5.x && git push origin 5.x --tags && npm publish --tag 5x",
96
96
  "release-6x": "git pull origin 6.x && git push origin 6.x && git push origin 6.x --tags && npm publish --tag 6x",
@@ -32,7 +32,7 @@ declare module 'mongoose' {
32
32
  _id: T;
33
33
 
34
34
  /** Assert that a given path or paths is populated. Throws an error if not populated. */
35
- $assertPopulated<Paths = {}>(path: string | string[], values?: Partial<Paths>): Omit<this, keyof Paths> & Paths;
35
+ $assertPopulated<Paths = {}>(path: string | string[], values?: Partial<Paths>): PopulateDocumentResult<this, Paths, PopulatedPathsDocumentType<DocType, Paths>, DocType>;
36
36
 
37
37
  /** Clear the document's modified paths. */
38
38
  $clearModifiedPaths(): this;
@@ -171,6 +171,13 @@ declare module 'mongoose' {
171
171
  * Returns the changes that happened to the document
172
172
  * in the format that will be sent to MongoDB.
173
173
  */
174
+ $getChanges(): UpdateQuery<this>;
175
+
176
+ /**
177
+ * Returns the changes that happened to the document
178
+ * in the format that will be sent to MongoDB.
179
+ * @deprecated Use `$getChanges()` instead.
180
+ */
174
181
  getChanges(): UpdateQuery<this>;
175
182
 
176
183
  /** Signal that we desire an increment of this documents version. */
@@ -238,8 +245,8 @@ declare module 'mongoose' {
238
245
  $parent(): Document | undefined;
239
246
 
240
247
  /** Populates document references. */
241
- populate<Paths = {}>(path: string | PopulateOptions | (string | PopulateOptions)[]): Promise<MergeType<this, Paths>>;
242
- populate<Paths = {}>(path: string, select?: string | AnyObject, model?: Model<any>, match?: AnyObject, options?: PopulateOptions): Promise<MergeType<this, Paths>>;
248
+ populate<Paths = {}>(path: string | PopulateOptions | (string | PopulateOptions)[]): Promise<PopulateDocumentResult<this, Paths, PopulatedPathsDocumentType<DocType, Paths>, DocType>>;
249
+ populate<Paths = {}>(path: string, select?: string | AnyObject, model?: Model<any>, match?: AnyObject, options?: PopulateOptions): Promise<PopulateDocumentResult<this, Paths, PopulatedPathsDocumentType<DocType, Paths>, DocType>>;
243
250
 
244
251
  /** Gets _id(s) used during population of the given `path`. If the path was not populated, returns `undefined`. */
245
252
  populated(path: string): any;
@@ -262,11 +269,41 @@ declare module 'mongoose' {
262
269
  toBSON(): Require_id<DocType>;
263
270
 
264
271
  /** The return value of this method is used in calls to JSON.stringify(doc). */
272
+ toJSON<PopulatedRawDocType, DepopulatedRawDocType>(
273
+ this: PopulatedDocumentMarker<PopulatedRawDocType, DepopulatedRawDocType>,
274
+ options: { depopulate: true }
275
+ ): Default__v<Require_id<DepopulatedRawDocType>, TSchemaOptions>;
276
+ toJSON<PopulatedRawDocType, DepopulatedRawDocType, O extends ToObjectOptions & { depopulate: true }>(
277
+ this: PopulatedDocumentMarker<PopulatedRawDocType, DepopulatedRawDocType>,
278
+ options: O
279
+ ): ToObjectReturnType<DepopulatedRawDocType, TVirtuals, O, TSchemaOptions>;
280
+ toJSON<PopulatedRawDocType, O extends ToObjectOptions>(
281
+ this: PopulatedDocumentMarker<PopulatedRawDocType, any>,
282
+ options: O
283
+ ): ToObjectReturnType<PopulatedRawDocType, TVirtuals, O, TSchemaOptions>;
284
+ toJSON<PopulatedRawDocType>(
285
+ this: PopulatedDocumentMarker<PopulatedRawDocType, any>
286
+ ): Default__v<Require_id<PopulatedRawDocType>, TSchemaOptions>;
265
287
  toJSON<O extends ToObjectOptions>(options: O): ToObjectReturnType<DocType, TVirtuals, O, TSchemaOptions>;
266
288
  toJSON(options?: ToObjectOptions): Default__v<Require_id<DocType>, TSchemaOptions>;
267
289
  toJSON<T>(options?: ToObjectOptions): Default__v<Require_id<T>, ResolveSchemaOptions<TSchemaOptions>>;
268
290
 
269
291
  /** Converts this document into a plain-old JavaScript object ([POJO](https://masteringjs.io/tutorials/fundamentals/pojo)). */
292
+ toObject<PopulatedRawDocType, DepopulatedRawDocType>(
293
+ this: PopulatedDocumentMarker<PopulatedRawDocType, DepopulatedRawDocType>,
294
+ options: { depopulate: true }
295
+ ): Default__v<Require_id<DepopulatedRawDocType>, TSchemaOptions>;
296
+ toObject<PopulatedRawDocType, DepopulatedRawDocType, O extends ToObjectOptions & { depopulate: true }>(
297
+ this: PopulatedDocumentMarker<PopulatedRawDocType, DepopulatedRawDocType>,
298
+ options: O
299
+ ): ToObjectReturnType<DepopulatedRawDocType, TVirtuals, O, TSchemaOptions>;
300
+ toObject<PopulatedRawDocType, O extends ToObjectOptions>(
301
+ this: PopulatedDocumentMarker<PopulatedRawDocType, any>,
302
+ options: O
303
+ ): ToObjectReturnType<PopulatedRawDocType, TVirtuals, O, TSchemaOptions>;
304
+ toObject<PopulatedRawDocType>(
305
+ this: PopulatedDocumentMarker<PopulatedRawDocType, any>
306
+ ): Default__v<Require_id<PopulatedRawDocType>, TSchemaOptions>;
270
307
  toObject<O extends ToObjectOptions>(options: O): ToObjectReturnType<DocType, TVirtuals, O, TSchemaOptions>;
271
308
  toObject(options?: ToObjectOptions): Default__v<Require_id<DocType>, TSchemaOptions>;
272
309
  toObject<T>(options?: ToObjectOptions): Default__v<Require_id<T>, ResolveSchemaOptions<TSchemaOptions>>;
package/types/index.d.ts CHANGED
@@ -177,13 +177,25 @@ declare module 'mongoose' {
177
177
  HydratedDocPathsType,
178
178
  any,
179
179
  TOverrides extends Record<string, never> ?
180
- Document<unknown, TQueryHelpers, RawDocType, TVirtuals, TSchemaOptions> & Default__v<Require_id<HydratedDocPathsType>, TSchemaOptions> & AddDefaultId<HydratedDocPathsType, {}, TSchemaOptions> :
180
+ Document<unknown, TQueryHelpers, RawDocType, TVirtuals, TSchemaOptions> &
181
+ Default__v<Require_id<HydratedDocPathsType>, TSchemaOptions> &
182
+ IfEquals<
183
+ TVirtuals,
184
+ {},
185
+ AddDefaultId<HydratedDocPathsType, {}, TSchemaOptions>,
186
+ TVirtuals
187
+ > :
181
188
  IfAny<
182
189
  TOverrides,
183
190
  Document<unknown, TQueryHelpers, RawDocType, TVirtuals, TSchemaOptions> & Default__v<Require_id<HydratedDocPathsType>, TSchemaOptions>,
184
191
  Document<unknown, TQueryHelpers, RawDocType, TVirtuals, TSchemaOptions> & MergeType<
185
192
  Default__v<Require_id<HydratedDocPathsType>, TSchemaOptions>,
186
- TOverrides
193
+ IfEquals<
194
+ TOverrides,
195
+ {},
196
+ TOverrides,
197
+ TOverrides & AddDefaultId<HydratedDocPathsType, TVirtuals, TSchemaOptions>
198
+ >
187
199
  >
188
200
  >
189
201
  >;
@@ -1094,6 +1106,9 @@ declare module 'mongoose' {
1094
1106
  // Handle DocumentArray - recurse into items
1095
1107
  : T extends Types.DocumentArray<infer ItemType>
1096
1108
  ? Types.DocumentArray<ApplyFlattenTransforms<ItemType, O>>
1109
+ // Handle plain arrays - recurse into items
1110
+ : T extends Array<infer ItemType>
1111
+ ? ApplyFlattenTransforms<ItemType, O>[]
1097
1112
  // Handle Subdocument - recurse into subdoc type
1098
1113
  : T extends Types.Subdocument<unknown, unknown, infer SubdocType>
1099
1114
  ? HydratedSingleSubdocument<ApplyFlattenTransforms<SubdocType, O>>