mongoose 9.0.1 → 9.1.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 (93) hide show
  1. package/lib/aggregate.js +1 -1
  2. package/lib/cast/string.js +1 -1
  3. package/lib/cast.js +7 -15
  4. package/lib/collection.js +2 -2
  5. package/lib/connection.js +20 -14
  6. package/lib/cursor/changeStream.js +5 -5
  7. package/lib/document.js +126 -79
  8. package/lib/drivers/node-mongodb-native/collection.js +33 -126
  9. package/lib/drivers/node-mongodb-native/connection.js +8 -23
  10. package/lib/error/cast.js +1 -1
  11. package/lib/helpers/aggregate/prepareDiscriminatorPipeline.js +4 -4
  12. package/lib/helpers/clone.js +8 -8
  13. package/lib/helpers/common.js +4 -4
  14. package/lib/helpers/cursor/eachAsync.js +1 -1
  15. package/lib/helpers/discriminator/getConstructor.js +1 -1
  16. package/lib/helpers/discriminator/getSchemaDiscriminatorByValue.js +1 -1
  17. package/lib/helpers/discriminator/mergeDiscriminatorSchema.js +2 -2
  18. package/lib/helpers/document/applyDefaults.js +1 -1
  19. package/lib/helpers/document/applyTimestamps.js +2 -1
  20. package/lib/helpers/document/applyVirtuals.js +4 -3
  21. package/lib/helpers/document/cleanModifiedSubpaths.js +1 -1
  22. package/lib/helpers/document/compile.js +4 -4
  23. package/lib/helpers/document/getDeepestSubdocumentForPath.js +1 -1
  24. package/lib/helpers/indexes/decorateDiscriminatorIndexOptions.js +1 -1
  25. package/lib/helpers/indexes/getRelatedIndexes.js +3 -3
  26. package/lib/helpers/model/castBulkWrite.js +5 -9
  27. package/lib/helpers/model/discriminator.js +1 -1
  28. package/lib/helpers/populate/assignRawDocsToIdStructure.js +1 -1
  29. package/lib/helpers/populate/assignVals.js +4 -4
  30. package/lib/helpers/populate/getModelsMapForPopulate.js +25 -23
  31. package/lib/helpers/populate/getSchemaTypes.js +6 -7
  32. package/lib/helpers/printJestWarning.js +1 -1
  33. package/lib/helpers/processConnectionOptions.js +1 -1
  34. package/lib/helpers/query/castUpdate.js +12 -12
  35. package/lib/helpers/query/getEmbeddedDiscriminatorPath.js +2 -2
  36. package/lib/helpers/query/handleImmutable.js +2 -2
  37. package/lib/helpers/query/sanitizeFilter.js +1 -1
  38. package/lib/helpers/schema/applyPlugins.js +1 -1
  39. package/lib/helpers/schema/applyReadConcern.js +1 -1
  40. package/lib/helpers/schema/applyWriteConcern.js +4 -2
  41. package/lib/helpers/schema/getIndexes.js +3 -3
  42. package/lib/helpers/schema/getSubdocumentStrictValue.js +1 -1
  43. package/lib/helpers/schema/handleIdOption.js +1 -1
  44. package/lib/helpers/schema/idGetter.js +1 -1
  45. package/lib/helpers/schematype/handleImmutable.js +1 -1
  46. package/lib/helpers/setDefaultsOnInsert.js +2 -5
  47. package/lib/helpers/timestamps/setDocumentTimestamps.js +2 -2
  48. package/lib/helpers/timestamps/setupTimestamps.js +2 -2
  49. package/lib/helpers/update/applyTimestampsToUpdate.js +10 -9
  50. package/lib/helpers/update/castArrayFilters.js +4 -4
  51. package/lib/helpers/update/decorateUpdateWithVersionKey.js +1 -1
  52. package/lib/helpers/updateValidators.js +4 -4
  53. package/lib/model.js +42 -48
  54. package/lib/mongoose.js +5 -5
  55. package/lib/options/virtualOptions.js +1 -1
  56. package/lib/plugins/saveSubdocs.js +2 -2
  57. package/lib/plugins/trackTransaction.js +3 -4
  58. package/lib/query.js +62 -59
  59. package/lib/queryHelpers.js +9 -12
  60. package/lib/schema/array.js +10 -12
  61. package/lib/schema/buffer.js +6 -6
  62. package/lib/schema/documentArray.js +15 -23
  63. package/lib/schema/documentArrayElement.js +3 -3
  64. package/lib/schema/map.js +1 -1
  65. package/lib/schema/mixed.js +2 -2
  66. package/lib/schema/number.js +22 -4
  67. package/lib/schema/objectId.js +1 -1
  68. package/lib/schema/operators/exists.js +1 -1
  69. package/lib/schema/operators/geospatial.js +1 -1
  70. package/lib/schema/string.js +2 -2
  71. package/lib/schema/subdocument.js +9 -12
  72. package/lib/schema/union.js +1 -1
  73. package/lib/schema.js +27 -28
  74. package/lib/schemaType.js +11 -11
  75. package/lib/types/array/index.js +2 -2
  76. package/lib/types/array/methods/index.js +38 -8
  77. package/lib/types/arraySubdocument.js +12 -2
  78. package/lib/types/buffer.js +1 -1
  79. package/lib/types/documentArray/index.js +2 -2
  80. package/lib/types/documentArray/methods/index.js +5 -5
  81. package/lib/types/map.js +8 -8
  82. package/lib/types/subdocument.js +15 -5
  83. package/lib/utils.js +23 -7
  84. package/package.json +3 -2
  85. package/types/index.d.ts +26 -9
  86. package/types/inferrawdoctype.d.ts +9 -3
  87. package/types/inferschematype.d.ts +20 -27
  88. package/types/middlewares.d.ts +11 -0
  89. package/types/models.d.ts +15 -5
  90. package/types/query.d.ts +1 -1
  91. package/types/schemaoptions.d.ts +4 -2
  92. package/types/utility.d.ts +1 -1
  93. package/types/virtuals.d.ts +3 -3
@@ -73,7 +73,7 @@ for (const i in EventEmitter.prototype) {
73
73
  ArraySubdocument.prototype.$setIndex = function(index) {
74
74
  this.__index = index;
75
75
 
76
- if (this.$__ != null && this.$__.validationError != null) {
76
+ if (this.$__?.validationError != null) {
77
77
  const keys = Object.keys(this.$__.validationError.errors);
78
78
  for (const key of keys) {
79
79
  this.invalidate(key, this.$__.validationError.errors[key]);
@@ -145,7 +145,7 @@ ArraySubdocument.prototype.$__fullPath = function(path, skipIndex) {
145
145
  */
146
146
 
147
147
  ArraySubdocument.prototype.$__pathRelativeToParent = function(path, skipIndex) {
148
- if (this.__index == null || (!this.__parentArray || !this.__parentArray.$path)) {
148
+ if (this.__index == null || !this.__parentArray?.$path) {
149
149
  return null;
150
150
  }
151
151
  if (skipIndex) {
@@ -169,6 +169,16 @@ ArraySubdocument.prototype.$parent = function() {
169
169
  return this[documentArrayParent];
170
170
  };
171
171
 
172
+ /*!
173
+ * Sets this sub-documents parent document.
174
+ *
175
+ * @api private
176
+ */
177
+
178
+ ArraySubdocument.prototype.$__setParent = function $__setParent(parent) {
179
+ this[documentArrayParent] = parent;
180
+ };
181
+
172
182
  /**
173
183
  * Returns this subdocument's parent array.
174
184
  *
@@ -131,7 +131,7 @@ MongooseBuffer.mixin = {
131
131
  copy: function(target) {
132
132
  const ret = Buffer.prototype.copy.apply(this, arguments);
133
133
 
134
- if (target && target.isMongooseBuffer) {
134
+ if (target?.isMongooseBuffer) {
135
135
  target._markModified();
136
136
  }
137
137
 
@@ -50,7 +50,7 @@ function MongooseDocumentArray(values, path, doc, schematype) {
50
50
  internals[arrayPathSymbol] = path;
51
51
  internals.__array = __array;
52
52
 
53
- if (doc && doc.$__) {
53
+ if (doc?.$__) {
54
54
  internals[arrayParentSymbol] = doc;
55
55
  internals[arraySchemaSymbol] = doc.$__schema.path(path);
56
56
 
@@ -79,7 +79,7 @@ function MongooseDocumentArray(values, path, doc, schematype) {
79
79
  if (Object.hasOwn(DocumentArrayMethods, prop)) {
80
80
  return DocumentArrayMethods[prop];
81
81
  }
82
- if (schematype && schematype.virtuals && Object.hasOwn(schematype.virtuals, prop)) {
82
+ if (schematype?.virtuals && Object.hasOwn(schematype.virtuals, prop)) {
83
83
  return schematype.virtuals[prop].applyGetters(undefined, target);
84
84
  }
85
85
  if (Object.hasOwn(ArrayMethods, prop)) {
@@ -25,7 +25,7 @@ const methods = {
25
25
 
26
26
  toString() {
27
27
  return _baseToString.call(this.__array.map(subdoc => {
28
- if (subdoc != null && subdoc.$__ != null) {
28
+ if (subdoc?.$__ != null) {
29
29
  return subdoc.toString();
30
30
  }
31
31
  return subdoc;
@@ -65,7 +65,7 @@ const methods = {
65
65
  value instanceof Constructor;
66
66
  if (isInstance ||
67
67
  // Hack re: #5001, see #5005
68
- (value && value.constructor && value.constructor.baseCasterConstructor === Constructor)) {
68
+ value?.constructor?.baseCasterConstructor === Constructor) {
69
69
  if (!(value[documentArrayParent] && value.__parentArray)) {
70
70
  // value may have been created using array.create()
71
71
  value[documentArrayParent] = this[arrayParentSymbol];
@@ -75,7 +75,7 @@ const methods = {
75
75
  return value;
76
76
  }
77
77
 
78
- if (value === undefined || value === null) {
78
+ if (value == null) {
79
79
  return null;
80
80
  }
81
81
 
@@ -133,9 +133,9 @@ const methods = {
133
133
  const schemaType = this[arraySchemaSymbol];
134
134
  let idSchemaType = null;
135
135
 
136
- if (schemaType && schemaType.schema) {
136
+ if (schemaType?.schema) {
137
137
  idSchemaType = schemaType.schema.path('_id');
138
- } else if (schemaType && schemaType.casterConstructor && schemaType.casterConstructor.schema) {
138
+ } else if (schemaType?.casterConstructor?.schema) {
139
139
  idSchemaType = schemaType.casterConstructor.schema.path('_id');
140
140
  }
141
141
 
package/lib/types/map.js CHANGED
@@ -22,7 +22,7 @@ class MongooseMap extends Map {
22
22
  v = Object.keys(v).reduce((arr, key) => arr.concat([[key, v[key]]]), []);
23
23
  }
24
24
  super(v);
25
- this.$__parent = doc != null && doc.$__ != null ? doc : null;
25
+ this.$__parent = doc?.$__ != null ? doc : null;
26
26
 
27
27
  // Calculate the full path from the root document
28
28
  // Priority: parent.$basePath (from subdoc) > options.path (from parent map/structure) > path (schema path)
@@ -50,7 +50,7 @@ class MongooseMap extends Map {
50
50
 
51
51
  super.set(key, value);
52
52
 
53
- if (value != null && value.$isSingleNested) {
53
+ if (value?.$isSingleNested) {
54
54
  value.$basePath = this.$__path + '.' + key;
55
55
  // Store the path relative to parent subdoc for efficient markModified()
56
56
  if (this.$__pathRelativeToParent != null) {
@@ -129,7 +129,7 @@ class MongooseMap extends Map {
129
129
 
130
130
  let _fullPath;
131
131
  const parent = this.$__parent;
132
- const populated = parent != null && parent.$__ && parent.$__.populated ?
132
+ const populated = parent?.$__?.populated ?
133
133
  parent.$populated(fullPath.call(this), true) || parent.$populated(this.$__path, true) :
134
134
  null;
135
135
  const priorVal = this.get(key);
@@ -177,7 +177,7 @@ class MongooseMap extends Map {
177
177
  options
178
178
  );
179
179
  } catch (error) {
180
- if (this.$__parent != null && this.$__parent.$__ != null) {
180
+ if (this.$__parent?.$__ != null) {
181
181
  this.$__parent.invalidate(fullPath.call(this), error);
182
182
  return;
183
183
  }
@@ -189,7 +189,7 @@ class MongooseMap extends Map {
189
189
 
190
190
  // Set relative path on subdocuments to avoid string operations in markModified()
191
191
  // The path should be relative to the parent subdocument (if any), not just the key
192
- if (value != null && value.$isSingleNested) {
192
+ if (value?.$isSingleNested) {
193
193
  if (this.$__pathRelativeToParent != null) {
194
194
  // Map's parent is a subdocument, store path relative to that subdoc (e.g., 'items.i2')
195
195
  value.$pathRelativeToParent = this.$__pathRelativeToParent + '.' + key;
@@ -199,7 +199,7 @@ class MongooseMap extends Map {
199
199
  }
200
200
  }
201
201
 
202
- if (parent != null && parent.$__ != null && !deepEqual(value, priorVal)) {
202
+ if (parent?.$__ != null && !deepEqual(value, priorVal)) {
203
203
  // Optimization: if parent is a subdocument, use precalculated relative path
204
204
  // to avoid building a full path just to strip the parent's prefix
205
205
  let pathToMark;
@@ -275,7 +275,7 @@ class MongooseMap extends Map {
275
275
  }
276
276
 
277
277
  toObject(options) {
278
- if (options && options.flattenMaps) {
278
+ if (options?.flattenMaps) {
279
279
  const ret = {};
280
280
  const keys = this.keys();
281
281
  for (const key of keys) {
@@ -308,7 +308,7 @@ class MongooseMap extends Map {
308
308
  */
309
309
 
310
310
  toJSON(options) {
311
- if (typeof (options && options.flattenMaps) === 'boolean' ? options.flattenMaps : true) {
311
+ if (typeof options?.flattenMaps === 'boolean' ? options.flattenMaps : true) {
312
312
  const ret = {};
313
313
  const keys = this.keys();
314
314
  for (const key of keys) {
@@ -23,10 +23,10 @@ function Subdocument(value, fields, parent, options) {
23
23
  }
24
24
  options = Object.assign(parentOptions, options);
25
25
  }
26
- if (options != null && options.path != null) {
26
+ if (options?.path != null) {
27
27
  this.$basePath = options.path;
28
28
  }
29
- if (options != null && options.pathRelativeToParent != null) {
29
+ if (options?.pathRelativeToParent != null) {
30
30
  this.$pathRelativeToParent = options.pathRelativeToParent;
31
31
  }
32
32
 
@@ -35,7 +35,7 @@ function Subdocument(value, fields, parent, options) {
35
35
  // subdocuments use relative paths (relative to the parent document) to track changes.
36
36
  // This avoids the subdocument's fields receiving the subdocument's path as options.path.
37
37
  let documentOptions = options;
38
- if (options != null && options.path != null) {
38
+ if (options?.path != null) {
39
39
  documentOptions = Object.assign({}, options);
40
40
  delete documentOptions.path;
41
41
  }
@@ -356,6 +356,16 @@ Subdocument.prototype.parent = function() {
356
356
 
357
357
  Subdocument.prototype.$parent = Subdocument.prototype.parent;
358
358
 
359
+ /*!
360
+ * Sets this sub-documents parent document.
361
+ *
362
+ * @api private
363
+ */
364
+
365
+ Subdocument.prototype.$__setParent = function $__setParent(parent) {
366
+ this.$__parent = parent;
367
+ };
368
+
359
369
  /**
360
370
  * ignore
361
371
  * @method $__removeFromParent
@@ -378,7 +388,7 @@ Subdocument.prototype.deleteOne = function deleteOne(options) {
378
388
  registerRemoveListener(this);
379
389
 
380
390
  // If removing entire doc, no need to remove subdoc
381
- if (!options || !options.noop) {
391
+ if (!options?.noop) {
382
392
  this.$__removeFromParent();
383
393
 
384
394
  const owner = this.ownerDocument();
@@ -422,7 +432,7 @@ Subdocument.prototype.$toObject = function $toObject(options, json) {
422
432
 
423
433
  // If `$toObject()` was called recursively, respect the minimize option, including schematype level minimize.
424
434
  // If minimize is set, then we can minimize out the whole object.
425
- if (Object.keys(ret).length === 0 && options?._calledWithOptions != null) {
435
+ if (utils.hasOwnKeys(ret) === false && options?._calledWithOptions != null) {
426
436
  const minimize = options._calledWithOptions?.minimize ?? this?.$__schemaTypeOptions?.minimize ?? options.minimize;
427
437
  if (minimize && !this.constructor.$__required) {
428
438
  return undefined;
package/lib/utils.js CHANGED
@@ -436,10 +436,26 @@ exports.isNativeObject = function(arg) {
436
436
  * @param {Any} val
437
437
  */
438
438
 
439
- exports.isEmptyObject = function(val) {
440
- return val != null &&
441
- typeof val === 'object' &&
442
- Object.keys(val).length === 0;
439
+ exports.isEmptyObject = function isEmptyObject(val) {
440
+ if (val == null || typeof val !== 'object') {
441
+ return false;
442
+ }
443
+ return exports.hasOwnKeys(val) === false;
444
+ };
445
+
446
+ /**
447
+ * Determines if `obj` has any own keys. Assumes obj is already an object.
448
+ * Faster than Object.keys(obj).length > 0.
449
+ * @param {Object} obj
450
+ */
451
+
452
+ exports.hasOwnKeys = function hasOwnKeys(obj) {
453
+ for (const key in obj) {
454
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
455
+ return true;
456
+ }
457
+ }
458
+ return false;
443
459
  };
444
460
 
445
461
  /**
@@ -665,7 +681,7 @@ function getValueLookup(obj, part) {
665
681
  return obj;
666
682
  }
667
683
  let _from = obj?._doc || obj;
668
- if (_from != null && _from.isMongooseArrayProxy) {
684
+ if (_from?.isMongooseArrayProxy) {
669
685
  _from = _from.__array;
670
686
  }
671
687
  return _from instanceof Map ?
@@ -720,7 +736,7 @@ exports.object.vals = function vals(o) {
720
736
  */
721
737
 
722
738
  exports.isNullOrUndefined = function(val) {
723
- return val === null || val === undefined;
739
+ return val == null;
724
740
  };
725
741
 
726
742
  /*!
@@ -919,7 +935,7 @@ exports.mergeClone = function(to, fromObj) {
919
935
  });
920
936
  } else {
921
937
  let val = fromObj[key];
922
- if (val != null && val.valueOf && !(val instanceof Date)) {
938
+ if (val?.valueOf && !(val instanceof Date)) {
923
939
  val = val.valueOf();
924
940
  }
925
941
  if (exports.isObject(val)) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mongoose",
3
3
  "description": "Mongoose MongoDB ODM",
4
- "version": "9.0.1",
4
+ "version": "9.1.0",
5
5
  "author": "Guillermo Rauch <guillermo@learnboost.com>",
6
6
  "keywords": [
7
7
  "mongodb",
@@ -50,7 +50,7 @@
50
50
  "mkdirp": "^3.0.1",
51
51
  "mocha": "11.7.5",
52
52
  "moment": "2.30.1",
53
- "mongodb-memory-server": "10.3.0",
53
+ "mongodb-memory-server": "11.0.0",
54
54
  "mongodb-runner": "^6.0.0",
55
55
  "mongodb-client-encryption": "~7.0",
56
56
  "ncp": "^2.0.0",
@@ -102,6 +102,7 @@
102
102
  "tdd": "mocha --watch --inspect --recursive ./test/*.test.js --watch-files lib/**/*.js test/**/*.js",
103
103
  "test-coverage": "nyc --reporter=html --reporter=text npm test",
104
104
  "ts-benchmark": "cd ./benchmarks/typescript/simple && npm install && npm run benchmark | node ../../../scripts/tsc-diagnostics-check",
105
+ "ts-benchmark:local": "node ./scripts/create-tarball && cd ./benchmarks/typescript/simple && rm -rf ./node_modules && npm install && npm run benchmark | node ../../../scripts/tsc-diagnostics-check",
105
106
  "attest-benchmark": "node ./benchmarks/typescript/infer.bench.mts"
106
107
  },
107
108
  "main": "./index.js",
package/types/index.d.ts CHANGED
@@ -177,7 +177,7 @@ 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> :
180
+ Document<unknown, TQueryHelpers, RawDocType, TVirtuals, TSchemaOptions> & Default__v<Require_id<HydratedDocPathsType>, TSchemaOptions> & AddDefaultId<HydratedDocPathsType, {}, TSchemaOptions> :
181
181
  IfAny<
182
182
  TOverrides,
183
183
  Document<unknown, TQueryHelpers, RawDocType, TVirtuals, TSchemaOptions> & Default__v<Require_id<HydratedDocPathsType>, TSchemaOptions>,
@@ -345,7 +345,8 @@ declare module 'mongoose' {
345
345
  TSchemaOptions extends { methods: infer M } ? M : {},
346
346
  TSchemaOptions extends { query: any } ? TSchemaOptions['query'] : {},
347
347
  TSchemaOptions extends { virtuals: any } ? TSchemaOptions['virtuals'] : {},
348
- RawDocType
348
+ RawDocType,
349
+ ResolveSchemaOptions<TSchemaOptions>
349
350
  >
350
351
  >(def: TSchemaDefinition): Schema<
351
352
  RawDocType,
@@ -374,7 +375,14 @@ declare module 'mongoose' {
374
375
  InferRawDocType<TSchemaDefinition, ResolveSchemaOptions<TSchemaOptions>>,
375
376
  ResolveSchemaOptions<TSchemaOptions>
376
377
  >,
377
- THydratedDocumentType extends AnyObject = HydratedDocument<InferHydratedDocType<TSchemaDefinition, ResolveSchemaOptions<TSchemaOptions>>>
378
+ THydratedDocumentType extends AnyObject = HydratedDocument<
379
+ InferHydratedDocType<TSchemaDefinition, ResolveSchemaOptions<TSchemaOptions>>,
380
+ TSchemaOptions extends { methods: infer M } ? M : {},
381
+ TSchemaOptions extends { query: any } ? TSchemaOptions['query'] : {},
382
+ TSchemaOptions extends { virtuals: any } ? TSchemaOptions['virtuals'] : {},
383
+ RawDocType,
384
+ ResolveSchemaOptions<TSchemaOptions>
385
+ >
378
386
  >(def: TSchemaDefinition, options: TSchemaOptions): Schema<
379
387
  RawDocType,
380
388
  Model<RawDocType, any, any, any>,
@@ -552,9 +560,14 @@ declare module 'mongoose' {
552
560
  pre<T = never>(method: MongooseDistinctDocumentMiddleware | MongooseDistinctDocumentMiddleware[] | RegExp, options: SchemaPreOptions & { document: false, query: boolean }, fn: PreMiddlewareFunction<T>): this;
553
561
  // this = Union of Document and Query, could be called with any of them
554
562
  pre<T = THydratedDocumentType | Query<any, any>>(
555
- method: MongooseQueryAndDocumentMiddleware | MongooseQueryAndDocumentMiddleware[] | RegExp,
563
+ method: 'updateOne' | RegExp,
564
+ options: SchemaPreOptions & { document: true, query: true },
565
+ fn: PreUpdateOneMiddlewareFunction<T>
566
+ ): this;
567
+ pre<T = THydratedDocumentType | Query<any, any>>(
568
+ method: 'deleteOne' | RegExp,
556
569
  options: SchemaPreOptions & { document: true, query: true },
557
- fn: PreMiddlewareFunction<T>
570
+ fn: PreDeleteOneMiddlewareFunction<T>
558
571
  ): this;
559
572
  // this = Document
560
573
  pre<T = THydratedDocumentType>(method: 'save', fn: PreSaveMiddlewareFunction<T>): this;
@@ -562,9 +575,14 @@ declare module 'mongoose' {
562
575
  pre<T = THydratedDocumentType>(method: MongooseDistinctDocumentMiddleware|MongooseDistinctDocumentMiddleware[], fn: PreMiddlewareFunction<T>): this;
563
576
  pre<T = THydratedDocumentType>(method: MongooseDistinctDocumentMiddleware|MongooseDistinctDocumentMiddleware[], options: SchemaPreOptions, fn: PreMiddlewareFunction<T>): this;
564
577
  pre<T = THydratedDocumentType>(
565
- method: MongooseQueryAndDocumentMiddleware | MongooseQueryAndDocumentMiddleware[] | RegExp,
578
+ method: 'updateOne' | RegExp,
579
+ options: SchemaPreOptions & { document: true },
580
+ fn: PreUpdateOneMiddlewareFunction<T>
581
+ ): this;
582
+ pre<T = THydratedDocumentType>(
583
+ method: 'deleteOne' | RegExp,
566
584
  options: SchemaPreOptions & { document: true },
567
- fn: PreMiddlewareFunction<T>
585
+ fn: PreDeleteOneMiddlewareFunction<T>
568
586
  ): this;
569
587
  pre<T = THydratedDocumentType>(method: MongooseQueryOrDocumentMiddleware | MongooseQueryOrDocumentMiddleware[] | RegExp, options: SchemaPreOptions & { document: true, query: false }, fn: PreMiddlewareFunction<T>): this;
570
588
  // this = Query
@@ -623,8 +641,7 @@ declare module 'mongoose' {
623
641
 
624
642
  /** Adds static "class" methods to Models compiled from this schema. */
625
643
  static<K extends keyof TStaticMethods>(name: K, fn: TStaticMethods[K]): this;
626
- static(obj: { [F in keyof TStaticMethods]: TStaticMethods[F] }): this;
627
- static(obj: { [F in keyof TStaticMethods]: TStaticMethods[F] } & { [name: string]: (this: TModelType, ...args: any[]) => any }): this;
644
+ static(obj: Partial<TStaticMethods> & { [name: string]: (this: TModelType, ...args: any[]) => any }): this;
628
645
  static(name: string, fn: (this: TModelType, ...args: any[]) => any): this;
629
646
 
630
647
  /** Object of currently defined statics on this schema. */
@@ -12,18 +12,24 @@ declare module 'mongoose' {
12
12
  ? ObtainSchemaGeneric<TSchema, 'EnforcedDocType'>
13
13
  : FlattenMaps<SubdocsToPOJOs<ObtainSchemaGeneric<TSchema, 'DocType'>>>;
14
14
 
15
- export type InferRawDocType<
15
+ export type InferRawDocTypeWithout_id<
16
16
  SchemaDefinition,
17
17
  TSchemaOptions extends Record<any, any> = DefaultSchemaOptions,
18
18
  TTransformOptions = { bufferToBinary: false }
19
- > = Require_id<ApplySchemaOptions<{
19
+ > = ApplySchemaOptions<{
20
20
  [
21
21
  K in keyof (RequiredPaths<SchemaDefinition, TSchemaOptions['typeKey']> &
22
22
  OptionalPaths<SchemaDefinition, TSchemaOptions['typeKey']>)
23
23
  ]: IsPathRequired<SchemaDefinition[K], TSchemaOptions['typeKey']> extends true
24
24
  ? ObtainRawDocumentPathType<SchemaDefinition[K], TSchemaOptions['typeKey'], TTransformOptions>
25
25
  : ObtainRawDocumentPathType<SchemaDefinition[K], TSchemaOptions['typeKey'], TTransformOptions> | null;
26
- }, TSchemaOptions>>;
26
+ }, TSchemaOptions>;
27
+
28
+ export type InferRawDocType<
29
+ SchemaDefinition,
30
+ TSchemaOptions extends Record<any, any> = DefaultSchemaOptions,
31
+ TTransformOptions = { bufferToBinary: false }
32
+ > = Require_id<InferRawDocTypeWithout_id<SchemaDefinition, TSchemaOptions, TTransformOptions>>;
27
33
 
28
34
  /**
29
35
  * @summary Allows users to optionally choose their own type for a schema field for stronger typing.
@@ -100,10 +100,10 @@ declare module 'mongoose' {
100
100
  {
101
101
  EnforcedDocType: EnforcedDocType;
102
102
  M: M;
103
- TInstanceMethods: TInstanceMethods;
104
- TQueryHelpers: TQueryHelpers;
105
- TVirtuals: AddDefaultId<DocType, TVirtuals, TSchemaOptions>;
106
- TStaticMethods: TStaticMethods;
103
+ TInstanceMethods: IfEquals<TInstanceMethods, {}, TSchemaOptions extends { methods: infer M } ? M : {}, TInstanceMethods>;
104
+ TQueryHelpers: IfEquals<TQueryHelpers, {}, TSchemaOptions extends { query: infer Q } ? Q : {}, TQueryHelpers>;
105
+ TVirtuals: AddDefaultId<DocType, IfEquals<TVirtuals, {}, TSchemaOptions extends { virtuals: infer V } ? V : {}, TVirtuals>, TSchemaOptions>;
106
+ TStaticMethods: IfEquals<TStaticMethods, {}, TSchemaOptions extends { statics: infer S } ? S : {}, TStaticMethods>;
107
107
  TSchemaOptions: TSchemaOptions;
108
108
  DocType: DocType;
109
109
  THydratedDocumentType: THydratedDocumentType;
@@ -136,11 +136,6 @@ declare module 'mongoose' {
136
136
  : T;
137
137
  }
138
138
 
139
- type IsPathDefaultUndefined<PathType> =
140
- PathType extends { default: undefined } ? true
141
- : PathType extends { default: (...args: any[]) => undefined } ? true
142
- : false;
143
-
144
139
  type RequiredPropertyDefinition =
145
140
  | {
146
141
  required: true | string | [true, string | undefined] | { isRequired: true };
@@ -159,16 +154,17 @@ type IsPathRequired<P, TypeKey extends string = DefaultTypeKey> =
159
154
  P extends { required: false } ?
160
155
  false
161
156
  : true
162
- : P extends Record<TypeKey, ArrayConstructor | any[]> ?
163
- IsPathDefaultUndefined<P> extends true ?
164
- false
165
- : true
166
- : P extends Record<TypeKey, any> ?
167
- P extends { default: any } ?
168
- IfEquals<P['default'], undefined, false, true>
169
- : false
157
+ : P extends { default: undefined | null | ((...args: any[]) => undefined) | ((...args: any[]) => null) } ? false
158
+ : P extends { default: any } ? true
159
+ : P extends Record<TypeKey, ArrayConstructor | any[]> ? true
170
160
  : false;
171
161
 
162
+ // Internal type used to efficiently check for never or any types
163
+ // can be efficiently checked like:
164
+ // `[T] extends [neverOrAny] ? T : ...`
165
+ // to avoid edge cases
166
+ type neverOrAny = ' ~neverOrAny~';
167
+
172
168
  /**
173
169
  * @summary A Utility to obtain schema's required path keys.
174
170
  * @param {T} T A generic refers to document definition.
@@ -251,6 +247,7 @@ type UnionToType<T extends readonly any[]> = T[number] extends infer U
251
247
 
252
248
  type IsSchemaTypeFromBuiltinClass<T> =
253
249
  T extends typeof String ? true
250
+ : unknown extends Buffer ? false
254
251
  : T extends typeof Number ? true
255
252
  : T extends typeof Boolean ? true
256
253
  : T extends typeof Buffer ? true
@@ -268,7 +265,6 @@ type IsSchemaTypeFromBuiltinClass<T> =
268
265
  : T extends NativeDate ? true
269
266
  : T extends typeof Schema.Types.Mixed ? true
270
267
  : T extends Types.UUID ? true
271
- : unknown extends Buffer ? false
272
268
  : T extends Buffer ? true
273
269
  : false;
274
270
 
@@ -284,12 +280,10 @@ type ResolvePathType<
284
280
  Options extends SchemaTypeOptions<PathValueType> = {},
285
281
  TypeKey extends string = DefaultSchemaOptions['typeKey'],
286
282
  TypeHint = never
287
- > = IfEquals<
288
- TypeHint,
289
- never,
290
- PathValueType extends Schema ? InferSchemaType<PathValueType>
283
+ > = [TypeHint] extends [never]
284
+ ? PathValueType extends Schema ? InferSchemaType<PathValueType>
291
285
  : PathValueType extends AnyArray<infer Item> ?
292
- IfEquals<Item, never> extends true
286
+ [Item] extends [never]
293
287
  ? any[]
294
288
  : Item extends Schema ?
295
289
  // If Item is a schema, infer its type.
@@ -328,7 +322,7 @@ type ResolvePathType<
328
322
  : never
329
323
  : PathValueType extends ArrayConstructor ? any[]
330
324
  : PathValueType extends typeof Schema.Types.Mixed ? any
331
- : IfEquals<PathValueType, ObjectConstructor> extends true ? any
325
+ : PathValueType extends ObjectConstructor ? any
332
326
  : IfEquals<PathValueType, {}> extends true ? any
333
327
  : PathValueType extends typeof SchemaType ? PathValueType['prototype']
334
328
  : PathValueType extends Record<string, any> ?
@@ -339,6 +333,5 @@ type ResolvePathType<
339
333
  typeKey: TypeKey;
340
334
  }
341
335
  >
342
- : unknown,
343
- TypeHint
344
- >;
336
+ : unknown
337
+ : TypeHint;
@@ -38,6 +38,17 @@ declare module 'mongoose' {
38
38
  this: ThisType,
39
39
  opts?: Record<string, any>
40
40
  ) => void | Promise<void> | Kareem.SkipWrappedFunction;
41
+ type PreDeleteOneMiddlewareFunction<ThisType = any> = (
42
+ this: ThisType,
43
+ doc: ThisType,
44
+ opts?: Record<string, any>
45
+ ) => void | Promise<void> | Kareem.SkipWrappedFunction;
46
+ type PreUpdateOneMiddlewareFunction<ThisType = any> = (
47
+ this: ThisType,
48
+ doc: ThisType,
49
+ update?: Record<string, any>,
50
+ opts?: Record<string, any>
51
+ ) => void | Promise<void> | Kareem.SkipWrappedFunction;
41
52
  type PreSaveMiddlewareFunction<ThisType = any> = (
42
53
  this: ThisType,
43
54
  opts: SaveOptions
package/types/models.d.ts CHANGED
@@ -190,19 +190,27 @@ declare module 'mongoose' {
190
190
  mongodb.InsertOneModel<TSchema> & MongooseBulkWritePerOperationOptions;
191
191
 
192
192
  export type ReplaceOneModel<TSchema extends mongodb.Document = mongodb.Document> =
193
- mongodb.ReplaceOneModel<TSchema> & MongooseBulkWritePerOperationOptions;
193
+ Omit<mongodb.ReplaceOneModel<TSchema>, 'filter'> &
194
+ { filter: QueryFilter<TSchema> } &
195
+ MongooseBulkUpdatePerOperationOptions;
194
196
 
195
197
  export type UpdateOneModel<TSchema extends mongodb.Document = mongodb.Document> =
196
- mongodb.UpdateOneModel<TSchema> & MongooseBulkUpdatePerOperationOptions;
198
+ Omit<mongodb.UpdateOneModel<TSchema>, 'filter'> &
199
+ { filter: QueryFilter<TSchema> } &
200
+ MongooseBulkUpdatePerOperationOptions;
197
201
 
198
202
  export type UpdateManyModel<TSchema extends mongodb.Document = mongodb.Document> =
199
- mongodb.UpdateManyModel<TSchema> & MongooseBulkUpdatePerOperationOptions;
203
+ Omit<mongodb.UpdateManyModel<TSchema>, 'filter'> &
204
+ { filter: QueryFilter<TSchema> } &
205
+ MongooseBulkUpdatePerOperationOptions;
200
206
 
201
207
  export type DeleteOneModel<TSchema extends mongodb.Document = mongodb.Document> =
202
- mongodb.DeleteOneModel<TSchema>;
208
+ Omit<mongodb.DeleteOneModel<TSchema>, 'filter'> &
209
+ { filter: QueryFilter<TSchema> };
203
210
 
204
211
  export type DeleteManyModel<TSchema extends mongodb.Document = mongodb.Document> =
205
- mongodb.DeleteManyModel<TSchema>;
212
+ Omit<mongodb.DeleteManyModel<TSchema>, 'filter'> &
213
+ { filter: QueryFilter<TSchema> };
206
214
 
207
215
  export type AnyBulkWriteOperation<TSchema extends mongodb.Document = mongodb.Document> =
208
216
  | { insertOne: InsertOneModel<TSchema> }
@@ -335,6 +343,8 @@ declare module 'mongoose' {
335
343
 
336
344
  /** Creates a new document or documents */
337
345
  create(): Promise<null>;
346
+ create(doc: Partial<TRawDocType>): Promise<THydratedDocumentType>;
347
+ create(docs: Array<Partial<TRawDocType>>): Promise<THydratedDocumentType[]>;
338
348
  create(docs: Array<DeepPartial<ApplyBasicCreateCasting<Require_id<TRawDocType>>>>, options: CreateOptions & { aggregateErrors: true }): Promise<(THydratedDocumentType | Error)[]>;
339
349
  create(docs: Array<DeepPartial<ApplyBasicCreateCasting<Require_id<TRawDocType>>>>, options?: CreateOptions): Promise<THydratedDocumentType[]>;
340
350
  create(doc: DeepPartial<ApplyBasicCreateCasting<Require_id<TRawDocType>>>): Promise<THydratedDocumentType>;
package/types/query.d.ts CHANGED
@@ -20,7 +20,7 @@ declare module 'mongoose' {
20
20
 
21
21
  export type ApplyBasicQueryCasting<T> = QueryTypeCasting<T> | QueryTypeCasting<T[]> | (T extends (infer U)[] ? QueryTypeCasting<U> : T) | null;
22
22
 
23
- type _QueryFilter<T> = ({ [P in keyof T]?: mongodb.Condition<ApplyBasicQueryCasting<T[P]>>; } & mongodb.RootFilterOperators<{ [P in keyof T]?: ApplyBasicQueryCasting<T[P]>; }>);
23
+ type _QueryFilter<T> = ({ [P in keyof T]?: mongodb.Condition<ApplyBasicQueryCasting<T[P]>>; } & mongodb.RootFilterOperators<{ [P in keyof mongodb.WithId<T>]?: ApplyBasicQueryCasting<mongodb.WithId<T>[P]>; }>);
24
24
  type QueryFilter<T> = IsItRecordAndNotAny<T> extends true ? _QueryFilter<WithLevel1NestedPaths<T>> : _QueryFilter<Record<string, any>>;
25
25
 
26
26
  type MongooseBaseQueryOptionKeys =
@@ -111,8 +111,10 @@ declare module 'mongoose' {
111
111
  /**
112
112
  * Optimistic concurrency is a strategy to ensure the document you're updating didn't change between when you
113
113
  * loaded it using find() or findOne(), and when you update it using save(). Set to `true` to enable
114
- * optimistic concurrency. Set to string array to enable optimistic concurrency for only certain fields,
115
- * or `{ exclude: string[] }` to define a list of fields to ignore for optimistic concurrency.
114
+ * optimistic concurrency for all fields. Set to a string array to enable optimistic concurrency only for
115
+ * the specified fields; note that this **replaces** the default array versioning behavior. Set to
116
+ * `{ exclude: string[] }` to enable optimistic concurrency for all fields except the specified ones;
117
+ * this also **replaces** the default array versioning.
116
118
  */
117
119
  optimisticConcurrency?: boolean | string[] | { exclude: string[] };
118
120
  /**
@@ -146,7 +146,7 @@ declare module 'mongoose' {
146
146
  * @param {T} T Function type to extract 'this' parameter from.
147
147
  * @param {F} F Fallback type to return if 'this' parameter does not exist.
148
148
  */
149
- type ThisParameter<T, F> = T extends { (this: infer This): void } ? This : F;
149
+ type ThisParameter<T, F> = T extends { (this: infer This, ...args: never): void } ? This : F;
150
150
 
151
151
  /**
152
152
  * @summary Decorates all functions in an object with 'this' parameter.
@@ -8,7 +8,7 @@ declare module 'mongoose' {
8
8
  type TVirtualPathFN<DocType = {}, PathType = unknown, TInstanceMethods = {}, TReturn = unknown> =
9
9
  <T = HydratedDocument<DocType, TInstanceMethods>>(this: Document<any, any, DocType> & DocType, value: PathType, virtual: VirtualType<T>, doc: Document<any, any, DocType> & DocType) => TReturn;
10
10
 
11
- type SchemaOptionsVirtualsPropertyType<DocType = any, VirtualPaths = Record<any, unknown>, TInstanceMethods = {}> = {
12
- [K in keyof VirtualPaths]: VirtualPathFunctions<IsItRecordAndNotAny<DocType> extends true ? DocType : any, VirtualPaths[K], TInstanceMethods>
13
- };
11
+ type SchemaOptionsVirtualsPropertyType<DocType = any, VirtualPaths = Record<any, unknown>, TInstanceMethods = {}> = {
12
+ [K in keyof VirtualPaths]: VirtualPathFunctions<IsItRecordAndNotAny<DocType> extends true ? DocType : any, VirtualPaths[K], TInstanceMethods>
13
+ };
14
14
  }