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
@@ -107,7 +107,7 @@ module.exports.castUpdateOne = function castUpdateOne(originalModel, updateOne,
107
107
 
108
108
  const model = decideModelByObject(originalModel, updateOne['filter']);
109
109
  const schema = model.schema;
110
- const strict = options.strict != null ? options.strict : model.schema.options.strict;
110
+ const strict = options.strict ?? model.schema.options.strict;
111
111
 
112
112
  const update = clone(updateOne['update']);
113
113
 
@@ -129,9 +129,7 @@ module.exports.castUpdateOne = function castUpdateOne(originalModel, updateOne,
129
129
  }
130
130
 
131
131
  const globalSetDefaultsOnInsert = originalModel.base.options.setDefaultsOnInsert;
132
- const shouldSetDefaultsOnInsert = updateOne.setDefaultsOnInsert == null ?
133
- globalSetDefaultsOnInsert :
134
- updateOne.setDefaultsOnInsert;
132
+ const shouldSetDefaultsOnInsert = updateOne.setDefaultsOnInsert ?? globalSetDefaultsOnInsert;
135
133
  if (shouldSetDefaultsOnInsert !== false) {
136
134
  setDefaultsOnInsert(updateOne['filter'], model.schema, update, {
137
135
  setDefaultsOnInsert: true,
@@ -170,12 +168,10 @@ module.exports.castUpdateMany = function castUpdateMany(originalModel, updateMan
170
168
 
171
169
  const model = decideModelByObject(originalModel, updateMany['filter']);
172
170
  const schema = model.schema;
173
- const strict = options.strict != null ? options.strict : model.schema.options.strict;
171
+ const strict = options.strict ?? model.schema.options.strict;
174
172
 
175
173
  const globalSetDefaultsOnInsert = originalModel.base.options.setDefaultsOnInsert;
176
- const shouldSetDefaultsOnInsert = updateMany.setDefaultsOnInsert == null ?
177
- globalSetDefaultsOnInsert :
178
- updateMany.setDefaultsOnInsert;
174
+ const shouldSetDefaultsOnInsert = updateMany.setDefaultsOnInsert ?? globalSetDefaultsOnInsert;
179
175
 
180
176
  if (shouldSetDefaultsOnInsert !== false) {
181
177
  setDefaultsOnInsert(updateMany['filter'], model.schema, updateMany['update'], {
@@ -223,7 +219,7 @@ module.exports.castUpdateMany = function castUpdateMany(originalModel, updateMan
223
219
  module.exports.castReplaceOne = async function castReplaceOne(originalModel, replaceOne, options) {
224
220
  const model = decideModelByObject(originalModel, replaceOne['filter']);
225
221
  const schema = model.schema;
226
- const strict = options.strict != null ? options.strict : model.schema.options.strict;
222
+ const strict = options.strict ?? model.schema.options.strict;
227
223
 
228
224
  _addDiscriminatorToObject(schema, replaceOne['filter']);
229
225
  replaceOne['filter'] = cast(model.schema, replaceOne['filter'], {
@@ -68,7 +68,7 @@ function validateDiscriminatorSchemasForEncryption(parentSchema, childSchema) {
68
68
  */
69
69
 
70
70
  module.exports = function discriminator(model, name, schema, tiedValue, applyPlugins, mergeHooks, overwriteExisting) {
71
- if (!(schema && schema.instanceOfSchema)) {
71
+ if (!schema?.instanceOfSchema) {
72
72
  throw new Error('You must pass a valid discriminator Schema');
73
73
  }
74
74
 
@@ -104,7 +104,7 @@ function assignRawDocsToIdStructure(rawIds, resultDocs, resultOrder, options, re
104
104
  } else {
105
105
  newOrder.push(doc);
106
106
  }
107
- } else if (id != null && id[modelSymbol] != null) {
107
+ } else if (id?.[modelSymbol] != null) {
108
108
  newOrder.push(id);
109
109
  } else {
110
110
  newOrder.push(options.retainNullValues || nullIfNotFound ? null : id);
@@ -129,11 +129,11 @@ module.exports = function assignVals(o) {
129
129
 
130
130
  if (isDoc && Array.isArray(valueToSet)) {
131
131
  for (const val of valueToSet) {
132
- if (val != null && val.$__ != null) {
132
+ if (val?.$__ != null) {
133
133
  val.$__.parent = docs[i];
134
134
  }
135
135
  }
136
- } else if (isDoc && valueToSet != null && valueToSet.$__ != null) {
136
+ } else if (isDoc && valueToSet?.$__ != null) {
137
137
  valueToSet.$__.parent = docs[i];
138
138
  }
139
139
 
@@ -184,7 +184,7 @@ module.exports = function assignVals(o) {
184
184
  // See gh-8342, gh-8455
185
185
  const curPath = parts.slice(0, j + 1).join('.');
186
186
  const schematype = originalSchema._getSchema(curPath);
187
- if (valueToSet == null && schematype != null && schematype.$isMongooseArray) {
187
+ if (valueToSet == null && schematype?.$isMongooseArray) {
188
188
  break;
189
189
  }
190
190
  cur[parts[j]] = {};
@@ -200,7 +200,7 @@ module.exports = function assignVals(o) {
200
200
  o.allOptions.options[populateModelSymbol] = o.allOptions.model;
201
201
  docs[i].$populated(_path, o.unpopulatedValues[i], o.allOptions.options);
202
202
 
203
- if (valueToSet != null && valueToSet.$__ != null) {
203
+ if (valueToSet?.$__ != null) {
204
204
  valueToSet.$__.wasPopulated = { value: o.unpopulatedValues[i] };
205
205
  }
206
206
 
@@ -22,10 +22,11 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {
22
22
  let doc;
23
23
  const len = docs.length;
24
24
  const map = [];
25
- const modelNameFromQuery = options.model && options.model.modelName || options.model;
25
+ const modelNameFromQuery = options.model?.modelName || options.model;
26
26
  let schema;
27
27
  let refPath;
28
28
  let modelNames;
29
+ let modelNamesSet;
29
30
  const available = {};
30
31
 
31
32
  const modelSchema = model.schema;
@@ -55,13 +56,13 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {
55
56
  let justOne = null;
56
57
 
57
58
  if (doc.$__ != null && doc.populated(options.path)) {
58
- const forceRepopulate = options.forceRepopulate != null ? options.forceRepopulate : doc.constructor.base.options.forceRepopulate;
59
+ const forceRepopulate = options.forceRepopulate ?? doc.constructor.base.options.forceRepopulate;
59
60
  if (forceRepopulate === false) {
60
61
  continue;
61
62
  }
62
63
  }
63
64
 
64
- const docSchema = doc != null && doc.$__ != null ? doc.$__schema : modelSchema;
65
+ const docSchema = doc?.$__ != null ? doc.$__schema : modelSchema;
65
66
  schema = getSchemaTypes(model, docSchema, doc, options.path);
66
67
 
67
68
  // Special case: populating a path that's a DocumentArray unless
@@ -72,7 +73,7 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {
72
73
  schema.options.refPath == null) {
73
74
  continue;
74
75
  }
75
- const isUnderneathDocArray = schema && schema.$parentSchemaDocArray;
76
+ const isUnderneathDocArray = schema?.$parentSchemaDocArray;
76
77
  if (isUnderneathDocArray && get(options, 'options.sort') != null) {
77
78
  return new MongooseError('Cannot populate with `sort` on path ' + options.path +
78
79
  ' because it is a subproperty of a document array');
@@ -84,7 +85,7 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {
84
85
  let schemaOptions = null;
85
86
  let modelNamesInOrder = null;
86
87
 
87
- if (schema != null && schema.instance === 'Embedded') {
88
+ if (schema?.instance === 'Embedded') {
88
89
  if (schema.options.ref) {
89
90
  const data = {
90
91
  localField: options.path + '._id',
@@ -123,8 +124,10 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {
123
124
  continue;
124
125
  }
125
126
  modelNames = modelNames || [];
127
+ modelNamesSet = modelNamesSet || new Set();
126
128
  for (const modelName of _modelNames) {
127
- if (modelNames.indexOf(modelName) === -1) {
129
+ if (modelNamesSet.has(modelName) === false) {
130
+ modelNamesSet.add(modelName);
128
131
  modelNames.push(modelName);
129
132
  }
130
133
  }
@@ -218,15 +221,15 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {
218
221
  let justOne = null;
219
222
 
220
223
  const originalSchema = schema;
221
- if (schema && schema.instance === 'Array') {
224
+ if (schema?.instance === 'Array') {
222
225
  schema = schema.embeddedSchemaType;
223
226
  }
224
- if (schema && schema.$isSchemaMap) {
227
+ if (schema?.$isSchemaMap) {
225
228
  schema = schema.$__schemaType;
226
229
  }
227
230
 
228
- const ref = schema && schema.options && schema.options.ref;
229
- refPath = schema && schema.options && schema.options.refPath;
231
+ const ref = schema?.options?.ref;
232
+ refPath = schema?.options?.refPath;
230
233
  if (schema != null &&
231
234
  schema[schemaMixedSymbol] &&
232
235
  !ref &&
@@ -281,7 +284,7 @@ module.exports = function getModelsMapForPopulate(model, docs, options) {
281
284
 
282
285
  schemaForCurrentDoc = modelForCurrentDoc.schema._getSchema(options.path);
283
286
 
284
- if (schemaForCurrentDoc && schemaForCurrentDoc.embeddedSchemaType) {
287
+ if (schemaForCurrentDoc?.embeddedSchemaType) {
285
288
  schemaForCurrentDoc = schemaForCurrentDoc.embeddedSchemaType;
286
289
  }
287
290
  } else {
@@ -485,7 +488,7 @@ function _virtualPopulate(model, docs, options, _virtualRes) {
485
488
  function addModelNamesToMap(model, map, available, modelNames, options, data, ret, doc, schemaOptions, unpopulatedValue) {
486
489
  // `PopulateOptions#connection`: if the model is passed as a string, the
487
490
  // connection matters because different connections have different models.
488
- const connection = options.connection != null ? options.connection : model.db;
491
+ const connection = options.connection ?? model.db;
489
492
 
490
493
  unpopulatedValue = unpopulatedValue === void 0 ? ret : unpopulatedValue;
491
494
  if (Array.isArray(unpopulatedValue)) {
@@ -523,7 +526,7 @@ function addModelNamesToMap(model, map, available, modelNames, options, data, re
523
526
 
524
527
  let ids = ret;
525
528
 
526
- const modelNamesForRefPath = data.modelNamesInOrder ? data.modelNamesInOrder : modelNames;
529
+ const modelNamesForRefPath = data.modelNamesInOrder || modelNames;
527
530
  if (data.isRefPath && Array.isArray(ret) && ret.length === modelNamesForRefPath.length) {
528
531
  ids = matchIdsToRefPaths(ret, modelNamesForRefPath, modelName);
529
532
  }
@@ -622,10 +625,9 @@ function _getLocalFieldValues(doc, localField, model, options, virtual, schema)
622
625
  const localFieldPath = localFieldPathType === 'real' ?
623
626
  model.schema.path(localField) :
624
627
  localFieldPathType.schema;
625
- const localFieldGetters = localFieldPath && localFieldPath.getters ?
626
- localFieldPath.getters : [];
628
+ const localFieldGetters = localFieldPath?.getters || [];
627
629
 
628
- localField = localFieldPath != null && localFieldPath.instance === 'Embedded' ? localField + '._id' : localField;
630
+ localField = localFieldPath?.instance === 'Embedded' ? localField + '._id' : localField;
629
631
 
630
632
  const _populateOptions = get(options, 'options', {});
631
633
 
@@ -657,17 +659,17 @@ function _getLocalFieldValues(doc, localField, model, options, virtual, schema)
657
659
  */
658
660
 
659
661
  function convertTo_id(val, schema) {
660
- if (val != null && val.$__ != null) {
662
+ if (val?.$__ != null) {
661
663
  return val._doc._id;
662
664
  }
663
- if (val != null && val._id != null && (schema == null || !schema.$isSchemaMap)) {
665
+ if (val?._id != null && !schema?.$isSchemaMap) {
664
666
  return val._id;
665
667
  }
666
668
 
667
669
  if (Array.isArray(val)) {
668
- const rawVal = val.__array != null ? val.__array : val;
670
+ const rawVal = val.__array ?? val;
669
671
  for (let i = 0; i < rawVal.length; ++i) {
670
- if (rawVal[i] != null && rawVal[i].$__ != null) {
672
+ if (rawVal[i]?.$__ != null) {
671
673
  rawVal[i] = rawVal[i]._doc._id;
672
674
  }
673
675
  }
@@ -683,7 +685,7 @@ function convertTo_id(val, schema) {
683
685
  if (getConstructorName(val) === 'Object' &&
684
686
  // The intent here is we should only flatten the object if we expect
685
687
  // to get a Map in the end. Avoid doing this for mixed types.
686
- (schema == null || schema[schemaMixedSymbol] == null)) {
688
+ schema?.[schemaMixedSymbol] == null) {
687
689
  const ret = [];
688
690
  for (const key of Object.keys(val)) {
689
691
  ret.push(val[key]);
@@ -721,7 +723,7 @@ function _findRefPathForDiscriminators(doc, modelSchema, data, options, normaliz
721
723
  if (schematype != null &&
722
724
  schematype.$isMongooseDocumentArray &&
723
725
  schematype.Constructor.discriminators != null &&
724
- Object.keys(schematype.Constructor.discriminators).length !== 0) {
726
+ utils.hasOwnKeys(schematype.Constructor.discriminators)) {
725
727
  const subdocs = utils.getValue(cur, doc);
726
728
  const remnant = options.path.substring(cur.length + 1);
727
729
  const discriminatorKey = schematype.Constructor.schema.options.discriminatorKey;
@@ -729,7 +731,7 @@ function _findRefPathForDiscriminators(doc, modelSchema, data, options, normaliz
729
731
  for (const subdoc of subdocs) {
730
732
  const discriminatorName = utils.getValue(discriminatorKey, subdoc);
731
733
  const discriminator = schematype.Constructor.discriminators[discriminatorName];
732
- const discriminatorSchema = discriminator && discriminator.schema;
734
+ const discriminatorSchema = discriminator?.schema;
733
735
  if (discriminatorSchema == null) {
734
736
  continue;
735
737
  }
@@ -32,12 +32,11 @@ module.exports = function getSchemaTypes(model, schema, doc, path) {
32
32
  return pathschema;
33
33
  }
34
34
 
35
- const discriminatorKey = schema.discriminatorMapping &&
36
- schema.discriminatorMapping.key;
35
+ const discriminatorKey = schema.discriminatorMapping?.key;
37
36
  if (discriminatorKey && model != null) {
38
- if (doc != null && doc[discriminatorKey] != null) {
37
+ if (doc?.[discriminatorKey] != null) {
39
38
  const discriminator = getDiscriminatorByValue(model.discriminators, doc[discriminatorKey]);
40
- schema = discriminator ? discriminator.schema : schema;
39
+ schema = discriminator?.schema || schema;
41
40
  } else if (model.discriminators != null) {
42
41
  return Object.keys(model.discriminators).reduce((arr, name) => {
43
42
  const disc = model.discriminators[name];
@@ -65,7 +64,7 @@ module.exports = function getSchemaTypes(model, schema, doc, path) {
65
64
  }
66
65
 
67
66
  let schemas = null;
68
- if (foundschema.schema != null && foundschema.schema.discriminators != null) {
67
+ if (foundschema.schema?.discriminators != null) {
69
68
  const discriminators = foundschema.schema.discriminators;
70
69
  const discriminatorKeyPath = trypath + '.' +
71
70
  foundschema.schema.options.discriminatorKey;
@@ -178,7 +177,7 @@ module.exports = function getSchemaTypes(model, schema, doc, path) {
178
177
  }
179
178
 
180
179
  const fullPath = nestedPath.concat([trypath]).join('.');
181
- if (topLevelDoc != null && topLevelDoc.$__ && topLevelDoc.$populated(fullPath, true) && p < parts.length) {
180
+ if (topLevelDoc?.$__ && topLevelDoc.$populated(fullPath, true) && p < parts.length) {
182
181
  const model = topLevelDoc.$populated(fullPath, true).options[populateModelSymbol];
183
182
  if (model != null) {
184
183
  const ret = search(
@@ -198,7 +197,7 @@ module.exports = function getSchemaTypes(model, schema, doc, path) {
198
197
  leanPopulateMap.get(_val[0]) :
199
198
  leanPopulateMap.get(_val);
200
199
  // Populated using lean, `leanPopulateMap` value is the foreign model
201
- const schema = model != null ? model.schema : null;
200
+ const schema = model?.schema ?? null;
202
201
  if (schema != null) {
203
202
  const ret = search(
204
203
  parts.slice(p),
@@ -11,7 +11,7 @@ if (typeof jest !== 'undefined' && !process.env.SUPPRESS_JEST_WARNINGS) {
11
11
  'to hide this warning.');
12
12
  }
13
13
 
14
- if (setTimeout.clock != null && typeof setTimeout.clock.Date === 'function') {
14
+ if (typeof setTimeout.clock?.Date === 'function') {
15
15
  utils.warn('Mongoose: looks like you\'re trying to test a Mongoose app ' +
16
16
  'with Jest\'s mock timers enabled. Please make sure you read ' +
17
17
  'Mongoose\'s docs on configuring Jest to test Node.js apps: ' +
@@ -31,7 +31,7 @@ function resolveOptsConflicts(pref, opts) {
31
31
  }
32
32
 
33
33
  function setsIndexOptions(opts) {
34
- const configIdx = opts.config && opts.config.autoIndex;
34
+ const configIdx = opts.config?.autoIndex;
35
35
  const { autoCreate, autoIndex } = opts;
36
36
  return !!(configIdx || autoCreate || autoIndex);
37
37
  }
@@ -71,7 +71,7 @@ module.exports = function castUpdate(schema, obj, options, context, filter) {
71
71
  const discriminatorValue = filter[schema.options.discriminatorKey];
72
72
  const byValue = getDiscriminatorByValue(context.model.discriminators, discriminatorValue);
73
73
  schema = schema.discriminators[discriminatorValue] ||
74
- (byValue && byValue.schema) ||
74
+ byValue?.schema ||
75
75
  schema;
76
76
  } else if (schema != null &&
77
77
  options.overwriteDiscriminatorKey &&
@@ -80,7 +80,7 @@ module.exports = function castUpdate(schema, obj, options, context, filter) {
80
80
  const discriminatorValue = obj[schema.options.discriminatorKey];
81
81
  const byValue = getDiscriminatorByValue(context.model.discriminators, discriminatorValue);
82
82
  schema = schema.discriminators[discriminatorValue] ||
83
- (byValue && byValue.schema) ||
83
+ byValue?.schema ||
84
84
  schema;
85
85
  } else if (schema != null &&
86
86
  options.overwriteDiscriminatorKey &&
@@ -90,7 +90,7 @@ module.exports = function castUpdate(schema, obj, options, context, filter) {
90
90
  const discriminatorValue = obj.$set[schema.options.discriminatorKey];
91
91
  const byValue = getDiscriminatorByValue(context.model.discriminators, discriminatorValue);
92
92
  schema = schema.discriminators[discriminatorValue] ||
93
- (byValue && byValue.schema) ||
93
+ byValue?.schema ||
94
94
  schema;
95
95
  }
96
96
 
@@ -133,7 +133,7 @@ module.exports = function castUpdate(schema, obj, options, context, filter) {
133
133
  const op = ops[i];
134
134
  val = ret[op];
135
135
  hasDollarKey = hasDollarKey || op.startsWith('$');
136
- if (val != null && val.$__) {
136
+ if (val?.$__) {
137
137
  val = val.toObject(internalToObjectOptions);
138
138
  ret[op] = val;
139
139
  }
@@ -153,9 +153,9 @@ module.exports = function castUpdate(schema, obj, options, context, filter) {
153
153
  }
154
154
  }
155
155
 
156
- if (Object.keys(ret).length === 0 &&
156
+ if (utils.hasOwnKeys(ret) === false &&
157
157
  options.upsert &&
158
- Object.keys(filter).length > 0) {
158
+ utils.hasOwnKeys(filter)) {
159
159
  // Trick the driver into allowing empty upserts to work around
160
160
  // https://github.com/mongodb/node-mongodb-native/pull/2490
161
161
  // Shallow clone to avoid passing defaults in re: gh-13962
@@ -225,7 +225,7 @@ function walkUpdatePath(schema, obj, op, options, context, filter, prefix) {
225
225
 
226
226
  let aggregatedError = null;
227
227
 
228
- const strictMode = strict != null ? strict : schema.options.strict;
228
+ const strictMode = strict ?? schema.options.strict;
229
229
 
230
230
  while (i--) {
231
231
  key = keys[i];
@@ -241,7 +241,7 @@ function walkUpdatePath(schema, obj, op, options, context, filter, prefix) {
241
241
  schematype = _res.schematype;
242
242
  }
243
243
  }
244
- if (schematype != null && schematype.schema != null) {
244
+ if (schematype?.schema != null) {
245
245
  obj[key] = cast(schematype.schema, obj[key], options, context);
246
246
  hasKeys = true;
247
247
  continue;
@@ -305,7 +305,7 @@ function walkUpdatePath(schema, obj, op, options, context, filter, prefix) {
305
305
  obj[key].$position = castNumber(val.$position);
306
306
  }
307
307
  } else {
308
- if (schematype != null && schematype.$isSingleNested) {
308
+ if (schematype?.$isSingleNested) {
309
309
  const _strict = strict == null ? schematype.schema.options.strict : strict;
310
310
  try {
311
311
  obj[key] = schematype.castForQuery(null, val, context, { strict: _strict });
@@ -359,7 +359,7 @@ function walkUpdatePath(schema, obj, op, options, context, filter, prefix) {
359
359
  const pathToCheck = (prefix + key);
360
360
  const v = schema._getPathType(pathToCheck);
361
361
  let _strict = strict;
362
- if (v && v.schema && _strict == null) {
362
+ if (v?.schema && _strict == null) {
363
363
  _strict = v.schema.options.strict;
364
364
  }
365
365
 
@@ -376,7 +376,7 @@ function walkUpdatePath(schema, obj, op, options, context, filter, prefix) {
376
376
  // we should be able to set a schema-less field
377
377
  // to an empty object literal
378
378
  hasKeys |= walkUpdatePath(schema, val, op, options, context, filter, prefix + key) ||
379
- (utils.isObject(val) && Object.keys(val).length === 0);
379
+ (utils.isObject(val) && utils.hasOwnKeys(val) === false);
380
380
  }
381
381
  } else {
382
382
  const isModifier = (key === '$each' || key === '$or' || key === '$and' || key === '$in');
@@ -407,7 +407,7 @@ function walkUpdatePath(schema, obj, op, options, context, filter, prefix) {
407
407
  }
408
408
 
409
409
  let isStrict = strict;
410
- if (pathDetails && pathDetails.schema && strict == null) {
410
+ if (pathDetails?.schema && strict == null) {
411
411
  isStrict = pathDetails.schema.options.strict;
412
412
  }
413
413
 
@@ -23,7 +23,7 @@ module.exports = function getEmbeddedDiscriminatorPath(schema, update, filter, p
23
23
 
24
24
  filter = filter || {};
25
25
  update = update || {};
26
- const arrayFilters = options != null && Array.isArray(options.arrayFilters) ?
26
+ const arrayFilters = Array.isArray(options?.arrayFilters) ?
27
27
  options.arrayFilters : [];
28
28
  const updatedPathsByFilter = updatedPathsByArrayFilter(update);
29
29
  let startIndex = 0;
@@ -83,7 +83,7 @@ module.exports = function getEmbeddedDiscriminatorPath(schema, update, filter, p
83
83
  }
84
84
 
85
85
  const discriminator = getDiscriminatorByValue(schematype.Constructor.discriminators, discriminatorKey);
86
- const discriminatorSchema = discriminator && discriminator.schema;
86
+ const discriminatorSchema = discriminator?.schema;
87
87
  if (discriminatorSchema == null) {
88
88
  continue;
89
89
  }
@@ -16,7 +16,7 @@ const StrictModeError = require('../../error/strict');
16
16
  */
17
17
 
18
18
  module.exports = function handleImmutable(schematype, strict, obj, key, fullPath, options, ctx) {
19
- if (schematype == null || !schematype.options || !schematype.options.immutable) {
19
+ if (!schematype?.options?.immutable) {
20
20
  return false;
21
21
  }
22
22
  let immutable = schematype.options.immutable;
@@ -28,7 +28,7 @@ module.exports = function handleImmutable(schematype, strict, obj, key, fullPath
28
28
  return false;
29
29
  }
30
30
 
31
- if (options && options.overwriteImmutable) {
31
+ if (options?.overwriteImmutable) {
32
32
  return false;
33
33
  }
34
34
  if (strict === false) {
@@ -17,7 +17,7 @@ module.exports = function sanitizeFilter(filter) {
17
17
  const filterKeys = Object.keys(filter);
18
18
  for (const key of filterKeys) {
19
19
  const value = filter[key];
20
- if (value != null && value[trustedSymbol]) {
20
+ if (value?.[trustedSymbol]) {
21
21
  continue;
22
22
  }
23
23
  if (key === '$and' || key === '$or') {
@@ -6,7 +6,7 @@ module.exports = function applyPlugins(schema, plugins, options, cacheKey) {
6
6
  }
7
7
  schema[cacheKey] = true;
8
8
 
9
- if (!options || !options.skipTopLevel) {
9
+ if (!options?.skipTopLevel) {
10
10
  let pluginTags = null;
11
11
  for (const plugin of plugins) {
12
12
  const tags = plugin[1] == null ? null : plugin[1].tags;
@@ -9,7 +9,7 @@ module.exports = function applyReadConcern(schema, options) {
9
9
  // because you shouldn't set read concern on individual operations
10
10
  // within a transaction.
11
11
  // See: https://www.mongodb.com/docs/manual/reference/read-concern/
12
- if (options && options.session && options.session.transaction) {
12
+ if (options?.session?.transaction) {
13
13
  return;
14
14
  }
15
15
 
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ const utils = require('../../utils');
4
+
3
5
  module.exports = function applyWriteConcern(schema, options) {
4
6
  if (options.writeConcern != null) {
5
7
  return;
@@ -7,11 +9,11 @@ module.exports = function applyWriteConcern(schema, options) {
7
9
  // Don't apply default write concern to operations in transactions,
8
10
  // because setting write concern on an operation in a transaction is an error
9
11
  // See: https://www.mongodb.com/docs/manual/reference/write-concern/
10
- if (options && options.session && options.session.transaction) {
12
+ if (options?.session?.transaction) {
11
13
  return;
12
14
  }
13
15
  const writeConcern = schema.options.writeConcern ?? {};
14
- if (Object.keys(writeConcern).length != 0) {
16
+ if (utils.hasOwnKeys(writeConcern)) {
15
17
  options.writeConcern = {};
16
18
  if (!('w' in options) && writeConcern.w != null) {
17
19
  options.writeConcern.w = writeConcern.w;
@@ -69,7 +69,7 @@ module.exports = function getIndexes(schema) {
69
69
 
70
70
  const index = path._index || (path.embeddedSchemaType && path.embeddedSchemaType._index);
71
71
 
72
- if (index !== false && index !== null && index !== undefined) {
72
+ if (index !== false && index != null) {
73
73
  const field = {};
74
74
  const isObject = helperIsObject(index);
75
75
  const options = isObject ? { ...index } : {};
@@ -100,7 +100,7 @@ module.exports = function getIndexes(schema) {
100
100
  options._autoIndex = schema.options.autoIndex;
101
101
  }
102
102
 
103
- const indexName = options && options.name;
103
+ const indexName = options?.name;
104
104
 
105
105
  if (typeof indexName === 'string') {
106
106
  if (indexByName.has(indexName)) {
@@ -156,7 +156,7 @@ module.exports = function getIndexes(schema) {
156
156
  }
157
157
 
158
158
  const newIndexOptions = Object.assign({}, indexOptions);
159
- if (indexOptions != null && indexOptions.partialFilterExpression != null) {
159
+ if (indexOptions?.partialFilterExpression != null) {
160
160
  newIndexOptions.partialFilterExpression = {};
161
161
  const partialFilterExpression = indexOptions.partialFilterExpression;
162
162
  for (const key of Object.keys(partialFilterExpression)) {
@@ -19,7 +19,7 @@ module.exports = function getSubdocumentStrictValue(schema, parts) {
19
19
  let strict = undefined;
20
20
  for (let i = 0; i < parts.length - 1; ++i) {
21
21
  const curSchemaType = schema.path(cur);
22
- if (curSchemaType && curSchemaType.schema) {
22
+ if (curSchemaType?.schema) {
23
23
  strict = curSchemaType.schema.options.strict;
24
24
  schema = curSchemaType.schema;
25
25
  cur = curSchemaType.$isMongooseDocumentArray && !isNaN(parts[i + 1]) ? '' : parts[i + 1];
@@ -3,7 +3,7 @@
3
3
  const addAutoId = require('./addAutoId');
4
4
 
5
5
  module.exports = function handleIdOption(schema, options) {
6
- if (options == null || options._id == null) {
6
+ if (options?._id == null) {
7
7
  return schema;
8
8
  }
9
9
 
@@ -12,7 +12,7 @@ module.exports = function addIdGetter(schema) {
12
12
  if (!autoIdGetter) {
13
13
  return schema;
14
14
  }
15
- if (schema.aliases && schema.aliases.id) {
15
+ if (schema.aliases?.id) {
16
16
  return schema;
17
17
  }
18
18
  schema.virtual('id').get(idGetter);
@@ -26,7 +26,7 @@ function createImmutableSetter(path, immutable) {
26
26
  if (this.isNew) {
27
27
  return v;
28
28
  }
29
- if (options && options.overwriteImmutable) {
29
+ if (options?.overwriteImmutable) {
30
30
  return v;
31
31
  }
32
32
 
@@ -15,10 +15,7 @@ const get = require('./get');
15
15
  module.exports = function(filter, schema, castedDoc, options) {
16
16
  options = options || {};
17
17
 
18
- const shouldSetDefaultsOnInsert =
19
- options.setDefaultsOnInsert != null ?
20
- options.setDefaultsOnInsert :
21
- schema.base.options.setDefaultsOnInsert;
18
+ const shouldSetDefaultsOnInsert = options.setDefaultsOnInsert ?? schema.base.options.setDefaultsOnInsert;
22
19
 
23
20
  if (!options.upsert || shouldSetDefaultsOnInsert === false) {
24
21
  return castedDoc;
@@ -60,7 +57,7 @@ module.exports = function(filter, schema, castedDoc, options) {
60
57
  updatedKeys[path] = true;
61
58
  }
62
59
 
63
- if (options && options.overwrite && !hasDollarUpdate) {
60
+ if (options?.overwrite && !hasDollarUpdate) {
64
61
  // Defaults will be set later, since we're overwriting we'll cast
65
62
  // the whole update to a document
66
63
  return castedDoc;
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  module.exports = function setDocumentTimestamps(doc, timestampOption, currentTime, createdAt, updatedAt) {
4
- const skipUpdatedAt = timestampOption != null && timestampOption.updatedAt === false;
5
- const skipCreatedAt = timestampOption != null && timestampOption.createdAt === false;
4
+ const skipUpdatedAt = timestampOption?.updatedAt === false;
5
+ const skipCreatedAt = timestampOption?.createdAt === false;
6
6
 
7
7
  const defaultTimestamp = currentTime != null ?
8
8
  currentTime() :
@@ -31,8 +31,8 @@ module.exports = function setupTimestamps(schema, timestamps) {
31
31
  schema.$timestamps = { createdAt: createdAt, updatedAt: updatedAt };
32
32
 
33
33
  if (createdAt && !schema.paths[createdAt]) {
34
- const baseImmutableCreatedAt = schema.base != null ? schema.base.get('timestamps.createdAt.immutable') : null;
35
- const immutable = baseImmutableCreatedAt != null ? baseImmutableCreatedAt : true;
34
+ const baseImmutableCreatedAt = schema.base?.get('timestamps.createdAt.immutable') ?? null;
35
+ const immutable = baseImmutableCreatedAt ?? true;
36
36
  schemaAdditions[createdAt] = { [schema.options.typeKey || 'type']: Date, immutable };
37
37
  }
38
38