mongoose 8.20.0 → 9.0.0-rc0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/eslint.config.mjs +198 -0
  2. package/lib/aggregate.js +17 -73
  3. package/lib/cast/bigint.js +1 -1
  4. package/lib/cast/double.js +1 -1
  5. package/lib/cast/uuid.js +5 -48
  6. package/lib/cast.js +2 -2
  7. package/lib/connection.js +0 -1
  8. package/lib/cursor/aggregationCursor.js +14 -24
  9. package/lib/cursor/queryCursor.js +7 -14
  10. package/lib/document.js +125 -121
  11. package/lib/drivers/node-mongodb-native/connection.js +3 -10
  12. package/lib/error/objectParameter.js +1 -2
  13. package/lib/error/validation.js +0 -8
  14. package/lib/helpers/clone.js +1 -1
  15. package/lib/helpers/common.js +1 -1
  16. package/lib/helpers/indexes/isIndexEqual.js +0 -1
  17. package/lib/helpers/model/applyDefaultsToPOJO.js +2 -2
  18. package/lib/helpers/model/applyHooks.js +43 -53
  19. package/lib/helpers/model/applyMethods.js +2 -2
  20. package/lib/helpers/model/applyStaticHooks.js +1 -48
  21. package/lib/helpers/model/castBulkWrite.js +1 -1
  22. package/lib/helpers/parallelLimit.js +18 -36
  23. package/lib/helpers/pluralize.js +3 -3
  24. package/lib/helpers/populate/assignRawDocsToIdStructure.js +1 -8
  25. package/lib/helpers/populate/createPopulateQueryFilter.js +1 -1
  26. package/lib/helpers/populate/getModelsMapForPopulate.js +17 -9
  27. package/lib/helpers/populate/getSchemaTypes.js +5 -5
  28. package/lib/helpers/query/cast$expr.js +8 -10
  29. package/lib/helpers/query/castFilterPath.js +1 -1
  30. package/lib/helpers/query/castUpdate.js +14 -12
  31. package/lib/helpers/query/getEmbeddedDiscriminatorPath.js +1 -1
  32. package/lib/helpers/schema/applyPlugins.js +1 -1
  33. package/lib/helpers/schema/getIndexes.js +1 -7
  34. package/lib/helpers/timestamps/setupTimestamps.js +3 -6
  35. package/lib/helpers/updateValidators.js +57 -111
  36. package/lib/model.js +419 -607
  37. package/lib/mongoose.js +41 -13
  38. package/lib/plugins/saveSubdocs.js +24 -51
  39. package/lib/plugins/sharding.js +5 -4
  40. package/lib/plugins/validateBeforeSave.js +3 -13
  41. package/lib/query.js +101 -145
  42. package/lib/queryHelpers.js +2 -2
  43. package/lib/schema/array.js +41 -84
  44. package/lib/schema/documentArray.js +57 -94
  45. package/lib/schema/documentArrayElement.js +16 -11
  46. package/lib/schema/string.js +1 -1
  47. package/lib/schema/subdocument.js +22 -28
  48. package/lib/schema/uuid.js +0 -21
  49. package/lib/schema.js +81 -39
  50. package/lib/schemaType.js +39 -57
  51. package/lib/types/array/index.js +2 -2
  52. package/lib/types/array/methods/index.js +4 -4
  53. package/lib/types/arraySubdocument.js +1 -1
  54. package/lib/types/buffer.js +10 -10
  55. package/lib/types/decimal128.js +1 -1
  56. package/lib/types/documentArray/index.js +1 -1
  57. package/lib/types/documentArray/methods/index.js +5 -3
  58. package/lib/types/double.js +1 -1
  59. package/lib/types/objectid.js +1 -1
  60. package/lib/types/subdocument.js +15 -43
  61. package/lib/types/uuid.js +1 -1
  62. package/lib/utils.js +1 -8
  63. package/lib/validOptions.js +3 -3
  64. package/package.json +11 -24
  65. package/types/connection.d.ts +20 -11
  66. package/types/document.d.ts +95 -26
  67. package/types/index.d.ts +143 -39
  68. package/types/inferhydrateddoctype.d.ts +115 -0
  69. package/types/inferrawdoctype.d.ts +99 -75
  70. package/types/inferschematype.d.ts +17 -3
  71. package/types/middlewares.d.ts +0 -2
  72. package/types/models.d.ts +131 -199
  73. package/types/mongooseoptions.d.ts +6 -5
  74. package/types/pipelinestage.d.ts +1 -1
  75. package/types/query.d.ts +71 -139
  76. package/types/schemaoptions.d.ts +1 -1
  77. package/types/schematypes.d.ts +14 -10
  78. package/types/types.d.ts +3 -4
  79. package/types/utility.d.ts +68 -48
  80. package/types/validation.d.ts +18 -14
  81. package/browser.js +0 -8
  82. package/dist/browser.umd.js +0 -2
  83. package/lib/browser.js +0 -141
  84. package/lib/browserDocument.js +0 -101
  85. package/lib/documentProvider.js +0 -30
  86. package/lib/drivers/browser/binary.js +0 -14
  87. package/lib/drivers/browser/decimal128.js +0 -7
  88. package/lib/drivers/browser/index.js +0 -13
  89. package/lib/drivers/browser/objectid.js +0 -29
  90. package/lib/helpers/promiseOrCallback.js +0 -54
package/lib/mongoose.js CHANGED
@@ -39,7 +39,7 @@ require('./helpers/printJestWarning');
39
39
 
40
40
  const objectIdHexRegexp = /^[0-9A-Fa-f]{24}$/;
41
41
 
42
- const { AsyncLocalStorage } = require('node:async_hooks');
42
+ const { AsyncLocalStorage } = require('async_hooks');
43
43
 
44
44
  /**
45
45
  * Mongoose constructor.
@@ -230,7 +230,6 @@ Mongoose.prototype.setDriver = function setDriver(driver) {
230
230
  * - `cloneSchemas`: `false` by default. Set to `true` to `clone()` all schemas before compiling into a model.
231
231
  * - `debug`: If `true`, prints the operations mongoose sends to MongoDB to the console. If a writable stream is passed, it will log to that stream, without colorization. If a callback function is passed, it will receive the collection name, the method name, then all arguments passed to the method. For example, if you wanted to replicate the default logging, you could output from the callback `Mongoose: ${collectionName}.${methodName}(${methodArgs.join(', ')})`.
232
232
  * - `id`: If `true`, adds a `id` virtual to all schemas unless overwritten on a per-schema basis.
233
- * - `timestamps.createdAt.immutable`: `true` by default. If `false`, it will change the `createdAt` field to be [`immutable: false`](https://mongoosejs.com/docs/api/schematype.html#SchemaType.prototype.immutable) which means you can update the `createdAt`
234
233
  * - `maxTimeMS`: If set, attaches [maxTimeMS](https://www.mongodb.com/docs/manual/reference/operator/meta/maxTimeMS/) to every query
235
234
  * - `objectIdGetter`: `true` by default. Mongoose adds a getter to MongoDB ObjectId's called `_id` that returns `this` for convenience with populate. Set this to false to remove the getter.
236
235
  * - `overwriteModels`: Set to `true` to default to overwriting models with the same name when calling `mongoose.model()`, as opposed to throwing an `OverwriteModelError`.
@@ -238,10 +237,12 @@ Mongoose.prototype.setDriver = function setDriver(driver) {
238
237
  * - `runValidators`: `false` by default. Set to true to enable [update validators](https://mongoosejs.com/docs/validation.html#update-validators) for all validators by default.
239
238
  * - `sanitizeFilter`: `false` by default. Set to true to enable the [sanitization of the query filters](https://mongoosejs.com/docs/api/mongoose.html#Mongoose.prototype.sanitizeFilter()) against query selector injection attacks by wrapping any nested objects that have a property whose name starts with `$` in a `$eq`.
240
239
  * - `selectPopulatedPaths`: `true` by default. Set to false to opt out of Mongoose adding all fields that you `populate()` to your `select()`. The schema-level option `selectPopulatedPaths` overwrites this one.
241
- * - `strict`: `true` by default, may be `false`, `true`, or `'throw'`. Sets the default strict mode for schemas.
242
240
  * - `strictQuery`: `false` by default. May be `false`, `true`, or `'throw'`. Sets the default [strictQuery](https://mongoosejs.com/docs/guide.html#strictQuery) mode for schemas.
241
+ * - `strict`: `true` by default, may be `false`, `true`, or `'throw'`. Sets the default strict mode for schemas.
242
+ * - `timestamps.createdAt.immutable`: `true` by default. If `false`, it will change the `createdAt` field to be [`immutable: false`](https://mongoosejs.com/docs/api/schematype.html#SchemaType.prototype.immutable) which means you can update the `createdAt`
243
243
  * - `toJSON`: `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toJSON()`](https://mongoosejs.com/docs/api/document.html#Document.prototype.toJSON()), for determining how Mongoose documents get serialized by `JSON.stringify()`
244
244
  * - `toObject`: `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toObject()`](https://mongoosejs.com/docs/api/document.html#Document.prototype.toObject())
245
+ * - `updatePipeline`: `false` by default. If `true`, allows passing update pipelines (arrays) to update operations by default without explicitly setting `updatePipeline: true` in each query.
245
246
  *
246
247
  * @param {String|Object} key The name of the option or a object of multiple key-value pairs
247
248
  * @param {String|Function|Boolean} value The value of the option, unused if "key" is a object
@@ -1051,16 +1052,6 @@ Mongoose.prototype.Model = Model;
1051
1052
 
1052
1053
  Mongoose.prototype.Document = Document;
1053
1054
 
1054
- /**
1055
- * The Mongoose DocumentProvider constructor. Mongoose users should not have to
1056
- * use this directly
1057
- *
1058
- * @method DocumentProvider
1059
- * @api public
1060
- */
1061
-
1062
- Mongoose.prototype.DocumentProvider = require('./documentProvider');
1063
-
1064
1055
  /**
1065
1056
  * The Mongoose ObjectId [SchemaType](https://mongoosejs.com/docs/schematypes.html). Used for
1066
1057
  * declaring paths in your schema that should be
@@ -1337,6 +1328,43 @@ Mongoose.prototype.skipMiddlewareFunction = Kareem.skipWrappedFunction;
1337
1328
 
1338
1329
  Mongoose.prototype.overwriteMiddlewareResult = Kareem.overwriteResult;
1339
1330
 
1331
+ /**
1332
+ * Use this function in `pre()` middleware to replace the arguments passed to the next middleware or hook.
1333
+ *
1334
+ * #### Example:
1335
+ *
1336
+ * // Suppose you have a schema for time in "HH:MM" string format, but you want to store it as an object { hours, minutes }
1337
+ * const timeStringToObject = (time) => {
1338
+ * if (typeof time !== 'string') return time;
1339
+ * const [hours, minutes] = time.split(':');
1340
+ * return { hours: parseInt(hours), minutes: parseInt(minutes) };
1341
+ * };
1342
+ *
1343
+ * const timeSchema = new Schema({
1344
+ * hours: { type: Number, required: true },
1345
+ * minutes: { type: Number, required: true },
1346
+ * });
1347
+ *
1348
+ * // In a pre('init') hook, replace raw string doc with custom object form
1349
+ * timeSchema.pre('init', function(doc) {
1350
+ * if (typeof doc === 'string') {
1351
+ * return mongoose.overwriteMiddlewareArguments(timeStringToObject(doc));
1352
+ * }
1353
+ * });
1354
+ *
1355
+ * // Now, initializing with a time string gets auto-converted by the hook
1356
+ * const userSchema = new Schema({ time: timeSchema });
1357
+ * const User = mongoose.model('User', userSchema);
1358
+ * const doc = new User({});
1359
+ * doc.$init({ time: '12:30' });
1360
+ *
1361
+ * @method overwriteMiddlewareArguments
1362
+ * @param {...any} args The new arguments to be passed to the next middleware. Pass multiple arguments as a spread, **not** as an array.
1363
+ * @api public
1364
+ */
1365
+
1366
+ Mongoose.prototype.overwriteMiddlewareArguments = Kareem.overwriteArguments;
1367
+
1340
1368
  /**
1341
1369
  * Takes in an object and deletes any keys from the object whose values
1342
1370
  * are strictly equal to `undefined`.
@@ -1,45 +1,44 @@
1
1
  'use strict';
2
2
 
3
- const each = require('../helpers/each');
4
-
5
3
  /*!
6
4
  * ignore
7
5
  */
8
6
 
9
7
  module.exports = function saveSubdocs(schema) {
10
8
  const unshift = true;
11
- schema.s.hooks.pre('save', false, function saveSubdocsPreSave(next) {
9
+ schema.s.hooks.pre('save', false, async function saveSubdocsPreSave() {
12
10
  if (this.$isSubdocument) {
13
- next();
14
11
  return;
15
12
  }
16
13
 
17
- const _this = this;
18
14
  const subdocs = this.$getAllSubdocs({ useCache: true });
19
15
 
20
16
  if (!subdocs.length) {
21
- next();
22
17
  return;
23
18
  }
24
19
 
25
- each(subdocs, function(subdoc, cb) {
26
- subdoc.$__schema.s.hooks.execPre('save', subdoc, function(err) {
27
- cb(err);
28
- });
29
- }, function(error) {
30
- // Invalidate subdocs cache because subdoc pre hooks can add new subdocuments
31
- if (_this.$__.saveOptions) {
32
- _this.$__.saveOptions.__subdocs = null;
33
- }
34
- if (error) {
35
- return _this.$__schema.s.hooks.execPost('save:error', _this, [_this], { error: error }, function(error) {
36
- next(error);
37
- });
38
- }
39
- next();
40
- });
20
+ await Promise.all(subdocs.map(subdoc => subdoc._execDocumentPreHooks('save')));
21
+
22
+ // Invalidate subdocs cache because subdoc pre hooks can add new subdocuments
23
+ if (this.$__.saveOptions) {
24
+ this.$__.saveOptions.__subdocs = null;
25
+ }
41
26
  }, null, unshift);
42
27
 
28
+ schema.s.hooks.pre('save', async function saveSubdocsPreDeleteOne() {
29
+ const removedSubdocs = this.$__.removedSubdocs;
30
+ if (!removedSubdocs || !removedSubdocs.length) {
31
+ return;
32
+ }
33
+
34
+ const promises = [];
35
+ for (const subdoc of removedSubdocs) {
36
+ promises.push(subdoc._execDocumentPreHooks('deleteOne'));
37
+ }
38
+
39
+ await Promise.all(promises);
40
+ });
41
+
43
42
  schema.s.hooks.post('save', async function saveSubdocsPostDeleteOne() {
44
43
  const removedSubdocs = this.$__.removedSubdocs;
45
44
  if (!removedSubdocs || !removedSubdocs.length) {
@@ -48,14 +47,7 @@ module.exports = function saveSubdocs(schema) {
48
47
 
49
48
  const promises = [];
50
49
  for (const subdoc of removedSubdocs) {
51
- promises.push(new Promise((resolve, reject) => {
52
- subdoc.$__schema.s.hooks.execPost('deleteOne', subdoc, [subdoc], function(err) {
53
- if (err) {
54
- return reject(err);
55
- }
56
- resolve();
57
- });
58
- }));
50
+ promises.push(subdoc._execDocumentPostHooks('deleteOne'));
59
51
  }
60
52
 
61
53
  this.$__.removedSubdocs = null;
@@ -67,7 +59,6 @@ module.exports = function saveSubdocs(schema) {
67
59
  return;
68
60
  }
69
61
 
70
- const _this = this;
71
62
  const subdocs = this.$getAllSubdocs({ useCache: true });
72
63
 
73
64
  if (!subdocs.length) {
@@ -76,27 +67,9 @@ module.exports = function saveSubdocs(schema) {
76
67
 
77
68
  const promises = [];
78
69
  for (const subdoc of subdocs) {
79
- promises.push(new Promise((resolve, reject) => {
80
- subdoc.$__schema.s.hooks.execPost('save', subdoc, [subdoc], function(err) {
81
- if (err) {
82
- return reject(err);
83
- }
84
- resolve();
85
- });
86
- }));
70
+ promises.push(subdoc._execDocumentPostHooks('save'));
87
71
  }
88
72
 
89
- try {
90
- await Promise.all(promises);
91
- } catch (error) {
92
- await new Promise((resolve, reject) => {
93
- this.$__schema.s.hooks.execPost('save:error', _this, [_this], { error: error }, function(error) {
94
- if (error) {
95
- return reject(error);
96
- }
97
- resolve();
98
- });
99
- });
100
- }
73
+ await Promise.all(promises);
101
74
  }, null, unshift);
102
75
  };
@@ -12,13 +12,14 @@ module.exports = function shardingPlugin(schema) {
12
12
  storeShard.call(this);
13
13
  return this;
14
14
  });
15
- schema.pre('save', function shardingPluginPreSave(next) {
15
+ schema.pre('save', function shardingPluginPreSave() {
16
16
  applyWhere.call(this);
17
- next();
18
17
  });
19
- schema.pre('deleteOne', { document: true, query: false }, function shardingPluginPreRemove(next) {
18
+ schema.pre('deleteOne', { document: true, query: false }, function shardingPluginPreDeleteOne() {
19
+ applyWhere.call(this);
20
+ });
21
+ schema.pre('updateOne', { document: true, query: false }, function shardingPluginPreUpdateOne() {
20
22
  applyWhere.call(this);
21
- next();
22
23
  });
23
24
  schema.post('save', function shardingPluginPostSave() {
24
25
  storeShard.call(this);
@@ -6,11 +6,10 @@
6
6
 
7
7
  module.exports = function validateBeforeSave(schema) {
8
8
  const unshift = true;
9
- schema.pre('save', false, function validateBeforeSave(next, options) {
10
- const _this = this;
9
+ schema.pre('save', false, async function validateBeforeSave(options) {
11
10
  // Nested docs have their own presave
12
11
  if (this.$isSubdocument) {
13
- return next();
12
+ return;
14
13
  }
15
14
 
16
15
  const hasValidateBeforeSaveOption = options &&
@@ -32,20 +31,11 @@ module.exports = function validateBeforeSave(schema) {
32
31
  const validateOptions = hasValidateModifiedOnlyOption ?
33
32
  { validateModifiedOnly: options.validateModifiedOnly } :
34
33
  null;
35
- this.$validate(validateOptions).then(
34
+ await this.$validate(validateOptions).then(
36
35
  () => {
37
36
  this.$op = 'save';
38
- next();
39
- },
40
- error => {
41
- _this.$__schema.s.hooks.execPost('save:error', _this, [_this], { error: error }, function(error) {
42
- _this.$op = 'save';
43
- next(error);
44
- });
45
37
  }
46
38
  );
47
- } else {
48
- next();
49
39
  }
50
40
  }, null, unshift);
51
41
  };