mongoose 9.0.0 → 9.0.2

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 (42) hide show
  1. package/lib/aggregate.js +1 -1
  2. package/lib/cast/double.js +1 -1
  3. package/lib/cast.js +1 -1
  4. package/lib/connection.js +10 -10
  5. package/lib/document.js +63 -19
  6. package/lib/drivers/node-mongodb-native/collection.js +38 -104
  7. package/lib/drivers/node-mongodb-native/connection.js +1 -1
  8. package/lib/helpers/common.js +1 -1
  9. package/lib/helpers/indexes/applySchemaCollation.js +1 -1
  10. package/lib/helpers/indexes/isDefaultIdIndex.js +1 -1
  11. package/lib/helpers/model/applyMethods.js +1 -1
  12. package/lib/helpers/model/castBulkWrite.js +13 -6
  13. package/lib/helpers/populate/getModelsMapForPopulate.js +3 -3
  14. package/lib/helpers/populate/modelNamesFromRefPath.js +1 -1
  15. package/lib/helpers/populate/removeDeselectedForeignField.js +1 -1
  16. package/lib/helpers/projection/applyProjection.js +2 -2
  17. package/lib/helpers/query/getEmbeddedDiscriminatorPath.js +1 -1
  18. package/lib/helpers/setDefaultsOnInsert.js +2 -2
  19. package/lib/helpers/timestamps/setupTimestamps.js +1 -1
  20. package/lib/helpers/update/applyTimestampsToUpdate.js +38 -25
  21. package/lib/helpers/update/decorateUpdateWithVersionKey.js +1 -1
  22. package/lib/model.js +17 -11
  23. package/lib/mongoose.js +3 -4
  24. package/lib/query.js +3 -3
  25. package/lib/schema/array.js +1 -1
  26. package/lib/schema/number.js +14 -2
  27. package/lib/schema/operators/text.js +1 -1
  28. package/lib/schema.js +21 -21
  29. package/lib/schemaType.js +8 -8
  30. package/lib/types/array/index.js +5 -5
  31. package/lib/types/documentArray/index.js +6 -6
  32. package/lib/types/objectid.js +1 -1
  33. package/lib/utils.js +12 -24
  34. package/lib/virtualType.js +1 -1
  35. package/package.json +8 -7
  36. package/types/index.d.ts +11 -3
  37. package/types/inferrawdoctype.d.ts +9 -3
  38. package/types/inferschematype.d.ts +20 -27
  39. package/types/models.d.ts +313 -85
  40. package/types/query.d.ts +91 -1
  41. package/types/utility.d.ts +1 -1
  42. package/types/virtuals.d.ts +3 -3
package/lib/aggregate.js CHANGED
@@ -103,7 +103,7 @@ Aggregate.prototype._optionsForExec = function() {
103
103
  const options = this.options || {};
104
104
 
105
105
  const asyncLocalStorage = this.model()?.db?.base.transactionAsyncLocalStorage?.getStore();
106
- if (!options.hasOwnProperty('session') && asyncLocalStorage?.session != null) {
106
+ if (!Object.hasOwn(options, 'session') && asyncLocalStorage?.session != null) {
107
107
  options.session = asyncLocalStorage.session;
108
108
  }
109
109
 
@@ -34,7 +34,7 @@ module.exports = function castDouble(val) {
34
34
  // ex: { a: 'im an object, valueOf: () => 'helloworld' } // throw an error
35
35
  if (typeof tempVal === 'string') {
36
36
  try {
37
- coercedVal = BSON.Double.fromString(val);
37
+ coercedVal = BSON.Double.fromString(tempVal);
38
38
  return coercedVal;
39
39
  } catch {
40
40
  assert.ok(false);
package/lib/cast.js CHANGED
@@ -107,7 +107,7 @@ module.exports = function cast(schema, obj, options, context) {
107
107
  val = cast(schema, val, options, context);
108
108
  } else if (path === '$text') {
109
109
  val = castTextSearch(val, path);
110
- } else if (path === '$comment' && !schema.paths.hasOwnProperty('$comment')) {
110
+ } else if (path === '$comment' && !Object.hasOwn(schema.paths, '$comment')) {
111
111
  val = castString(val, path);
112
112
  obj[path] = val;
113
113
  } else {
package/lib/connection.js CHANGED
@@ -164,7 +164,7 @@ Object.defineProperty(Connection.prototype, 'readyState', {
164
164
  */
165
165
 
166
166
  Connection.prototype.get = function getOption(key) {
167
- if (this.config.hasOwnProperty(key)) {
167
+ if (Object.hasOwn(this.config, key)) {
168
168
  return this.config[key];
169
169
  }
170
170
 
@@ -192,7 +192,7 @@ Connection.prototype.get = function getOption(key) {
192
192
  */
193
193
 
194
194
  Connection.prototype.set = function setOption(key, val) {
195
- if (this.config.hasOwnProperty(key)) {
195
+ if (Object.hasOwn(this.config, key)) {
196
196
  this.config[key] = val;
197
197
  return val;
198
198
  }
@@ -459,7 +459,7 @@ Connection.prototype.bulkWrite = async function bulkWrite(ops, options) {
459
459
 
460
460
  const ordered = options.ordered == null ? true : options.ordered;
461
461
  const asyncLocalStorage = this.base.transactionAsyncLocalStorage?.getStore();
462
- if ((!options || !options.hasOwnProperty('session')) && asyncLocalStorage?.session != null) {
462
+ if ((!options || !Object.hasOwn(options, 'session')) && asyncLocalStorage?.session != null) {
463
463
  options = { ...options, session: asyncLocalStorage.session };
464
464
  }
465
465
 
@@ -477,7 +477,7 @@ Connection.prototype.bulkWrite = async function bulkWrite(ops, options) {
477
477
  if (op.name == null) {
478
478
  throw new MongooseError('Must specify operation name in Connection.prototype.bulkWrite()');
479
479
  }
480
- if (!castBulkWrite.cast.hasOwnProperty(op.name)) {
480
+ if (!Object.hasOwn(castBulkWrite.cast, op.name)) {
481
481
  throw new MongooseError(`Unrecognized bulkWrite() operation name ${op.name}`);
482
482
  }
483
483
 
@@ -513,7 +513,7 @@ Connection.prototype.bulkWrite = async function bulkWrite(ops, options) {
513
513
  results[i] = error;
514
514
  continue;
515
515
  }
516
- if (!castBulkWrite.cast.hasOwnProperty(op.name)) {
516
+ if (!Object.hasOwn(castBulkWrite.cast, op.name)) {
517
517
  const error = new MongooseError(`Unrecognized bulkWrite() operation name ${op.name}`);
518
518
  validationErrors.push({ index: i, error: error });
519
519
  results[i] = error;
@@ -772,10 +772,10 @@ async function _wrapUserTransaction(fn, session, mongoose) {
772
772
  function _resetSessionDocuments(session) {
773
773
  for (const doc of session[sessionNewDocuments].keys()) {
774
774
  const state = session[sessionNewDocuments].get(doc);
775
- if (state.hasOwnProperty('isNew')) {
775
+ if (Object.hasOwn(state, 'isNew')) {
776
776
  doc.$isNew = state.isNew;
777
777
  }
778
- if (state.hasOwnProperty('versionKey')) {
778
+ if (Object.hasOwn(state, 'versionKey')) {
779
779
  doc.set(doc.schema.options.versionKey, state.versionKey);
780
780
  }
781
781
 
@@ -1013,7 +1013,7 @@ Connection.prototype.onOpen = function() {
1013
1013
  // avoid having the collection subscribe to our event emitter
1014
1014
  // to prevent 0.3 warning
1015
1015
  for (const i in this.collections) {
1016
- if (utils.object.hasOwnProperty(this.collections, i)) {
1016
+ if (Object.hasOwn(this.collections, i)) {
1017
1017
  this.collections[i].onOpen();
1018
1018
  }
1019
1019
  }
@@ -1321,7 +1321,7 @@ Connection.prototype.onClose = function onClose(force) {
1321
1321
  // avoid having the collection subscribe to our event emitter
1322
1322
  // to prevent 0.3 warning
1323
1323
  for (const i in this.collections) {
1324
- if (utils.object.hasOwnProperty(this.collections, i)) {
1324
+ if (Object.hasOwn(this.collections, i)) {
1325
1325
  this.collections[i].onClose(force);
1326
1326
  }
1327
1327
  }
@@ -1782,7 +1782,7 @@ Connection.prototype.syncIndexes = async function syncIndexes(options = {}) {
1782
1782
  };
1783
1783
 
1784
1784
  /**
1785
- * Switches to a different database using the same [connection pool](https://mongoosejs.com/docs/api/connectionshtml#connection_pools).
1785
+ * Switches to a different database using the same [connection pool](https://mongoosejs.com/docs/connections.html#connection_pools).
1786
1786
  *
1787
1787
  * Returns a new connection object, with the new db.
1788
1788
  *
package/lib/document.js CHANGED
@@ -648,6 +648,10 @@ Document.prototype.init = function(doc, opts, fn) {
648
648
  opts = null;
649
649
  }
650
650
 
651
+ if (doc == null) {
652
+ throw new ObjectParameterError(doc, 'doc', 'init');
653
+ }
654
+
651
655
  this.$__init(doc, opts);
652
656
 
653
657
  if (fn) {
@@ -677,6 +681,9 @@ Document.prototype.$init = function() {
677
681
  */
678
682
 
679
683
  Document.prototype.$__init = function(doc, opts) {
684
+ if (doc == null) {
685
+ throw new ObjectParameterError(doc, 'doc', 'init');
686
+ }
680
687
  this.$isNew = false;
681
688
  opts = opts || {};
682
689
 
@@ -784,7 +791,7 @@ function init(self, obj, doc, opts, prefix) {
784
791
  }
785
792
  } else {
786
793
  // Retain order when overwriting defaults
787
- if (doc.hasOwnProperty(i) && value !== void 0 && !opts.hydratedPopulatedDocs) {
794
+ if (Object.hasOwn(doc, i) && value !== void 0 && !opts.hydratedPopulatedDocs) {
788
795
  delete doc[i];
789
796
  }
790
797
  if (value === null) {
@@ -1167,7 +1174,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
1167
1174
  const orderedKeys = Object.keys(this.$__schema.tree);
1168
1175
  for (let i = 0, len = orderedKeys.length; i < len; ++i) {
1169
1176
  (key = orderedKeys[i]) &&
1170
- (this._doc.hasOwnProperty(key)) &&
1177
+ (Object.hasOwn(this._doc, key)) &&
1171
1178
  (orderedDoc[key] = undefined);
1172
1179
  }
1173
1180
  this._doc = Object.assign(orderedDoc, this._doc);
@@ -1217,8 +1224,8 @@ Document.prototype.$set = function $set(path, val, type, options) {
1217
1224
  return this;
1218
1225
  }
1219
1226
  const wasModified = this.$isModified(path);
1220
- const hasInitialVal = this.$__.savedState != null && this.$__.savedState.hasOwnProperty(path);
1221
- if (this.$__.savedState != null && !this.$isNew && !this.$__.savedState.hasOwnProperty(path)) {
1227
+ const hasInitialVal = this.$__.savedState != null && Object.hasOwn(this.$__.savedState, path);
1228
+ if (this.$__.savedState != null && !this.$isNew && !Object.hasOwn(this.$__.savedState, path)) {
1222
1229
  const initialVal = this.$__getValue(path);
1223
1230
  this.$__.savedState[path] = initialVal;
1224
1231
 
@@ -1523,7 +1530,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
1523
1530
  this.$__.session[sessionNewDocuments].get(this).modifiedPaths &&
1524
1531
  !this.$__.session[sessionNewDocuments].get(this).modifiedPaths.has(savedStatePath);
1525
1532
  if (savedState != null &&
1526
- savedState.hasOwnProperty(savedStatePath) &&
1533
+ Object.hasOwn(savedState, savedStatePath) &&
1527
1534
  (!isInTransaction || isModifiedWithinTransaction) &&
1528
1535
  utils.deepEqual(val, savedState[savedStatePath])) {
1529
1536
  this.unmarkModified(path);
@@ -2005,7 +2012,7 @@ Document.prototype.$get = Document.prototype.get;
2005
2012
 
2006
2013
  Document.prototype.$__path = function(path) {
2007
2014
  const adhocs = this.$__.adhocPaths;
2008
- const adhocType = adhocs && adhocs.hasOwnProperty(path) ? adhocs[path] : null;
2015
+ const adhocType = adhocs && Object.hasOwn(adhocs, path) ? adhocs[path] : null;
2009
2016
 
2010
2017
  if (adhocType) {
2011
2018
  return adhocType;
@@ -2049,7 +2056,7 @@ Document.prototype.$__saveInitialState = function $__saveInitialState(path) {
2049
2056
  if (savedState != null) {
2050
2057
  const firstDot = savedStatePath.indexOf('.');
2051
2058
  const topLevelPath = firstDot === -1 ? savedStatePath : savedStatePath.slice(0, firstDot);
2052
- if (!savedState.hasOwnProperty(topLevelPath)) {
2059
+ if (!Object.hasOwn(savedState, topLevelPath)) {
2053
2060
  savedState[topLevelPath] = clone(this.$__getValue(topLevelPath));
2054
2061
  }
2055
2062
  }
@@ -2360,7 +2367,7 @@ Document.prototype.$isDefault = function(path) {
2360
2367
  }
2361
2368
 
2362
2369
  if (typeof path === 'string' && path.indexOf(' ') === -1) {
2363
- return this.$__.activePaths.getStatePaths('default').hasOwnProperty(path);
2370
+ return Object.hasOwn(this.$__.activePaths.getStatePaths('default'), path);
2364
2371
  }
2365
2372
 
2366
2373
  let paths = path;
@@ -2368,7 +2375,7 @@ Document.prototype.$isDefault = function(path) {
2368
2375
  paths = paths.split(' ');
2369
2376
  }
2370
2377
 
2371
- return paths.some(path => this.$__.activePaths.getStatePaths('default').hasOwnProperty(path));
2378
+ return paths.some(path => Object.hasOwn(this.$__.activePaths.getStatePaths('default'), path));
2372
2379
  };
2373
2380
 
2374
2381
  /**
@@ -2422,7 +2429,7 @@ Document.prototype.isDirectModified = function(path) {
2422
2429
  }
2423
2430
 
2424
2431
  if (typeof path === 'string' && path.indexOf(' ') === -1) {
2425
- const res = this.$__.activePaths.getStatePaths('modify').hasOwnProperty(path);
2432
+ const res = Object.hasOwn(this.$__.activePaths.getStatePaths('modify'), path);
2426
2433
  if (res || path.indexOf('.') === -1) {
2427
2434
  return res;
2428
2435
  }
@@ -2461,7 +2468,7 @@ Document.prototype.isInit = function(path) {
2461
2468
  }
2462
2469
 
2463
2470
  if (typeof path === 'string' && path.indexOf(' ') === -1) {
2464
- return this.$__.activePaths.getStatePaths('init').hasOwnProperty(path);
2471
+ return Object.hasOwn(this.$__.activePaths.getStatePaths('init'), path);
2465
2472
  }
2466
2473
 
2467
2474
  let paths = path;
@@ -2469,7 +2476,7 @@ Document.prototype.isInit = function(path) {
2469
2476
  paths = paths.split(' ');
2470
2477
  }
2471
2478
 
2472
- return paths.some(path => this.$__.activePaths.getStatePaths('init').hasOwnProperty(path));
2479
+ return paths.some(path => Object.hasOwn(this.$__.activePaths.getStatePaths('init'), path));
2473
2480
  };
2474
2481
 
2475
2482
  /**
@@ -2607,7 +2614,7 @@ Document.prototype.isDirectSelected = function isDirectSelected(path) {
2607
2614
  return true;
2608
2615
  }
2609
2616
 
2610
- if (this.$__.selected.hasOwnProperty(path)) {
2617
+ if (Object.hasOwn(this.$__.selected, path)) {
2611
2618
  return inclusive;
2612
2619
  }
2613
2620
 
@@ -2779,7 +2786,7 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate
2779
2786
  if (doc.$isModified(fullPathToSubdoc, null, modifiedPaths) &&
2780
2787
  // Avoid using isDirectModified() here because that does additional checks on whether the parent path
2781
2788
  // is direct modified, which can cause performance issues re: gh-14897
2782
- !subdocParent.$__.activePaths.getStatePaths('modify').hasOwnProperty(fullPathToSubdoc) &&
2789
+ !Object.hasOwn(subdocParent.$__.activePaths.getStatePaths('modify'), fullPathToSubdoc) &&
2783
2790
  !subdocParent.$isDefault(fullPathToSubdoc)) {
2784
2791
  paths.add(fullPathToSubdoc);
2785
2792
 
@@ -2850,7 +2857,12 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate
2850
2857
  // Single nested paths (paths embedded under single nested subdocs) will
2851
2858
  // be validated on their own when we call `validate()` on the subdoc itself.
2852
2859
  // Re: gh-8468
2853
- Object.keys(flat).filter(path => !doc.$__schema.singleNestedPaths.hasOwnProperty(path)).forEach(addToPaths);
2860
+ const singleNestedPaths = doc.$__schema.singleNestedPaths;
2861
+ for (const path of Object.keys(flat)) {
2862
+ if (!Object.hasOwn(singleNestedPaths, path)) {
2863
+ addToPaths(path);
2864
+ }
2865
+ }
2854
2866
  }
2855
2867
  }
2856
2868
 
@@ -4188,7 +4200,7 @@ function applyVirtuals(self, json, options, toObjectOptions) {
4188
4200
  }
4189
4201
 
4190
4202
  // Allow skipping aliases with `toObject({ virtuals: true, aliases: false })`
4191
- if (!aliases && schema.aliases.hasOwnProperty(path)) {
4203
+ if (!aliases && Object.hasOwn(schema.aliases, path)) {
4192
4204
  continue;
4193
4205
  }
4194
4206
 
@@ -5101,7 +5113,7 @@ function checkDivergentArray(doc, path, array) {
5101
5113
  // would be similarly destructive as we never received all
5102
5114
  // elements of the array and potentially would overwrite data.
5103
5115
  const check = pop.options.match ||
5104
- pop.options.options && utils.object.hasOwnProperty(pop.options.options, 'limit') || // 0 is not permitted
5116
+ pop.options.options && Object.hasOwn(pop.options.options, 'limit') || // 0 is not permitted
5105
5117
  pop.options.options && pop.options.options.skip || // 0 is permitted
5106
5118
  pop.options.select && // deselected _id?
5107
5119
  (pop.options.select._id === 0 ||
@@ -5169,7 +5181,7 @@ function operand(self, where, delta, data, val, op) {
5169
5181
  if (/\.\d+\.|\.\d+$/.test(data.path)) {
5170
5182
  self.$__.version = VERSION_ALL;
5171
5183
  } else {
5172
- self.$__.version = VERSION_INC;
5184
+ self.$__.version |= VERSION_INC;
5173
5185
  }
5174
5186
  } else if (/^\$p/.test(op)) {
5175
5187
  // potentially changing array positions
@@ -5180,7 +5192,7 @@ function operand(self, where, delta, data, val, op) {
5180
5192
  } else if (/\.\d+\.|\.\d+$/.test(data.path)) {
5181
5193
  // now handling $set, $unset
5182
5194
  // subpath of array
5183
- self.$__.version = VERSION_WHERE;
5195
+ self.$__.version |= VERSION_WHERE;
5184
5196
  }
5185
5197
  }
5186
5198
 
@@ -5426,6 +5438,38 @@ Document.prototype.$__hasOnlyPrimitiveValues = function $__hasOnlyPrimitiveValue
5426
5438
  }));
5427
5439
  };
5428
5440
 
5441
+ /*!
5442
+ * Increment this document's version if necessary.
5443
+ */
5444
+
5445
+ Document.prototype._applyVersionIncrement = function _applyVersionIncrement() {
5446
+ if (!this.$__.version) return;
5447
+ const doIncrement = VERSION_INC === (VERSION_INC & this.$__.version);
5448
+
5449
+ this.$__.version = undefined;
5450
+ if (doIncrement) {
5451
+ const key = this.$__schema.options.versionKey;
5452
+ const version = this.$__getValue(key) || 0;
5453
+ this.$__setValue(key, version + 1); // increment version if was successful
5454
+ }
5455
+ };
5456
+
5457
+ /*!
5458
+ * Increment this document's version if necessary.
5459
+ */
5460
+
5461
+ Document.prototype._applyVersionIncrement = function _applyVersionIncrement() {
5462
+ if (!this.$__.version) return;
5463
+ const doIncrement = VERSION_INC === (VERSION_INC & this.$__.version);
5464
+
5465
+ this.$__.version = undefined;
5466
+ if (doIncrement) {
5467
+ const key = this.$__schema.options.versionKey;
5468
+ const version = this.$__getValue(key) || 0;
5469
+ this.$__setValue(key, version + 1); // increment version if was successful
5470
+ }
5471
+ };
5472
+
5429
5473
  /*!
5430
5474
  * Module exports.
5431
5475
  */
@@ -80,12 +80,6 @@ NativeCollection.prototype._getCollection = function _getCollection() {
80
80
  return null;
81
81
  };
82
82
 
83
- /*!
84
- * ignore
85
- */
86
-
87
- const syncCollectionMethods = { watch: true, find: true, aggregate: true };
88
-
89
83
  /**
90
84
  * Copy the collection methods and make them subject to queues
91
85
  * @param {Number|String} I
@@ -107,7 +101,6 @@ function iter(i) {
107
101
  _this.conn.options &&
108
102
  _this.conn.options.debug;
109
103
  const debug = connectionDebug == null ? globalDebug : connectionDebug;
110
- const lastArg = arguments[arguments.length - 1];
111
104
  const opId = new ObjectId();
112
105
 
113
106
  // If user force closed, queueing will hang forever. See #5664
@@ -122,8 +115,8 @@ function iter(i) {
122
115
  }
123
116
  }
124
117
 
125
- let _args = args;
126
- let callback = null;
118
+ let timeout = null;
119
+ let waitForBufferPromise = null;
127
120
  if (this._shouldBufferCommands() && this.buffer) {
128
121
  this.conn.emit('buffer', {
129
122
  _id: opId,
@@ -133,79 +126,28 @@ function iter(i) {
133
126
  args: args
134
127
  });
135
128
 
136
- let callback;
137
- let _args = args;
138
- let promise = null;
139
- let timeout = null;
140
- if (syncCollectionMethods[i] && typeof lastArg === 'function') {
141
- this.addQueue(i, _args);
142
- callback = lastArg;
143
- } else if (syncCollectionMethods[i]) {
144
- promise = new this.Promise((resolve, reject) => {
145
- callback = function collectionOperationCallback(err, res) {
146
- if (timeout != null) {
147
- clearTimeout(timeout);
148
- }
149
- if (err != null) {
150
- return reject(err);
151
- }
152
- resolve(res);
153
- };
154
- _args = args.concat([callback]);
155
- this.addQueue(i, _args);
156
- });
157
- } else if (typeof lastArg === 'function') {
158
- callback = function collectionOperationCallback() {
159
- if (timeout != null) {
160
- clearTimeout(timeout);
161
- }
162
- return lastArg.apply(this, arguments);
163
- };
164
- _args = args.slice(0, args.length - 1).concat([callback]);
165
- } else {
166
- promise = new Promise((resolve, reject) => {
167
- callback = function collectionOperationCallback(err, res) {
168
- if (timeout != null) {
169
- clearTimeout(timeout);
170
- }
171
- if (err != null) {
172
- return reject(err);
173
- }
174
- resolve(res);
175
- };
176
- _args = args.concat([callback]);
177
- this.addQueue(i, _args);
178
- });
179
- }
180
-
181
129
  const bufferTimeoutMS = this._getBufferTimeoutMS();
182
- timeout = setTimeout(() => {
183
- const removed = this.removeQueue(i, _args);
184
- if (removed) {
185
- const message = 'Operation `' + this.name + '.' + i + '()` buffering timed out after ' +
186
- bufferTimeoutMS + 'ms';
187
- const err = new MongooseError(message);
188
- this.conn.emit('buffer-end', { _id: opId, modelName: _this.modelName, collectionName: _this.name, method: i, error: err });
189
- callback(err);
190
- }
191
- }, bufferTimeoutMS);
192
-
193
- if (!syncCollectionMethods[i] && typeof lastArg === 'function') {
194
- this.addQueue(i, _args);
195
- return;
196
- }
130
+ waitForBufferPromise = new Promise((resolve, reject) => {
131
+ this.addQueue(resolve);
132
+
133
+ timeout = setTimeout(() => {
134
+ const removed = this.removeQueue(resolve);
135
+ if (removed) {
136
+ const message = 'Operation `' + this.name + '.' + i + '()` buffering timed out after ' +
137
+ bufferTimeoutMS + 'ms';
138
+ const err = new MongooseError(message);
139
+ this.conn.emit('buffer-end', { _id: opId, modelName: _this.modelName, collectionName: _this.name, method: i, error: err });
140
+ reject(err);
141
+ }
142
+ }, bufferTimeoutMS);
143
+ });
197
144
 
198
- return promise;
199
- } else if (!syncCollectionMethods[i] && typeof lastArg === 'function') {
200
- callback = function collectionOperationCallback(err, res) {
201
- if (err != null) {
202
- _this.conn.emit('operation-end', { _id: opId, modelName: _this.modelName, collectionName: _this.name, method: i, error: err });
203
- } else {
204
- _this.conn.emit('operation-end', { _id: opId, modelName: _this.modelName, collectionName: _this.name, method: i, result: res });
145
+ return waitForBufferPromise.then(() => {
146
+ if (timeout) {
147
+ clearTimeout(timeout);
205
148
  }
206
- return lastArg.apply(this, arguments);
207
- };
208
- _args = args.slice(0, args.length - 1).concat([callback]);
149
+ return this[i].apply(this, args);
150
+ });
209
151
  }
210
152
 
211
153
  if (debug) {
@@ -227,7 +169,7 @@ function iter(i) {
227
169
  }
228
170
  }
229
171
 
230
- this.conn.emit('operation-start', { _id: opId, modelName: _this.modelName, collectionName: this.name, method: i, params: _args });
172
+ this.conn.emit('operation-start', { _id: opId, modelName: _this.modelName, collectionName: this.name, method: i, params: args });
231
173
 
232
174
  try {
233
175
  if (collection == null) {
@@ -237,45 +179,37 @@ function iter(i) {
237
179
  throw new MongooseError(message);
238
180
  }
239
181
 
240
- if (syncCollectionMethods[i] && typeof lastArg === 'function') {
241
- const result = collection[i].apply(collection, _args.slice(0, _args.length - 1));
242
- this.conn.emit('operation-end', { _id: opId, modelName: _this.modelName, collectionName: this.name, method: i, result });
243
- return lastArg.call(this, null, result);
244
- }
245
-
246
- const ret = collection[i].apply(collection, _args);
182
+ const ret = collection[i].apply(collection, args);
247
183
  if (ret != null && typeof ret.then === 'function') {
248
184
  return ret.then(
249
185
  result => {
250
- if (typeof lastArg === 'function') {
251
- lastArg(null, result);
252
- } else {
253
- this.conn.emit('operation-end', { _id: opId, modelName: _this.modelName, collectionName: this.name, method: i, result });
186
+ if (timeout != null) {
187
+ clearTimeout(timeout);
254
188
  }
189
+ this.conn.emit('operation-end', { _id: opId, modelName: _this.modelName, collectionName: this.name, method: i, result });
255
190
  return result;
256
191
  },
257
192
  error => {
258
- if (typeof lastArg === 'function') {
259
- lastArg(error);
260
- return;
261
- } else {
262
- this.conn.emit('operation-end', { _id: opId, modelName: _this.modelName, collectionName: this.name, method: i, error });
193
+ if (timeout != null) {
194
+ clearTimeout(timeout);
263
195
  }
196
+ this.conn.emit('operation-end', { _id: opId, modelName: _this.modelName, collectionName: this.name, method: i, error });
264
197
  throw error;
265
198
  }
266
199
  );
267
200
  }
201
+
202
+ this.conn.emit('operation-end', { _id: opId, modelName: _this.modelName, collectionName: this.name, method: i, result: ret });
203
+ if (timeout != null) {
204
+ clearTimeout(timeout);
205
+ }
268
206
  return ret;
269
207
  } catch (error) {
270
- // Collection operation may throw because of max bson size, catch it here
271
- // See gh-3906
272
- if (typeof lastArg === 'function') {
273
- return lastArg(error);
274
- } else {
275
- this.conn.emit('operation-end', { _id: opId, modelName: _this.modelName, collectionName: this.name, method: i, error: error });
276
-
277
- throw error;
208
+ if (timeout != null) {
209
+ clearTimeout(timeout);
278
210
  }
211
+ this.conn.emit('operation-end', { _id: opId, modelName: _this.modelName, collectionName: this.name, method: i, error: error });
212
+ throw error;
279
213
  }
280
214
  };
281
215
  }
@@ -508,7 +508,7 @@ function _setClient(conn, client, options, dbName) {
508
508
  conn.onOpen();
509
509
 
510
510
  for (const i in conn.collections) {
511
- if (utils.object.hasOwnProperty(conn.collections, i)) {
511
+ if (Object.hasOwn(conn.collections, i)) {
512
512
  conn.collections[i].onOpen();
513
513
  }
514
514
  }
@@ -55,7 +55,7 @@ function flatten(update, path, options, schema) {
55
55
  if (isNested) {
56
56
  const paths = Object.keys(schema.paths);
57
57
  for (const p of paths) {
58
- if (p.startsWith(path + key + '.') && !result.hasOwnProperty(p)) {
58
+ if (p.startsWith(path + key + '.') && !Object.hasOwn(result, p)) {
59
59
  result[p] = void 0;
60
60
  }
61
61
  }
@@ -7,7 +7,7 @@ module.exports = function applySchemaCollation(indexKeys, indexOptions, schemaOp
7
7
  return;
8
8
  }
9
9
 
10
- if (schemaOptions.hasOwnProperty('collation') && !indexOptions.hasOwnProperty('collation')) {
10
+ if (Object.hasOwn(schemaOptions, 'collation') && !Object.hasOwn(indexOptions, 'collation')) {
11
11
  indexOptions.collation = schemaOptions.collation;
12
12
  }
13
13
  };
@@ -14,5 +14,5 @@ module.exports = function isDefaultIdIndex(index) {
14
14
  }
15
15
 
16
16
  const key = get(index, 'key', {});
17
- return Object.keys(key).length === 1 && key.hasOwnProperty('_id');
17
+ return Object.keys(key).length === 1 && Object.hasOwn(key, '_id');
18
18
  };
@@ -28,7 +28,7 @@ module.exports = function applyMethods(model, schema) {
28
28
  }
29
29
  for (const method of Object.keys(schema.methods)) {
30
30
  const fn = schema.methods[method];
31
- if (schema.tree.hasOwnProperty(method)) {
31
+ if (Object.hasOwn(schema.tree, method)) {
32
32
  throw new Error('You have a method and a property in your schema both ' +
33
33
  'named "' + method + '"');
34
34
  }
@@ -118,7 +118,10 @@ module.exports.castUpdateOne = function castUpdateOne(originalModel, updateOne,
118
118
  if (model.schema.$timestamps != null && doInitTimestamps) {
119
119
  const createdAt = model.schema.$timestamps.createdAt;
120
120
  const updatedAt = model.schema.$timestamps.updatedAt;
121
- applyTimestampsToUpdate(now, createdAt, updatedAt, update, {});
121
+ applyTimestampsToUpdate(now, createdAt, updatedAt, update, {
122
+ timestamps: updateOne.timestamps,
123
+ overwriteImmutable: updateOne.overwriteImmutable
124
+ });
122
125
  }
123
126
 
124
127
  if (doInitTimestamps) {
@@ -150,7 +153,8 @@ module.exports.castUpdateOne = function castUpdateOne(originalModel, updateOne,
150
153
  strict: strict,
151
154
  upsert: updateOne.upsert,
152
155
  arrayFilters: updateOne.arrayFilters,
153
- overwriteDiscriminatorKey: updateOne.overwriteDiscriminatorKey
156
+ overwriteDiscriminatorKey: updateOne.overwriteDiscriminatorKey,
157
+ overwriteImmutable: updateOne.overwriteImmutable
154
158
  }, model, updateOne['filter']);
155
159
 
156
160
  return updateOne;
@@ -185,7 +189,10 @@ module.exports.castUpdateMany = function castUpdateMany(originalModel, updateMan
185
189
  if (model.schema.$timestamps != null && doInitTimestamps) {
186
190
  const createdAt = model.schema.$timestamps.createdAt;
187
191
  const updatedAt = model.schema.$timestamps.updatedAt;
188
- applyTimestampsToUpdate(now, createdAt, updatedAt, updateMany['update'], {});
192
+ applyTimestampsToUpdate(now, createdAt, updatedAt, updateMany['update'], {
193
+ timestamps: updateMany.timestamps,
194
+ overwriteImmutable: updateMany.overwriteImmutable
195
+ });
189
196
  }
190
197
  if (doInitTimestamps) {
191
198
  applyTimestampsToChildren(now, updateMany['update'], model.schema);
@@ -208,7 +215,8 @@ module.exports.castUpdateMany = function castUpdateMany(originalModel, updateMan
208
215
  strict: strict,
209
216
  upsert: updateMany.upsert,
210
217
  arrayFilters: updateMany.arrayFilters,
211
- overwriteDiscriminatorKey: updateMany.overwriteDiscriminatorKey
218
+ overwriteDiscriminatorKey: updateMany.overwriteDiscriminatorKey,
219
+ overwriteImmutable: updateMany.overwriteImmutable
212
220
  }, model, updateMany['filter']);
213
221
  };
214
222
 
@@ -289,13 +297,12 @@ function _addDiscriminatorToObject(schema, obj) {
289
297
 
290
298
  function decideModelByObject(model, object) {
291
299
  const discriminatorKey = model.schema.options.discriminatorKey;
292
- if (object != null && object.hasOwnProperty(discriminatorKey)) {
300
+ if (object != null && Object.hasOwn(object, discriminatorKey)) {
293
301
  model = getDiscriminatorByValue(model.discriminators, object[discriminatorKey]) || model;
294
302
  }
295
303
  return model;
296
304
  }
297
305
 
298
-
299
306
  /**
300
307
  * gets timestamps option for a given operation. If the option is set within an individual operation, use it. Otherwise, use the global timestamps option configured in the `bulkWrite` options. Overall default is `true`.
301
308
  * @api private
@@ -386,13 +386,13 @@ function _virtualPopulate(model, docs, options, _virtualRes) {
386
386
  }
387
387
  data.count = virtual.options.count;
388
388
 
389
- if (virtual.options.skip != null && !options.hasOwnProperty('skip')) {
389
+ if (virtual.options.skip != null && !Object.hasOwn(options, 'skip')) {
390
390
  options.skip = virtual.options.skip;
391
391
  }
392
- if (virtual.options.limit != null && !options.hasOwnProperty('limit')) {
392
+ if (virtual.options.limit != null && !Object.hasOwn(options, 'limit')) {
393
393
  options.limit = virtual.options.limit;
394
394
  }
395
- if (virtual.options.perDocumentLimit != null && !options.hasOwnProperty('perDocumentLimit')) {
395
+ if (virtual.options.perDocumentLimit != null && !Object.hasOwn(options, 'perDocumentLimit')) {
396
396
  options.perDocumentLimit = virtual.options.perDocumentLimit;
397
397
  }
398
398
  let foreignField = virtual.options.foreignField;