mongoose 9.0.2 → 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.
- package/lib/aggregate.js +1 -1
- package/lib/cast/string.js +1 -1
- package/lib/cast.js +7 -15
- package/lib/collection.js +2 -2
- package/lib/connection.js +20 -14
- package/lib/cursor/changeStream.js +5 -5
- package/lib/document.js +117 -77
- package/lib/drivers/node-mongodb-native/collection.js +5 -17
- package/lib/drivers/node-mongodb-native/connection.js +8 -23
- package/lib/error/cast.js +1 -1
- package/lib/helpers/aggregate/prepareDiscriminatorPipeline.js +4 -4
- package/lib/helpers/clone.js +8 -8
- package/lib/helpers/common.js +4 -4
- package/lib/helpers/cursor/eachAsync.js +1 -1
- package/lib/helpers/discriminator/getConstructor.js +1 -1
- package/lib/helpers/discriminator/getSchemaDiscriminatorByValue.js +1 -1
- package/lib/helpers/discriminator/mergeDiscriminatorSchema.js +2 -2
- package/lib/helpers/document/applyDefaults.js +1 -1
- package/lib/helpers/document/applyTimestamps.js +2 -1
- package/lib/helpers/document/applyVirtuals.js +4 -3
- package/lib/helpers/document/cleanModifiedSubpaths.js +1 -1
- package/lib/helpers/document/compile.js +4 -4
- package/lib/helpers/document/getDeepestSubdocumentForPath.js +1 -1
- package/lib/helpers/indexes/decorateDiscriminatorIndexOptions.js +1 -1
- package/lib/helpers/indexes/getRelatedIndexes.js +3 -3
- package/lib/helpers/model/castBulkWrite.js +5 -9
- package/lib/helpers/model/discriminator.js +1 -1
- package/lib/helpers/populate/assignRawDocsToIdStructure.js +1 -1
- package/lib/helpers/populate/assignVals.js +4 -4
- package/lib/helpers/populate/getModelsMapForPopulate.js +25 -23
- package/lib/helpers/populate/getSchemaTypes.js +6 -7
- package/lib/helpers/printJestWarning.js +1 -1
- package/lib/helpers/processConnectionOptions.js +1 -1
- package/lib/helpers/query/castUpdate.js +12 -12
- package/lib/helpers/query/getEmbeddedDiscriminatorPath.js +2 -2
- package/lib/helpers/query/handleImmutable.js +2 -2
- package/lib/helpers/query/sanitizeFilter.js +1 -1
- package/lib/helpers/schema/applyPlugins.js +1 -1
- package/lib/helpers/schema/applyReadConcern.js +1 -1
- package/lib/helpers/schema/applyWriteConcern.js +4 -2
- package/lib/helpers/schema/getIndexes.js +3 -3
- package/lib/helpers/schema/getSubdocumentStrictValue.js +1 -1
- package/lib/helpers/schema/handleIdOption.js +1 -1
- package/lib/helpers/schema/idGetter.js +1 -1
- package/lib/helpers/schematype/handleImmutable.js +1 -1
- package/lib/helpers/setDefaultsOnInsert.js +2 -5
- package/lib/helpers/timestamps/setDocumentTimestamps.js +2 -2
- package/lib/helpers/timestamps/setupTimestamps.js +2 -2
- package/lib/helpers/update/applyTimestampsToUpdate.js +10 -9
- package/lib/helpers/update/castArrayFilters.js +4 -4
- package/lib/helpers/update/decorateUpdateWithVersionKey.js +1 -1
- package/lib/helpers/updateValidators.js +4 -4
- package/lib/model.js +33 -44
- package/lib/mongoose.js +5 -5
- package/lib/options/virtualOptions.js +1 -1
- package/lib/plugins/saveSubdocs.js +2 -2
- package/lib/plugins/trackTransaction.js +3 -4
- package/lib/query.js +62 -59
- package/lib/queryHelpers.js +9 -12
- package/lib/schema/array.js +10 -12
- package/lib/schema/buffer.js +6 -6
- package/lib/schema/documentArray.js +15 -23
- package/lib/schema/documentArrayElement.js +3 -3
- package/lib/schema/map.js +1 -1
- package/lib/schema/mixed.js +2 -2
- package/lib/schema/number.js +22 -4
- package/lib/schema/objectId.js +1 -1
- package/lib/schema/operators/exists.js +1 -1
- package/lib/schema/operators/geospatial.js +1 -1
- package/lib/schema/string.js +2 -2
- package/lib/schema/subdocument.js +9 -12
- package/lib/schema/union.js +1 -1
- package/lib/schema.js +27 -28
- package/lib/schemaType.js +11 -11
- package/lib/types/array/index.js +2 -2
- package/lib/types/array/methods/index.js +38 -8
- package/lib/types/arraySubdocument.js +12 -2
- package/lib/types/buffer.js +1 -1
- package/lib/types/documentArray/index.js +2 -2
- package/lib/types/documentArray/methods/index.js +5 -5
- package/lib/types/map.js +8 -8
- package/lib/types/subdocument.js +15 -5
- package/lib/utils.js +23 -7
- package/package.json +2 -2
- package/types/index.d.ts +15 -5
- package/types/middlewares.d.ts +11 -0
- package/types/models.d.ts +15 -5
- package/types/schemaoptions.d.ts +4 -2
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 (
|
|
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
|
|
224
|
+
if (schema?.instance === 'Array') {
|
|
222
225
|
schema = schema.embeddedSchemaType;
|
|
223
226
|
}
|
|
224
|
-
if (schema
|
|
227
|
+
if (schema?.$isSchemaMap) {
|
|
225
228
|
schema = schema.$__schemaType;
|
|
226
229
|
}
|
|
227
230
|
|
|
228
|
-
const ref = schema
|
|
229
|
-
refPath = schema
|
|
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
|
|
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
|
|
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
|
|
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
|
|
626
|
-
localFieldPath.getters : [];
|
|
628
|
+
const localFieldGetters = localFieldPath?.getters || [];
|
|
627
629
|
|
|
628
|
-
localField = localFieldPath
|
|
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
|
|
662
|
+
if (val?.$__ != null) {
|
|
661
663
|
return val._doc._id;
|
|
662
664
|
}
|
|
663
|
-
if (val
|
|
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
|
|
670
|
+
const rawVal = val.__array ?? val;
|
|
669
671
|
for (let i = 0; i < rawVal.length; ++i) {
|
|
670
|
-
if (rawVal[i]
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
37
|
+
if (doc?.[discriminatorKey] != null) {
|
|
39
38
|
const discriminator = getDiscriminatorByValue(model.discriminators, doc[discriminatorKey]);
|
|
40
|
-
schema = discriminator
|
|
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
|
|
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
|
|
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
|
|
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 (
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 (
|
|
156
|
+
if (utils.hasOwnKeys(ret) === false &&
|
|
157
157
|
options.upsert &&
|
|
158
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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) &&
|
|
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
|
|
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 =
|
|
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
|
|
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 (
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
12
|
+
if (options?.session?.transaction) {
|
|
11
13
|
return;
|
|
12
14
|
}
|
|
13
15
|
const writeConcern = schema.options.writeConcern ?? {};
|
|
14
|
-
if (
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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];
|
|
@@ -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
|
|
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
|
|
5
|
-
const skipCreatedAt = timestampOption
|
|
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
|
|
35
|
-
const immutable = baseImmutableCreatedAt
|
|
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
|
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const get = require('../get');
|
|
8
|
+
const utils = require('../../utils');
|
|
8
9
|
|
|
9
10
|
module.exports = applyTimestampsToUpdate;
|
|
10
11
|
|
|
@@ -22,11 +23,11 @@ function applyTimestampsToUpdate(now, createdAt, updatedAt, currentUpdate, optio
|
|
|
22
23
|
return currentUpdate;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
const skipCreatedAt = timestamps
|
|
26
|
-
const skipUpdatedAt = timestamps
|
|
26
|
+
const skipCreatedAt = timestamps?.createdAt === false;
|
|
27
|
+
const skipUpdatedAt = timestamps?.updatedAt === false;
|
|
27
28
|
|
|
28
29
|
if (isReplace) {
|
|
29
|
-
if (currentUpdate
|
|
30
|
+
if (currentUpdate?.$set) {
|
|
30
31
|
currentUpdate = currentUpdate.$set;
|
|
31
32
|
updates.$set = {};
|
|
32
33
|
_updates = updates.$set;
|
|
@@ -51,7 +52,7 @@ function applyTimestampsToUpdate(now, createdAt, updatedAt, currentUpdate, optio
|
|
|
51
52
|
}
|
|
52
53
|
updates.$set = updates.$set || {};
|
|
53
54
|
if (!skipUpdatedAt && updatedAt &&
|
|
54
|
-
|
|
55
|
+
!currentUpdate.$currentDate?.[updatedAt]) {
|
|
55
56
|
let timestampSet = false;
|
|
56
57
|
if (updatedAt.indexOf('.') !== -1) {
|
|
57
58
|
const pieces = updatedAt.split('.');
|
|
@@ -62,7 +63,7 @@ function applyTimestampsToUpdate(now, createdAt, updatedAt, currentUpdate, optio
|
|
|
62
63
|
currentUpdate[start][remnant] = now;
|
|
63
64
|
timestampSet = true;
|
|
64
65
|
break;
|
|
65
|
-
} else if (currentUpdate.$set
|
|
66
|
+
} else if (currentUpdate.$set?.[start]) {
|
|
66
67
|
currentUpdate.$set[start][remnant] = now;
|
|
67
68
|
timestampSet = true;
|
|
68
69
|
break;
|
|
@@ -81,7 +82,7 @@ function applyTimestampsToUpdate(now, createdAt, updatedAt, currentUpdate, optio
|
|
|
81
82
|
|
|
82
83
|
if (!skipCreatedAt && createdAt) {
|
|
83
84
|
const overwriteImmutable = get(options, 'overwriteImmutable', false);
|
|
84
|
-
const hasUserCreatedAt = currentUpdate[createdAt] != null || currentUpdate
|
|
85
|
+
const hasUserCreatedAt = currentUpdate[createdAt] != null || currentUpdate.$set?.[createdAt] != null;
|
|
85
86
|
|
|
86
87
|
// If overwriteImmutable is true and user provided createdAt, keep their value
|
|
87
88
|
if (overwriteImmutable && hasUserCreatedAt) {
|
|
@@ -95,7 +96,7 @@ function applyTimestampsToUpdate(now, createdAt, updatedAt, currentUpdate, optio
|
|
|
95
96
|
if (currentUpdate[createdAt]) {
|
|
96
97
|
delete currentUpdate[createdAt];
|
|
97
98
|
}
|
|
98
|
-
if (currentUpdate.$set
|
|
99
|
+
if (currentUpdate.$set?.[createdAt]) {
|
|
99
100
|
delete currentUpdate.$set[createdAt];
|
|
100
101
|
}
|
|
101
102
|
let timestampSet = false;
|
|
@@ -108,7 +109,7 @@ function applyTimestampsToUpdate(now, createdAt, updatedAt, currentUpdate, optio
|
|
|
108
109
|
currentUpdate[start][remnant] = now;
|
|
109
110
|
timestampSet = true;
|
|
110
111
|
break;
|
|
111
|
-
} else if (currentUpdate.$set
|
|
112
|
+
} else if (currentUpdate.$set?.[start]) {
|
|
112
113
|
currentUpdate.$set[start][remnant] = now;
|
|
113
114
|
timestampSet = true;
|
|
114
115
|
break;
|
|
@@ -123,7 +124,7 @@ function applyTimestampsToUpdate(now, createdAt, updatedAt, currentUpdate, optio
|
|
|
123
124
|
}
|
|
124
125
|
}
|
|
125
126
|
|
|
126
|
-
if (
|
|
127
|
+
if (utils.hasOwnKeys(updates.$set) === false) {
|
|
127
128
|
delete updates.$set;
|
|
128
129
|
}
|
|
129
130
|
return updates;
|
|
@@ -4,6 +4,7 @@ const castFilterPath = require('../query/castFilterPath');
|
|
|
4
4
|
const cleanPositionalOperators = require('../schema/cleanPositionalOperators');
|
|
5
5
|
const getPath = require('../schema/getPath');
|
|
6
6
|
const updatedPathsByArrayFilter = require('./updatedPathsByArrayFilter');
|
|
7
|
+
const utils = require('../../utils');
|
|
7
8
|
|
|
8
9
|
module.exports = function castArrayFilters(query) {
|
|
9
10
|
const arrayFilters = query.options.arrayFilters;
|
|
@@ -18,7 +19,7 @@ module.exports = function castArrayFilters(query) {
|
|
|
18
19
|
if (query._mongooseOptions.strict != null) {
|
|
19
20
|
strictQuery = query._mongooseOptions.strict;
|
|
20
21
|
}
|
|
21
|
-
if (query.model
|
|
22
|
+
if (query.model?.base.options.strictQuery != null) {
|
|
22
23
|
strictQuery = query.model.base.options.strictQuery;
|
|
23
24
|
}
|
|
24
25
|
if (schema._userProvidedOptions.strictQuery != null) {
|
|
@@ -63,8 +64,7 @@ function _castArrayFilters(arrayFilters, schema, strictQuery, updatedPathsByFilt
|
|
|
63
64
|
|
|
64
65
|
const baseSchematype = getPath(schema, baseFilterPath, discriminatorValueMap);
|
|
65
66
|
let filterBaseSchema = baseSchematype != null ? baseSchematype.schema : null;
|
|
66
|
-
if (filterBaseSchema != null &&
|
|
67
|
-
filterBaseSchema.discriminators != null &&
|
|
67
|
+
if (filterBaseSchema?.discriminators != null &&
|
|
68
68
|
filter[filterWildcardPath + '.' + filterBaseSchema.options.discriminatorKey]) {
|
|
69
69
|
filterBaseSchema = filterBaseSchema.discriminators[filter[filterWildcardPath + '.' + filterBaseSchema.options.discriminatorKey]] || filterBaseSchema;
|
|
70
70
|
discriminatorValueMap[baseFilterPath] = filter[filterWildcardPath + '.' + filterBaseSchema.options.discriminatorKey];
|
|
@@ -74,7 +74,7 @@ function _castArrayFilters(arrayFilters, schema, strictQuery, updatedPathsByFilt
|
|
|
74
74
|
if (updatedPathsByFilter[key] === null) {
|
|
75
75
|
continue;
|
|
76
76
|
}
|
|
77
|
-
if (
|
|
77
|
+
if (utils.hasOwnKeys(updatedPathsByFilter) === false) {
|
|
78
78
|
continue;
|
|
79
79
|
}
|
|
80
80
|
const dot = key.indexOf('.');
|