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
@@ -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
@@ -97,17 +91,9 @@ function iter(i) {
97
91
  const collection = this._getCollection();
98
92
  const args = Array.from(arguments);
99
93
  const _this = this;
100
- const globalDebug = _this &&
101
- _this.conn &&
102
- _this.conn.base &&
103
- _this.conn.base.options &&
104
- _this.conn.base.options.debug;
105
- const connectionDebug = _this &&
106
- _this.conn &&
107
- _this.conn.options &&
108
- _this.conn.options.debug;
94
+ const globalDebug = _this?.conn?.base?.options?.debug;
95
+ const connectionDebug = _this?.conn?.options?.debug;
109
96
  const debug = connectionDebug == null ? globalDebug : connectionDebug;
110
- const lastArg = arguments[arguments.length - 1];
111
97
  const opId = new ObjectId();
112
98
 
113
99
  // If user force closed, queueing will hang forever. See #5664
@@ -122,9 +108,8 @@ function iter(i) {
122
108
  }
123
109
  }
124
110
 
125
- let _args = args;
126
- let callback = null;
127
111
  let timeout = null;
112
+ let waitForBufferPromise = null;
128
113
  if (this._shouldBufferCommands() && this.buffer) {
129
114
  this.conn.emit('buffer', {
130
115
  _id: opId,
@@ -134,78 +119,28 @@ function iter(i) {
134
119
  args: args
135
120
  });
136
121
 
137
- let callback;
138
- let _args = args;
139
- let promise = 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
122
  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
- }
123
+ waitForBufferPromise = new Promise((resolve, reject) => {
124
+ this.addQueue(resolve);
125
+
126
+ timeout = setTimeout(() => {
127
+ const removed = this.removeQueue(resolve);
128
+ if (removed) {
129
+ const message = 'Operation `' + this.name + '.' + i + '()` buffering timed out after ' +
130
+ bufferTimeoutMS + 'ms';
131
+ const err = new MongooseError(message);
132
+ this.conn.emit('buffer-end', { _id: opId, modelName: _this.modelName, collectionName: _this.name, method: i, error: err });
133
+ reject(err);
134
+ }
135
+ }, bufferTimeoutMS);
136
+ });
197
137
 
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 });
138
+ return waitForBufferPromise.then(() => {
139
+ if (timeout) {
140
+ clearTimeout(timeout);
205
141
  }
206
- return lastArg.apply(this, arguments);
207
- };
208
- _args = args.slice(0, args.length - 1).concat([callback]);
142
+ return this[i].apply(this, args);
143
+ });
209
144
  }
210
145
 
211
146
  if (debug) {
@@ -227,7 +162,7 @@ function iter(i) {
227
162
  }
228
163
  }
229
164
 
230
- this.conn.emit('operation-start', { _id: opId, modelName: _this.modelName, collectionName: this.name, method: i, params: _args });
165
+ this.conn.emit('operation-start', { _id: opId, modelName: _this.modelName, collectionName: this.name, method: i, params: args });
231
166
 
232
167
  try {
233
168
  if (collection == null) {
@@ -237,60 +172,37 @@ function iter(i) {
237
172
  throw new MongooseError(message);
238
173
  }
239
174
 
240
- if (syncCollectionMethods[i] && typeof lastArg === 'function') {
241
- const result = collection[i].apply(collection, _args.slice(0, _args.length - 1));
242
- if (timeout != null) {
243
- clearTimeout(timeout);
244
- }
245
- this.conn.emit('operation-end', { _id: opId, modelName: _this.modelName, collectionName: this.name, method: i, result });
246
- return lastArg.call(this, null, result);
247
- }
248
-
249
- const ret = collection[i].apply(collection, _args);
250
- if (ret != null && typeof ret.then === 'function') {
175
+ const ret = collection[i].apply(collection, args);
176
+ if (typeof ret?.then === 'function') {
251
177
  return ret.then(
252
178
  result => {
253
179
  if (timeout != null) {
254
180
  clearTimeout(timeout);
255
181
  }
256
- if (typeof lastArg === 'function') {
257
- lastArg(null, result);
258
- } else {
259
- this.conn.emit('operation-end', { _id: opId, modelName: _this.modelName, collectionName: this.name, method: i, result });
260
- }
182
+ this.conn.emit('operation-end', { _id: opId, modelName: _this.modelName, collectionName: this.name, method: i, result });
261
183
  return result;
262
184
  },
263
185
  error => {
264
186
  if (timeout != null) {
265
187
  clearTimeout(timeout);
266
188
  }
267
- if (typeof lastArg === 'function') {
268
- lastArg(error);
269
- return;
270
- } else {
271
- this.conn.emit('operation-end', { _id: opId, modelName: _this.modelName, collectionName: this.name, method: i, error });
272
- }
189
+ this.conn.emit('operation-end', { _id: opId, modelName: _this.modelName, collectionName: this.name, method: i, error });
273
190
  throw error;
274
191
  }
275
192
  );
276
193
  }
194
+
195
+ this.conn.emit('operation-end', { _id: opId, modelName: _this.modelName, collectionName: this.name, method: i, result: ret });
277
196
  if (timeout != null) {
278
197
  clearTimeout(timeout);
279
198
  }
280
199
  return ret;
281
200
  } catch (error) {
282
- // Collection operation may throw because of max bson size, catch it here
283
- // See gh-3906
284
201
  if (timeout != null) {
285
202
  clearTimeout(timeout);
286
203
  }
287
- if (typeof lastArg === 'function') {
288
- return lastArg(error);
289
- } else {
290
- this.conn.emit('operation-end', { _id: opId, modelName: _this.modelName, collectionName: this.name, method: i, error: error });
291
-
292
- throw error;
293
- }
204
+ this.conn.emit('operation-end', { _id: opId, modelName: _this.modelName, collectionName: this.name, method: i, error: error });
205
+ throw error;
294
206
  }
295
207
  };
296
208
  }
@@ -393,7 +305,7 @@ function formatDate(x, key, shell) {
393
305
  }
394
306
  }
395
307
  function format(obj, sub, color, shell) {
396
- if (obj && typeof obj.toBSON === 'function') {
308
+ if (typeof obj?.toBSON === 'function') {
397
309
  obj = obj.toBSON();
398
310
  }
399
311
  if (obj == null) {
@@ -443,12 +355,7 @@ function format(obj, sub, color, shell) {
443
355
  formatDate(x, key, shell);
444
356
  } else if (_constructorName === 'ClientSession') {
445
357
  x[key] = inspectable('ClientSession("' +
446
- (
447
- x[key] &&
448
- x[key].id &&
449
- x[key].id.id &&
450
- x[key].id.id.buffer || ''
451
- ).toString('hex') + '")');
358
+ (x[key]?.id?.id?.buffer || '').toString('hex') + '")');
452
359
  } else if (Array.isArray(x[key])) {
453
360
  x[key] = x[key].map(map);
454
361
  } else if (error != null) {
@@ -118,7 +118,7 @@ NativeConnection.prototype.useDb = function(name, options) {
118
118
  newConn.otherDbs.push(this);
119
119
 
120
120
  // push onto the relatedDbs cache, this is used when state changes
121
- if (options && options.useCache) {
121
+ if (options?.useCache) {
122
122
  this.relatedDbs[newConn.name] = newConn;
123
123
  newConn.relatedDbs = this.relatedDbs;
124
124
  }
@@ -251,9 +251,7 @@ NativeConnection.prototype.createClient = async function createClient(uri, optio
251
251
 
252
252
  if (options) {
253
253
 
254
- const autoIndex = options.config && options.config.autoIndex != null ?
255
- options.config.autoIndex :
256
- options.autoIndex;
254
+ const autoIndex = options.config?.autoIndex ?? options.autoIndex;
257
255
  if (autoIndex != null) {
258
256
  this.config.autoIndex = autoIndex !== false;
259
257
  delete options.config;
@@ -316,15 +314,15 @@ NativeConnection.prototype.createClient = async function createClient(uri, optio
316
314
 
317
315
  const { schemaMap, encryptedFieldsMap } = this._buildEncryptionSchemas();
318
316
 
319
- if ((Object.keys(schemaMap).length > 0 || Object.keys(encryptedFieldsMap).length) && !options.autoEncryption) {
317
+ if ((utils.hasOwnKeys(schemaMap) || utils.hasOwnKeys(encryptedFieldsMap)) && !options.autoEncryption) {
320
318
  throw new Error('Must provide `autoEncryption` when connecting with encrypted schemas.');
321
319
  }
322
320
 
323
- if (Object.keys(schemaMap).length > 0) {
321
+ if (utils.hasOwnKeys(schemaMap)) {
324
322
  options.autoEncryption.schemaMap = schemaMap;
325
323
  }
326
324
 
327
- if (Object.keys(encryptedFieldsMap).length > 0) {
325
+ if (utils.hasOwnKeys(encryptedFieldsMap)) {
328
326
  options.autoEncryption.encryptedFieldsMap = encryptedFieldsMap;
329
327
  }
330
328
 
@@ -435,18 +433,8 @@ function _setClient(conn, client, options, dbName) {
435
433
  const db = dbName != null ? client.db(dbName) : client.db();
436
434
  conn.db = db;
437
435
  conn.client = client;
438
- conn.host = client &&
439
- client.s &&
440
- client.s.options &&
441
- client.s.options.hosts &&
442
- client.s.options.hosts[0] &&
443
- client.s.options.hosts[0].host || void 0;
444
- conn.port = client &&
445
- client.s &&
446
- client.s.options &&
447
- client.s.options.hosts &&
448
- client.s.options.hosts[0] &&
449
- client.s.options.hosts[0].port || void 0;
436
+ conn.host = client?.s?.options?.hosts?.[0]?.host;
437
+ conn.port = client?.s?.options?.hosts?.[0]?.port;
450
438
  conn.name = dbName != null ? dbName : db.databaseName;
451
439
  conn._closeCalled = client._closeCalled;
452
440
 
@@ -463,10 +451,7 @@ function _setClient(conn, client, options, dbName) {
463
451
  }
464
452
  };
465
453
 
466
- const type = client &&
467
- client.topology &&
468
- client.topology.description &&
469
- client.topology.description.type || '';
454
+ const type = client?.topology?.description?.type || '';
470
455
 
471
456
  if (type === 'Single') {
472
457
  client.on('serverDescriptionChanged', ev => {
package/lib/error/cast.js CHANGED
@@ -109,7 +109,7 @@ function getValueType(value) {
109
109
  }
110
110
 
111
111
  function getMessageFormat(schemaType) {
112
- const messageFormat = schemaType && schemaType._castErrorMessage || null;
112
+ const messageFormat = schemaType?._castErrorMessage || null;
113
113
  if (typeof messageFormat === 'string' || typeof messageFormat === 'function') {
114
114
  return messageFormat;
115
115
  }
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  module.exports = function prepareDiscriminatorPipeline(pipeline, schema, prefix) {
4
- const discriminatorMapping = schema && schema.discriminatorMapping;
4
+ const discriminatorMapping = schema?.discriminatorMapping;
5
5
  prefix = prefix || '';
6
6
 
7
7
  if (discriminatorMapping && !discriminatorMapping.isRoot) {
@@ -18,12 +18,12 @@ module.exports = function prepareDiscriminatorPipeline(pipeline, schema, prefix)
18
18
  originalPipeline[0].$match[filterKey] = discriminatorValue;
19
19
  // `originalPipeline` is a ref, so there's no need for
20
20
  // aggregate._pipeline = originalPipeline
21
- } else if (originalPipeline[0] != null && originalPipeline[0].$geoNear) {
21
+ } else if (originalPipeline[0]?.$geoNear) {
22
22
  originalPipeline[0].$geoNear.query =
23
23
  originalPipeline[0].$geoNear.query || {};
24
24
  originalPipeline[0].$geoNear.query[filterKey] = discriminatorValue;
25
- } else if (originalPipeline[0] != null && originalPipeline[0].$search) {
26
- if (originalPipeline[1] && originalPipeline[1].$match != null) {
25
+ } else if (originalPipeline[0]?.$search) {
26
+ if (originalPipeline[1]?.$match != null) {
27
27
  originalPipeline[1].$match[filterKey] = originalPipeline[1].$match[filterKey] || discriminatorValue;
28
28
  } else {
29
29
  const match = {};
@@ -53,7 +53,7 @@ function clone(obj, options, isArrayChild) {
53
53
  if (obj.__parentArray != null) {
54
54
  clonedDoc.__parentArray = obj.__parentArray;
55
55
  }
56
- clonedDoc.$__parent = obj.$__parent;
56
+ clonedDoc.$__setParent(options.parentDoc ?? obj.$__parent);
57
57
  return clonedDoc;
58
58
  }
59
59
  }
@@ -63,7 +63,7 @@ function clone(obj, options, isArrayChild) {
63
63
  }
64
64
 
65
65
  let ret;
66
- if (options && options.json && typeof obj.toJSON === 'function') {
66
+ if (options?.json && typeof obj.toJSON === 'function') {
67
67
  ret = obj.toJSON(options);
68
68
  } else {
69
69
  ret = obj.toObject(options);
@@ -89,14 +89,14 @@ function clone(obj, options, isArrayChild) {
89
89
  }
90
90
 
91
91
  if (isBsonType(obj, 'ObjectId')) {
92
- if (options && options.flattenObjectIds) {
92
+ if (options?.flattenObjectIds) {
93
93
  return obj.toJSON();
94
94
  }
95
95
  return new ObjectId(obj.id);
96
96
  }
97
97
 
98
98
  if (isBsonType(obj, 'Decimal128')) {
99
- if (options && options.flattenDecimals) {
99
+ if (options?.flattenDecimals) {
100
100
  return obj.toJSON();
101
101
  }
102
102
  return Decimal.fromString(obj.toString());
@@ -114,7 +114,7 @@ function clone(obj, options, isArrayChild) {
114
114
  // If we're cloning this object to go into a MongoDB command,
115
115
  // and there's a `toBSON()` function, assume this object will be
116
116
  // stored as a primitive in MongoDB and doesn't need to be cloned.
117
- if (options && options.bson && typeof obj.toBSON === 'function') {
117
+ if (options?.bson && typeof obj.toBSON === 'function') {
118
118
  return obj;
119
119
  }
120
120
 
@@ -131,9 +131,9 @@ module.exports = clone;
131
131
  */
132
132
 
133
133
  function cloneObject(obj, options, isArrayChild) {
134
- const minimize = options && options.minimize;
135
- const omitUndefined = options && options.omitUndefined;
136
- const seen = options && options._seen;
134
+ const minimize = options?.minimize;
135
+ const omitUndefined = options?.omitUndefined;
136
+ const seen = options?._seen;
137
137
  const ret = {};
138
138
  let hasKeys;
139
139
 
@@ -35,12 +35,12 @@ function flatten(update, path, options, schema) {
35
35
  result[path + key] = val;
36
36
 
37
37
  // Avoid going into mixed paths if schema is specified
38
- const keySchema = schema && schema.path && schema.path(path + key);
39
- const isNested = schema && schema.nested && schema.nested[path + key];
40
- if (keySchema && keySchema.instance === 'Mixed') continue;
38
+ const keySchema = schema?.path?.(path + key);
39
+ const isNested = schema?.nested?.[path + key];
40
+ if (keySchema?.instance === 'Mixed') continue;
41
41
 
42
42
  if (shouldFlatten(val)) {
43
- if (options && options.skipArrays && Array.isArray(val)) {
43
+ if (options?.skipArrays && Array.isArray(val)) {
44
44
  continue;
45
45
  }
46
46
  const flat = flatten(val, path + key, options, schema);
@@ -174,7 +174,7 @@ module.exports = async function eachAsync(next, fn, options) {
174
174
  } catch (err) {
175
175
  return callback(err);
176
176
  }
177
- if (maybePromise && typeof maybePromise.then === 'function') {
177
+ if (typeof maybePromise?.then === 'function') {
178
178
  maybePromise.then(
179
179
  function() { callback(null); },
180
180
  function(error) {
@@ -9,7 +9,7 @@ const getDiscriminatorByValue = require('./getDiscriminatorByValue');
9
9
 
10
10
  module.exports = function getConstructor(Constructor, value, defaultDiscriminatorValue) {
11
11
  const discriminatorKey = Constructor.schema.options.discriminatorKey;
12
- let discriminatorValue = (value != null && value[discriminatorKey]);
12
+ let discriminatorValue = value?.[discriminatorKey];
13
13
  if (discriminatorValue == null) {
14
14
  discriminatorValue = defaultDiscriminatorValue;
15
15
  }
@@ -11,7 +11,7 @@ const areDiscriminatorValuesEqual = require('./areDiscriminatorValuesEqual');
11
11
  */
12
12
 
13
13
  module.exports = function getSchemaDiscriminatorByValue(schema, value) {
14
- if (schema == null || schema.discriminators == null) {
14
+ if (schema?.discriminators == null) {
15
15
  return null;
16
16
  }
17
17
  for (const key of Object.keys(schema.discriminators)) {
@@ -40,7 +40,7 @@ module.exports = function mergeDiscriminatorSchema(to, from, path, seen) {
40
40
  continue;
41
41
  }
42
42
  }
43
- if (path === 'tree' && from != null && from.instanceOfSchema) {
43
+ if (path === 'tree' && from?.instanceOfSchema) {
44
44
  continue;
45
45
  }
46
46
  if (specialProperties.has(key)) {
@@ -85,7 +85,7 @@ module.exports = function mergeDiscriminatorSchema(to, from, path, seen) {
85
85
  }
86
86
  }
87
87
 
88
- if (from != null && from.instanceOfSchema) {
88
+ if (from?.instanceOfSchema) {
89
89
  to.tree = Object.assign({}, from.tree, to.tree);
90
90
  }
91
91
  };
@@ -5,7 +5,7 @@ const isNestedProjection = require('../projection/isNestedProjection');
5
5
  module.exports = function applyDefaults(doc, fields, exclude, hasIncludedChildren, isBeforeSetters, pathsToSkip, options) {
6
6
  const paths = Object.keys(doc.$__schema.paths);
7
7
  const plen = paths.length;
8
- const skipParentChangeTracking = options && options.skipParentChangeTracking;
8
+ const skipParentChangeTracking = options?.skipParentChangeTracking;
9
9
 
10
10
  for (let i = 0; i < plen; ++i) {
11
11
  let def;
@@ -2,6 +2,7 @@
2
2
 
3
3
  const handleTimestampOption = require('../schema/handleTimestampOption');
4
4
  const mpath = require('mpath');
5
+ const utils = require('../../utils');
5
6
 
6
7
  module.exports = applyTimestamps;
7
8
 
@@ -71,7 +72,7 @@ function applyTimestampsToDoc(schema, obj, options) {
71
72
  return;
72
73
  }
73
74
 
74
- if (schema.discriminators && Object.keys(schema.discriminators).length > 0) {
75
+ if (schema.discriminators && utils.hasOwnKeys(schema.discriminators)) {
75
76
  for (const discriminatorKey of Object.keys(schema.discriminators)) {
76
77
  const discriminator = schema.discriminators[discriminatorKey];
77
78
  const key = discriminator.discriminatorMapping.key;
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const mpath = require('mpath');
4
+ const utils = require('../../utils');
4
5
 
5
6
  module.exports = applyVirtuals;
6
7
 
@@ -76,7 +77,7 @@ function applyVirtualsToChildren(schema, res, virtuals) {
76
77
  attachedVirtuals = true;
77
78
  }
78
79
 
79
- if (virtuals && virtuals.length && !attachedVirtuals) {
80
+ if (virtuals?.length && !attachedVirtuals) {
80
81
  applyVirtualsToDoc(schema, res, virtuals);
81
82
  }
82
83
  }
@@ -101,7 +102,7 @@ function applyVirtualsToDoc(schema, obj, virtuals) {
101
102
  return;
102
103
  }
103
104
 
104
- if (schema.discriminators && Object.keys(schema.discriminators).length > 0) {
105
+ if (schema.discriminators && utils.hasOwnKeys(schema.discriminators)) {
105
106
  for (const discriminatorKey of Object.keys(schema.discriminators)) {
106
107
  const discriminator = schema.discriminators[discriminatorKey];
107
108
  const key = discriminator.discriminatorMapping.key;
@@ -133,7 +134,7 @@ function applyVirtualsToDoc(schema, obj, virtuals) {
133
134
  }
134
135
  let val = virtualType.applyGetters(cur[sp[sp.length - 1]], obj);
135
136
  const isPopulateVirtual =
136
- virtualType.options && (virtualType.options.ref || virtualType.options.refPath);
137
+ virtualType.options?.ref || virtualType.options?.refPath;
137
138
  if (isPopulateVirtual && val === undefined) {
138
139
  if (virtualType.options.justOne) {
139
140
  val = null;
@@ -16,7 +16,7 @@ module.exports = function cleanModifiedSubpaths(doc, path, options) {
16
16
  for (const modifiedPath of Object.keys(doc.$__.activePaths.getStatePaths('modify'))) {
17
17
  if (skipDocArrays) {
18
18
  const schemaType = doc.$__schema.path(modifiedPath);
19
- if (schemaType && schemaType.$isMongooseDocumentArray) {
19
+ if (schemaType?.$isMongooseDocumentArray) {
20
20
  continue;
21
21
  }
22
22
  }
@@ -46,7 +46,7 @@ function compile(tree, proto, prefix, options) {
46
46
  const limb = tree[key];
47
47
 
48
48
  const hasSubprops = isPOJO(limb) &&
49
- Object.keys(limb).length > 0 &&
49
+ utils.hasOwnKeys(limb) &&
50
50
  (!limb[typeKey] || (typeKey === 'type' && isPOJO(limb.type) && limb.type.type));
51
51
  const subprops = hasSubprops ? limb : null;
52
52
 
@@ -132,7 +132,7 @@ function defineKey({ prop, subprops, prototype, prefix, options }) {
132
132
  writable: false,
133
133
  value: function() {
134
134
  return _this.get(path, null, {
135
- virtuals: this && this.schema && this.schema.options && this.schema.options.toObject && this.schema.options.toObject.virtuals || null
135
+ virtuals: this?.schema?.options?.toObject?.virtuals || null
136
136
  });
137
137
  }
138
138
  });
@@ -143,7 +143,7 @@ function defineKey({ prop, subprops, prototype, prefix, options }) {
143
143
  writable: false,
144
144
  value: function() {
145
145
  return _this.get(path, null, {
146
- virtuals: this && this.schema && this.schema.options && this.schema.options.toJSON && this.schema.options.toJSON.virtuals || null
146
+ virtuals: this?.schema?.options?.toJSON?.virtuals || null
147
147
  });
148
148
  }
149
149
  });
@@ -178,7 +178,7 @@ function defineKey({ prop, subprops, prototype, prefix, options }) {
178
178
  return this.$__.getters[path];
179
179
  },
180
180
  set: function(v) {
181
- if (v != null && v.$__isNested) {
181
+ if (v?.$__isNested) {
182
182
  // Convert top-level to POJO, but leave subdocs hydrated so `$set`
183
183
  // can handle them. See gh-9293.
184
184
  v = v.$__get();
@@ -17,7 +17,7 @@ module.exports = function getDeepestSubdocumentForPath(doc, parts, schema) {
17
17
  let subdoc = doc;
18
18
  for (let i = 0; i < parts.length - 1; ++i) {
19
19
  const curSchemaType = curSchema.path(curPath);
20
- if (curSchemaType && curSchemaType.schema) {
20
+ if (curSchemaType?.schema) {
21
21
  let newSubdoc = subdoc.get(curPath);
22
22
  curSchema = curSchemaType.schema;
23
23
  curPath = parts[i + 1];
@@ -4,7 +4,7 @@ module.exports = function decorateDiscriminatorIndexOptions(schema, indexOptions
4
4
  // If the model is a discriminator and has an index, add a
5
5
  // partialFilterExpression by default so the index will only apply
6
6
  // to that discriminator.
7
- const discriminatorName = schema.discriminatorMapping && schema.discriminatorMapping.value;
7
+ const discriminatorName = schema.discriminatorMapping?.value;
8
8
  if (discriminatorName && !('sparse' in indexOptions)) {
9
9
  const discriminatorKey = schema.options.discriminatorKey;
10
10
  indexOptions.partialFilterExpression = indexOptions.partialFilterExpression || {};
@@ -31,8 +31,8 @@ function getRelatedIndexes({
31
31
  indexes,
32
32
  indexesType
33
33
  }) {
34
- const discriminatorKey = discriminatorMapping && discriminatorMapping.key;
35
- const discriminatorValue = discriminatorMapping && discriminatorMapping.value;
34
+ const discriminatorKey = discriminatorMapping?.key;
35
+ const discriminatorValue = discriminatorMapping?.value;
36
36
 
37
37
  if (!discriminatorKey) {
38
38
  return indexes;
@@ -57,7 +57,7 @@ function getRelatedIndexes({
57
57
  function getPartialFilterExpression(index, indexesType) {
58
58
  if (indexesType === 'schema') {
59
59
  const options = index[1];
60
- return options && options.partialFilterExpression;
60
+ return options?.partialFilterExpression;
61
61
  }
62
62
  return index.partialFilterExpression;
63
63
  }