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
package/lib/document.js
CHANGED
|
@@ -149,7 +149,7 @@ function Document(obj, fields, options) {
|
|
|
149
149
|
|
|
150
150
|
// determine if this doc is a result of a query with
|
|
151
151
|
// excluded fields
|
|
152
|
-
if (utils.isPOJO(fields) &&
|
|
152
|
+
if (utils.isPOJO(fields) && utils.hasOwnKeys(fields)) {
|
|
153
153
|
exclude = isExclusive(fields);
|
|
154
154
|
this.$__.selected = fields;
|
|
155
155
|
this.$__.exclude = exclude;
|
|
@@ -702,7 +702,7 @@ Document.prototype.$__init = function(doc, opts) {
|
|
|
702
702
|
continue;
|
|
703
703
|
}
|
|
704
704
|
for (const child of item._childDocs) {
|
|
705
|
-
if (child
|
|
705
|
+
if (child?.$__ == null) {
|
|
706
706
|
continue;
|
|
707
707
|
}
|
|
708
708
|
child.$__.parent = this;
|
|
@@ -801,7 +801,7 @@ function init(self, obj, doc, opts, prefix) {
|
|
|
801
801
|
|
|
802
802
|
if (schemaType && !wasPopulated && !opts.hydratedPopulatedDocs) {
|
|
803
803
|
try {
|
|
804
|
-
if (opts
|
|
804
|
+
if (opts?.setters) {
|
|
805
805
|
// Call applySetters with `init = false` because otherwise setters are a noop
|
|
806
806
|
const overrideInit = false;
|
|
807
807
|
doc[i] = schemaType.applySetters(value, self, overrideInit, null, opts);
|
|
@@ -820,7 +820,7 @@ function init(self, obj, doc, opts, prefix) {
|
|
|
820
820
|
} else if (schemaType && opts.hydratedPopulatedDocs) {
|
|
821
821
|
doc[i] = schemaType.cast(value, self, true, undefined, { hydratedPopulatedDocs: true });
|
|
822
822
|
|
|
823
|
-
if (doc[i]
|
|
823
|
+
if (doc[i]?.$__?.wasPopulated) {
|
|
824
824
|
self.$populated(path, doc[i].$__.wasPopulated.value, doc[i].$__.wasPopulated.options);
|
|
825
825
|
} else if (Array.isArray(doc[i]) && doc[i].length && doc[i][0]?.$__?.wasPopulated) {
|
|
826
826
|
self.$populated(path, doc[i].map(populatedDoc => populatedDoc?.$__?.wasPopulated?.value).filter(val => val != null), doc[i][0].$__.wasPopulated.options);
|
|
@@ -849,7 +849,7 @@ function init(self, obj, doc, opts, prefix) {
|
|
|
849
849
|
* - same as in [Model.updateOne](https://mongoosejs.com/docs/api/model.html#Model.updateOne)
|
|
850
850
|
*
|
|
851
851
|
* @see Model.updateOne https://mongoosejs.com/docs/api/model.html#Model.updateOne
|
|
852
|
-
* @param {Object}
|
|
852
|
+
* @param {Object} update
|
|
853
853
|
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.setOptions())
|
|
854
854
|
* @param {Object} [options.lean] if truthy, mongoose will return the document as a plain JavaScript object rather than a mongoose document. See [`Query.lean()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.lean()) and the [Mongoose lean tutorial](https://mongoosejs.com/docs/tutorials/lean.html).
|
|
855
855
|
* @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
|
|
@@ -860,33 +860,33 @@ function init(self, obj, doc, opts, prefix) {
|
|
|
860
860
|
* @instance
|
|
861
861
|
*/
|
|
862
862
|
|
|
863
|
-
Document.prototype.updateOne = function updateOne(
|
|
864
|
-
const query = this.constructor.updateOne(
|
|
863
|
+
Document.prototype.updateOne = function updateOne(update, options) {
|
|
864
|
+
const query = this.constructor.updateOne();
|
|
865
865
|
const self = this;
|
|
866
866
|
query.pre(async function queryPreUpdateOne() {
|
|
867
|
-
const res = await self._execDocumentPreHooks('updateOne', self);
|
|
867
|
+
const res = await self._execDocumentPreHooks('updateOne', self, update, options);
|
|
868
868
|
// `self` is passed to pre hooks as argument for backwards compatibility, but that
|
|
869
869
|
// isn't the actual arguments passed to the wrapped function.
|
|
870
|
-
if (res
|
|
870
|
+
if (res[0] !== self || res[1] !== update || res[2] !== options) {
|
|
871
871
|
throw new Error('Document updateOne pre hooks cannot overwrite arguments');
|
|
872
872
|
}
|
|
873
|
+
query.updateOne({ _id: self._doc._id }, update, options);
|
|
873
874
|
// Apply custom where conditions _after_ document updateOne middleware for
|
|
874
875
|
// consistency with save() - sharding plugin needs to set $where
|
|
875
876
|
if (self.$where != null) {
|
|
876
877
|
this.where(self.$where);
|
|
877
878
|
}
|
|
879
|
+
if (self.$session() != null) {
|
|
880
|
+
if (!('session' in query.options)) {
|
|
881
|
+
query.options.session = self.$session();
|
|
882
|
+
}
|
|
883
|
+
}
|
|
878
884
|
return res;
|
|
879
885
|
});
|
|
880
886
|
query.post(function queryPostUpdateOne() {
|
|
881
887
|
return self._execDocumentPostHooks('updateOne');
|
|
882
888
|
});
|
|
883
889
|
|
|
884
|
-
if (this.$session() != null) {
|
|
885
|
-
if (!('session' in query.options)) {
|
|
886
|
-
query.options.session = this.$session();
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
|
-
|
|
890
890
|
return query;
|
|
891
891
|
};
|
|
892
892
|
|
|
@@ -938,14 +938,14 @@ Document.prototype.replaceOne = function replaceOne() {
|
|
|
938
938
|
|
|
939
939
|
Document.prototype.$session = function $session(session) {
|
|
940
940
|
if (arguments.length === 0) {
|
|
941
|
-
if (this.$__.session
|
|
941
|
+
if (this.$__.session?.hasEnded) {
|
|
942
942
|
this.$__.session = null;
|
|
943
943
|
return null;
|
|
944
944
|
}
|
|
945
945
|
return this.$__.session;
|
|
946
946
|
}
|
|
947
947
|
|
|
948
|
-
if (session
|
|
948
|
+
if (session?.hasEnded) {
|
|
949
949
|
throw new MongooseError('Cannot set a document\'s session to a session that has ended. Make sure you haven\'t ' +
|
|
950
950
|
'called `endSession()` on the session you are passing to `$session()`.');
|
|
951
951
|
}
|
|
@@ -1022,17 +1022,21 @@ Document.prototype.$timestamps = function $timestamps(value) {
|
|
|
1022
1022
|
*/
|
|
1023
1023
|
|
|
1024
1024
|
Document.prototype.overwrite = function overwrite(obj) {
|
|
1025
|
-
const keys =
|
|
1025
|
+
const keys = new Set(Object.keys(this._doc));
|
|
1026
|
+
for (const key of Object.keys(obj)) {
|
|
1027
|
+
keys.add(key);
|
|
1028
|
+
}
|
|
1026
1029
|
|
|
1030
|
+
const schemaOptions = this.$__schema.options;
|
|
1027
1031
|
for (const key of keys) {
|
|
1028
1032
|
if (key === '_id') {
|
|
1029
1033
|
continue;
|
|
1030
1034
|
}
|
|
1031
1035
|
// Explicitly skip version key
|
|
1032
|
-
if (
|
|
1036
|
+
if (schemaOptions.versionKey && key === schemaOptions.versionKey) {
|
|
1033
1037
|
continue;
|
|
1034
1038
|
}
|
|
1035
|
-
if (
|
|
1039
|
+
if (schemaOptions.discriminatorKey && key === schemaOptions.discriminatorKey) {
|
|
1036
1040
|
continue;
|
|
1037
1041
|
}
|
|
1038
1042
|
this.$set(key, obj[key]);
|
|
@@ -1062,7 +1066,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1062
1066
|
type = undefined;
|
|
1063
1067
|
}
|
|
1064
1068
|
|
|
1065
|
-
const merge = options
|
|
1069
|
+
const merge = options?.merge;
|
|
1066
1070
|
const adhoc = type && type !== true;
|
|
1067
1071
|
const constructing = type === true;
|
|
1068
1072
|
let adhocs;
|
|
@@ -1108,7 +1112,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1108
1112
|
|
|
1109
1113
|
// `_skipMinimizeTopLevel` is because we may have deleted the top-level
|
|
1110
1114
|
// nested key to ensure key order.
|
|
1111
|
-
const _skipMinimizeTopLevel = options
|
|
1115
|
+
const _skipMinimizeTopLevel = options?._skipMinimizeTopLevel || false;
|
|
1112
1116
|
if (len === 0 && _skipMinimizeTopLevel) {
|
|
1113
1117
|
delete options._skipMinimizeTopLevel;
|
|
1114
1118
|
if (val) {
|
|
@@ -1422,7 +1426,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1422
1426
|
|
|
1423
1427
|
let didPopulate = false;
|
|
1424
1428
|
if (refMatches && val instanceof Document && (!val.$__.wasPopulated || utils.deepEqual(val.$__.wasPopulated.value, val._doc._id))) {
|
|
1425
|
-
const unpopulatedValue =
|
|
1429
|
+
const unpopulatedValue = schema?.$isSingleNested ? schema.cast(val, this) : val._doc._id;
|
|
1426
1430
|
this.$populated(path, unpopulatedValue, { [populateModelSymbol]: val.constructor });
|
|
1427
1431
|
val.$__.wasPopulated = { value: unpopulatedValue };
|
|
1428
1432
|
didPopulate = true;
|
|
@@ -1454,7 +1458,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1454
1458
|
if (this.$__schema.singleNestedPaths[path] != null && parts.length > 1) {
|
|
1455
1459
|
setterContext = getDeepestSubdocumentForPath(this, parts, this.schema);
|
|
1456
1460
|
}
|
|
1457
|
-
if (options
|
|
1461
|
+
if (options?.overwriteImmutable) {
|
|
1458
1462
|
val = schema.applySetters(val, setterContext, false, priorVal, { path, overwriteImmutable: true });
|
|
1459
1463
|
} else {
|
|
1460
1464
|
val = schema.applySetters(val, setterContext, false, priorVal, { path });
|
|
@@ -1465,9 +1469,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1465
1469
|
!Array.isArray(schema) &&
|
|
1466
1470
|
schema.$isMongooseDocumentArray &&
|
|
1467
1471
|
val.length !== 0 &&
|
|
1468
|
-
val[0] != null
|
|
1469
|
-
val[0].$__ != null &&
|
|
1470
|
-
val[0].$__.populated != null) {
|
|
1472
|
+
val[0]?.$__?.populated != null) {
|
|
1471
1473
|
const populatedPaths = Object.keys(val[0].$__.populated);
|
|
1472
1474
|
for (const populatedPath of populatedPaths) {
|
|
1473
1475
|
this.$populated(path + '.' + populatedPath,
|
|
@@ -1632,7 +1634,7 @@ Document.prototype.set = Document.prototype.$set;
|
|
|
1632
1634
|
*/
|
|
1633
1635
|
|
|
1634
1636
|
Document.prototype.$__shouldModify = function(pathToMark, path, options, constructing, parts, schema, val, priorVal) {
|
|
1635
|
-
if (options
|
|
1637
|
+
if (options?._skipMarkModified) {
|
|
1636
1638
|
return false;
|
|
1637
1639
|
}
|
|
1638
1640
|
if (this.$isNew) {
|
|
@@ -1702,9 +1704,9 @@ Document.prototype.$__set = function(pathToMark, path, options, constructing, pa
|
|
|
1702
1704
|
schema, val, priorVal);
|
|
1703
1705
|
|
|
1704
1706
|
if (shouldModify) {
|
|
1705
|
-
if (this.$__.primitiveAtomics
|
|
1707
|
+
if (this.$__.primitiveAtomics?.[path]) {
|
|
1706
1708
|
delete this.$__.primitiveAtomics[path];
|
|
1707
|
-
if (
|
|
1709
|
+
if (utils.hasOwnKeys(this.$__.primitiveAtomics) === false) {
|
|
1708
1710
|
delete this.$__.primitiveAtomics;
|
|
1709
1711
|
}
|
|
1710
1712
|
}
|
|
@@ -1946,7 +1948,7 @@ Document.prototype.get = function(path, type, options) {
|
|
|
1946
1948
|
return obj;
|
|
1947
1949
|
}
|
|
1948
1950
|
|
|
1949
|
-
if (schema
|
|
1951
|
+
if (schema?.instance === 'Mixed') {
|
|
1950
1952
|
const virtual = this.$__schema.virtualpath(path);
|
|
1951
1953
|
if (virtual != null) {
|
|
1952
1954
|
schema = virtual;
|
|
@@ -1963,7 +1965,7 @@ Document.prototype.get = function(path, type, options) {
|
|
|
1963
1965
|
}
|
|
1964
1966
|
|
|
1965
1967
|
for (let i = 0, l = pieces.length; i < l; i++) {
|
|
1966
|
-
if (obj
|
|
1968
|
+
if (obj?._doc) {
|
|
1967
1969
|
obj = obj._doc;
|
|
1968
1970
|
}
|
|
1969
1971
|
|
|
@@ -2291,7 +2293,7 @@ Document.prototype[documentModifiedPaths] = Document.prototype.modifiedPaths;
|
|
|
2291
2293
|
|
|
2292
2294
|
Document.prototype.isModified = function(paths, options, modifiedPaths) {
|
|
2293
2295
|
if (paths) {
|
|
2294
|
-
const ignoreAtomics = options
|
|
2296
|
+
const ignoreAtomics = options?.ignoreAtomics;
|
|
2295
2297
|
const directModifiedPathsObj = this.$__.activePaths.states.modify;
|
|
2296
2298
|
if (directModifiedPathsObj == null) {
|
|
2297
2299
|
return false;
|
|
@@ -2316,7 +2318,7 @@ Document.prototype.isModified = function(paths, options, modifiedPaths) {
|
|
|
2316
2318
|
if (ignoreAtomics) {
|
|
2317
2319
|
directModifiedPaths = directModifiedPaths.filter(path => {
|
|
2318
2320
|
const value = this.$__getValue(path);
|
|
2319
|
-
if (value
|
|
2321
|
+
if (value?.[arrayAtomicsSymbol] != null && value[arrayAtomicsSymbol].$set === undefined) {
|
|
2320
2322
|
return false;
|
|
2321
2323
|
}
|
|
2322
2324
|
return true;
|
|
@@ -2438,7 +2440,7 @@ Document.prototype.isDirectModified = function(path) {
|
|
|
2438
2440
|
for (let i = 0; i < pieces.length - 1; ++i) {
|
|
2439
2441
|
const subpath = pieces.slice(0, i + 1).join('.');
|
|
2440
2442
|
const subdoc = this.$get(subpath);
|
|
2441
|
-
if (subdoc
|
|
2443
|
+
if (subdoc?.$__ != null && subdoc.isDirectModified(pieces.slice(i + 1).join('.'))) {
|
|
2442
2444
|
return true;
|
|
2443
2445
|
}
|
|
2444
2446
|
}
|
|
@@ -2656,7 +2658,7 @@ Document.prototype.validate = async function validate(pathsToValidate, options)
|
|
|
2656
2658
|
const isOnePathOnly = options.pathsToSkip.indexOf(' ') === -1;
|
|
2657
2659
|
options.pathsToSkip = isOnePathOnly ? [options.pathsToSkip] : options.pathsToSkip.split(' ');
|
|
2658
2660
|
}
|
|
2659
|
-
const _skipParallelValidateCheck = options
|
|
2661
|
+
const _skipParallelValidateCheck = options?._skipParallelValidateCheck;
|
|
2660
2662
|
|
|
2661
2663
|
if (this.$isSubdocument != null) {
|
|
2662
2664
|
// Skip parallel validate check for subdocuments
|
|
@@ -2697,7 +2699,7 @@ function _evaluateRequiredFunctions(doc) {
|
|
|
2697
2699
|
|
|
2698
2700
|
const p = doc.$__schema.path(path);
|
|
2699
2701
|
|
|
2700
|
-
if (
|
|
2702
|
+
if (typeof p?.originalRequiredValue === 'function') {
|
|
2701
2703
|
doc.$__.cachedRequired = doc.$__.cachedRequired || {};
|
|
2702
2704
|
try {
|
|
2703
2705
|
doc.$__.cachedRequired[path] = p.originalRequiredValue.call(doc, doc);
|
|
@@ -2757,7 +2759,7 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate
|
|
|
2757
2759
|
}
|
|
2758
2760
|
} else if (schemaType.$isMongooseDocumentArray) {
|
|
2759
2761
|
const arr = doc.$get(path);
|
|
2760
|
-
if (arr
|
|
2762
|
+
if (arr?.length) {
|
|
2761
2763
|
for (const subdoc of arr) {
|
|
2762
2764
|
if (subdoc) {
|
|
2763
2765
|
topLevelSubdocs.push(subdoc);
|
|
@@ -2910,7 +2912,7 @@ function _addArrayPathsToValidate(doc, paths) {
|
|
|
2910
2912
|
// it unless we have a case of #6364
|
|
2911
2913
|
(!Array.isArray(_pathType) &&
|
|
2912
2914
|
_pathType.$isMongooseDocumentArray &&
|
|
2913
|
-
!
|
|
2915
|
+
!_pathType?.schemaOptions?.required)) {
|
|
2914
2916
|
continue;
|
|
2915
2917
|
}
|
|
2916
2918
|
|
|
@@ -2977,7 +2979,7 @@ Document.prototype.$__validate = async function $__validate(pathsToValidate, opt
|
|
|
2977
2979
|
(typeof options === 'object') &&
|
|
2978
2980
|
('validateModifiedOnly' in options);
|
|
2979
2981
|
|
|
2980
|
-
const pathsToSkip =
|
|
2982
|
+
const pathsToSkip = options?.pathsToSkip || null;
|
|
2981
2983
|
|
|
2982
2984
|
let shouldValidateModifiedOnly;
|
|
2983
2985
|
if (hasValidateModifiedOnlyOption) {
|
|
@@ -2986,7 +2988,7 @@ Document.prototype.$__validate = async function $__validate(pathsToValidate, opt
|
|
|
2986
2988
|
shouldValidateModifiedOnly = this.$__schema.options.validateModifiedOnly;
|
|
2987
2989
|
}
|
|
2988
2990
|
|
|
2989
|
-
const validateAllPaths = options
|
|
2991
|
+
const validateAllPaths = options?.validateAllPaths;
|
|
2990
2992
|
if (validateAllPaths) {
|
|
2991
2993
|
if (pathsToSkip) {
|
|
2992
2994
|
throw new TypeError('Cannot set both `validateAllPaths` and `pathsToSkip`');
|
|
@@ -3013,7 +3015,7 @@ Document.prototype.$__validate = async function $__validate(pathsToValidate, opt
|
|
|
3013
3015
|
delete validationError.errors[errPath];
|
|
3014
3016
|
}
|
|
3015
3017
|
}
|
|
3016
|
-
if (
|
|
3018
|
+
if (utils.hasOwnKeys(validationError.errors) === false) {
|
|
3017
3019
|
validationError = void 0;
|
|
3018
3020
|
}
|
|
3019
3021
|
}
|
|
@@ -3044,7 +3046,7 @@ Document.prototype.$__validate = async function $__validate(pathsToValidate, opt
|
|
|
3044
3046
|
// the children as well
|
|
3045
3047
|
for (const path of paths) {
|
|
3046
3048
|
const schemaType = this.$__schema.path(path);
|
|
3047
|
-
if (!schemaType
|
|
3049
|
+
if (!schemaType?.$isMongooseArray) {
|
|
3048
3050
|
continue;
|
|
3049
3051
|
}
|
|
3050
3052
|
const val = this.$__getValue(path);
|
|
@@ -3056,7 +3058,7 @@ Document.prototype.$__validate = async function $__validate(pathsToValidate, opt
|
|
|
3056
3058
|
paths = [...paths];
|
|
3057
3059
|
doValidateOptionsByPath = {};
|
|
3058
3060
|
} else {
|
|
3059
|
-
const pathDetails = _getPathsToValidate(this, pathsToValidate, pathsToSkip, options
|
|
3061
|
+
const pathDetails = _getPathsToValidate(this, pathsToValidate, pathsToSkip, options?._nestedValidate);
|
|
3060
3062
|
paths = shouldValidateModifiedOnly ?
|
|
3061
3063
|
pathDetails[0].filter((path) => this.$isModified(path)) :
|
|
3062
3064
|
pathDetails[0];
|
|
@@ -3124,7 +3126,7 @@ Document.prototype.$__validate = async function $__validate(pathsToValidate, opt
|
|
|
3124
3126
|
let pop;
|
|
3125
3127
|
if ((pop = _this.$populated(path))) {
|
|
3126
3128
|
val = pop;
|
|
3127
|
-
} else if (val
|
|
3129
|
+
} else if (val?.$__?.wasPopulated) {
|
|
3128
3130
|
// Array paths, like `somearray.1`, do not show up as populated with `$populated()`,
|
|
3129
3131
|
// so in that case pull out the document's id
|
|
3130
3132
|
val = val._doc._id;
|
|
@@ -3240,9 +3242,9 @@ Document.prototype.validateSync = function(pathsToValidate, options) {
|
|
|
3240
3242
|
shouldValidateModifiedOnly = this.$__schema.options.validateModifiedOnly;
|
|
3241
3243
|
}
|
|
3242
3244
|
|
|
3243
|
-
let pathsToSkip = options
|
|
3245
|
+
let pathsToSkip = options?.pathsToSkip;
|
|
3244
3246
|
|
|
3245
|
-
const validateAllPaths = options
|
|
3247
|
+
const validateAllPaths = options?.validateAllPaths;
|
|
3246
3248
|
if (validateAllPaths) {
|
|
3247
3249
|
if (pathsToSkip) {
|
|
3248
3250
|
throw new TypeError('Cannot set both `validateAllPaths` and `pathsToSkip`');
|
|
@@ -3268,7 +3270,7 @@ Document.prototype.validateSync = function(pathsToValidate, options) {
|
|
|
3268
3270
|
// the children as well
|
|
3269
3271
|
for (const path of paths) {
|
|
3270
3272
|
const schemaType = this.$__schema.path(path);
|
|
3271
|
-
if (!schemaType
|
|
3273
|
+
if (!schemaType?.$isMongooseArray) {
|
|
3272
3274
|
continue;
|
|
3273
3275
|
}
|
|
3274
3276
|
const val = this.$__getValue(path);
|
|
@@ -3409,12 +3411,12 @@ Document.prototype.invalidate = function(path, err, val, kind) {
|
|
|
3409
3411
|
*/
|
|
3410
3412
|
|
|
3411
3413
|
Document.prototype.$markValid = function(path) {
|
|
3412
|
-
if (!this.$__.validationError
|
|
3414
|
+
if (!this.$__.validationError?.errors[path]) {
|
|
3413
3415
|
return;
|
|
3414
3416
|
}
|
|
3415
3417
|
|
|
3416
3418
|
delete this.$__.validationError.errors[path];
|
|
3417
|
-
if (
|
|
3419
|
+
if (utils.hasOwnKeys(this.$__.validationError.errors) === false) {
|
|
3418
3420
|
this.$__.validationError = null;
|
|
3419
3421
|
}
|
|
3420
3422
|
};
|
|
@@ -3434,7 +3436,7 @@ function _markValidSubpaths(doc, path) {
|
|
|
3434
3436
|
delete doc.$__.validationError.errors[key];
|
|
3435
3437
|
}
|
|
3436
3438
|
}
|
|
3437
|
-
if (
|
|
3439
|
+
if (utils.hasOwnKeys(doc.$__.validationError.errors) === false) {
|
|
3438
3440
|
doc.$__.validationError = null;
|
|
3439
3441
|
}
|
|
3440
3442
|
}
|
|
@@ -3509,7 +3511,7 @@ function _checkImmutableSubpaths(subdoc, schematype, priorVal) {
|
|
|
3509
3511
|
*/
|
|
3510
3512
|
|
|
3511
3513
|
Document.prototype.$isValid = function(path) {
|
|
3512
|
-
if (this.$__.validationError == null ||
|
|
3514
|
+
if (this.$__.validationError == null || utils.hasOwnKeys(this.$__.validationError.errors) === false) {
|
|
3513
3515
|
return true;
|
|
3514
3516
|
}
|
|
3515
3517
|
if (path == null) {
|
|
@@ -3541,7 +3543,7 @@ Document.prototype.$__reset = function reset() {
|
|
|
3541
3543
|
|
|
3542
3544
|
// Skip for subdocuments
|
|
3543
3545
|
const subdocs = !this.$isSubdocument ? this.$getAllSubdocs({ useCache: true }) : null;
|
|
3544
|
-
if (subdocs
|
|
3546
|
+
if (subdocs?.length > 0) {
|
|
3545
3547
|
for (const subdoc of subdocs) {
|
|
3546
3548
|
subdoc.$__reset();
|
|
3547
3549
|
}
|
|
@@ -3551,7 +3553,9 @@ Document.prototype.$__reset = function reset() {
|
|
|
3551
3553
|
this.$__dirty().forEach(function(dirt) {
|
|
3552
3554
|
const type = dirt.value;
|
|
3553
3555
|
|
|
3554
|
-
if (type && type
|
|
3556
|
+
if (type && typeof type.clearAtomics === 'function') {
|
|
3557
|
+
type.clearAtomics();
|
|
3558
|
+
} else if (type && type[arrayAtomicsSymbol]) {
|
|
3555
3559
|
type[arrayAtomicsBackupSymbol] = type[arrayAtomicsSymbol];
|
|
3556
3560
|
type[arrayAtomicsSymbol] = {};
|
|
3557
3561
|
}
|
|
@@ -3583,7 +3587,7 @@ Document.prototype.$__reset = function reset() {
|
|
|
3583
3587
|
*/
|
|
3584
3588
|
|
|
3585
3589
|
Document.prototype.$__undoReset = function $__undoReset() {
|
|
3586
|
-
if (this.$__.backup
|
|
3590
|
+
if (this.$__.backup?.activePaths == null) {
|
|
3587
3591
|
return;
|
|
3588
3592
|
}
|
|
3589
3593
|
|
|
@@ -3596,7 +3600,7 @@ Document.prototype.$__undoReset = function $__undoReset() {
|
|
|
3596
3600
|
for (const dirt of this.$__dirty()) {
|
|
3597
3601
|
const type = dirt.value;
|
|
3598
3602
|
|
|
3599
|
-
if (type
|
|
3603
|
+
if (type?.[arrayAtomicsSymbol] && type[arrayAtomicsBackupSymbol]) {
|
|
3600
3604
|
type[arrayAtomicsSymbol] = type[arrayAtomicsBackupSymbol];
|
|
3601
3605
|
}
|
|
3602
3606
|
}
|
|
@@ -3764,14 +3768,14 @@ Document.prototype.$getAllSubdocs = function(options) {
|
|
|
3764
3768
|
}
|
|
3765
3769
|
if (Array.isArray(val)) {
|
|
3766
3770
|
for (const el of val) {
|
|
3767
|
-
if (el
|
|
3771
|
+
if (el?.$__) {
|
|
3768
3772
|
newSubdocs.push(el);
|
|
3769
3773
|
}
|
|
3770
3774
|
}
|
|
3771
3775
|
}
|
|
3772
3776
|
if (val instanceof Map) {
|
|
3773
3777
|
for (const el of val.values()) {
|
|
3774
|
-
if (el
|
|
3778
|
+
if (el?.$__) {
|
|
3775
3779
|
newSubdocs.push(el);
|
|
3776
3780
|
}
|
|
3777
3781
|
}
|
|
@@ -3818,7 +3822,7 @@ Document.prototype.$__handleReject = function handleReject(err) {
|
|
|
3818
3822
|
// emit on the Model if listening
|
|
3819
3823
|
if (this.$listeners('error').length) {
|
|
3820
3824
|
this.$emit('error', err);
|
|
3821
|
-
} else if (this.constructor.listeners
|
|
3825
|
+
} else if (this.constructor.listeners?.('error').length) {
|
|
3822
3826
|
this.constructor.emit('error', err);
|
|
3823
3827
|
}
|
|
3824
3828
|
};
|
|
@@ -3847,7 +3851,7 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
3847
3851
|
_minimize = options.minimize;
|
|
3848
3852
|
} else if (this.$__schemaTypeOptions?.minimize != null) {
|
|
3849
3853
|
_minimize = this.$__schemaTypeOptions.minimize;
|
|
3850
|
-
} else if (defaultOptions
|
|
3854
|
+
} else if (defaultOptions?.minimize != null) {
|
|
3851
3855
|
_minimize = defaultOptions.minimize;
|
|
3852
3856
|
} else {
|
|
3853
3857
|
_minimize = this.$__schema.options.minimize;
|
|
@@ -4171,7 +4175,7 @@ function applyVirtuals(self, json, options, toObjectOptions) {
|
|
|
4171
4175
|
let assignPath;
|
|
4172
4176
|
let cur = self._doc;
|
|
4173
4177
|
let v;
|
|
4174
|
-
const aliases = typeof
|
|
4178
|
+
const aliases = typeof toObjectOptions?.aliases === 'boolean'
|
|
4175
4179
|
? toObjectOptions.aliases
|
|
4176
4180
|
: true;
|
|
4177
4181
|
|
|
@@ -4179,7 +4183,7 @@ function applyVirtuals(self, json, options, toObjectOptions) {
|
|
|
4179
4183
|
let virtualsToApply = null;
|
|
4180
4184
|
if (Array.isArray(options.virtuals)) {
|
|
4181
4185
|
virtualsToApply = new Set(options.virtuals);
|
|
4182
|
-
} else if (options.virtuals
|
|
4186
|
+
} else if (options.virtuals?.pathsToSkip) {
|
|
4183
4187
|
virtualsToApply = new Set(paths);
|
|
4184
4188
|
for (let i = 0; i < options.virtuals.pathsToSkip.length; i++) {
|
|
4185
4189
|
if (virtualsToApply.has(options.virtuals.pathsToSkip[i])) {
|
|
@@ -4387,7 +4391,7 @@ function omitDeselectedFields(self, json) {
|
|
|
4387
4391
|
selected = {};
|
|
4388
4392
|
queryhelpers.applyPaths(selected, schema);
|
|
4389
4393
|
}
|
|
4390
|
-
if (selected == null ||
|
|
4394
|
+
if (selected == null || utils.hasOwnKeys(selected) === false) {
|
|
4391
4395
|
return json;
|
|
4392
4396
|
}
|
|
4393
4397
|
|
|
@@ -4469,6 +4473,20 @@ Document.prototype.parent = function() {
|
|
|
4469
4473
|
|
|
4470
4474
|
Document.prototype.$parent = Document.prototype.parent;
|
|
4471
4475
|
|
|
4476
|
+
/**
|
|
4477
|
+
* Set the parent of this document.
|
|
4478
|
+
*
|
|
4479
|
+
* @param {Document} parent
|
|
4480
|
+
* @api private
|
|
4481
|
+
* @method $__setParent
|
|
4482
|
+
* @memberOf Document
|
|
4483
|
+
* @instance
|
|
4484
|
+
*/
|
|
4485
|
+
|
|
4486
|
+
Document.prototype.$__setParent = function $__setParent(parent) {
|
|
4487
|
+
this.$__.parent = parent;
|
|
4488
|
+
};
|
|
4489
|
+
|
|
4472
4490
|
/**
|
|
4473
4491
|
* Helper for console.log
|
|
4474
4492
|
*
|
|
@@ -4724,7 +4742,7 @@ Document.prototype.populated = function(path, val, options) {
|
|
|
4724
4742
|
for (let i = 0; i < pieces.length - 1; ++i) {
|
|
4725
4743
|
const subpath = pieces.slice(0, i + 1).join('.');
|
|
4726
4744
|
const subdoc = this.$get(subpath);
|
|
4727
|
-
if (subdoc
|
|
4745
|
+
if (subdoc?.$__ != null && this.$populated(subpath)) {
|
|
4728
4746
|
const rest = pieces.slice(i + 1).join('.');
|
|
4729
4747
|
subdoc.$populated(rest, val, options);
|
|
4730
4748
|
// No need to continue because the above recursion should take care of
|
|
@@ -4815,7 +4833,7 @@ Document.prototype.depopulate = function(path) {
|
|
|
4815
4833
|
|
|
4816
4834
|
let populatedIds;
|
|
4817
4835
|
const virtualKeys = this.$$populatedVirtuals ? Object.keys(this.$$populatedVirtuals) : [];
|
|
4818
|
-
const populated = this.$__
|
|
4836
|
+
const populated = this.$__?.populated || {};
|
|
4819
4837
|
|
|
4820
4838
|
if (arguments.length === 0) {
|
|
4821
4839
|
// Depopulate all
|
|
@@ -4964,7 +4982,13 @@ Document.prototype.$__delta = function $__delta() {
|
|
|
4964
4982
|
if (Array.isArray(optimisticConcurrency)) {
|
|
4965
4983
|
const optCon = new Set(optimisticConcurrency);
|
|
4966
4984
|
const modPaths = this.modifiedPaths();
|
|
4967
|
-
if (modPaths.
|
|
4985
|
+
if (modPaths.some(path => optCon.has(path))) {
|
|
4986
|
+
this.$__.version = dirty.length ? VERSION_ALL : VERSION_WHERE;
|
|
4987
|
+
}
|
|
4988
|
+
} else if (Array.isArray(optimisticConcurrency?.exclude)) {
|
|
4989
|
+
const excluded = new Set(optimisticConcurrency.exclude);
|
|
4990
|
+
const modPaths = this.modifiedPaths();
|
|
4991
|
+
if (modPaths.some(path => !excluded.has(path))) {
|
|
4968
4992
|
this.$__.version = dirty.length ? VERSION_ALL : VERSION_WHERE;
|
|
4969
4993
|
}
|
|
4970
4994
|
} else {
|
|
@@ -4984,7 +5008,7 @@ Document.prototype.$__delta = function $__delta() {
|
|
|
4984
5008
|
where._id = this._doc._id;
|
|
4985
5009
|
// If `_id` is an object, need to depopulate, but also need to be careful
|
|
4986
5010
|
// because `_id` can technically be null (see gh-6406)
|
|
4987
|
-
if (
|
|
5011
|
+
if (where?._id?.$__ != null) {
|
|
4988
5012
|
where._id = where._id.toObject({ transform: false, depopulate: true });
|
|
4989
5013
|
}
|
|
4990
5014
|
for (; d < len; ++d) {
|
|
@@ -5035,15 +5059,15 @@ Document.prototype.$__delta = function $__delta() {
|
|
|
5035
5059
|
operand(this, where, delta, data, 1, '$unset');
|
|
5036
5060
|
} else if (value === null) {
|
|
5037
5061
|
operand(this, where, delta, data, null);
|
|
5038
|
-
} else if (
|
|
5039
|
-
// arrays and other custom types
|
|
5062
|
+
} else if (typeof value.getAtomics === 'function') {
|
|
5063
|
+
// arrays and other custom container types
|
|
5040
5064
|
handleAtomics(this, where, delta, data, value);
|
|
5041
5065
|
} else if (value[MongooseBuffer.pathSymbol] && Buffer.isBuffer(value)) {
|
|
5042
5066
|
// MongooseBuffer
|
|
5043
5067
|
value = value.toObject();
|
|
5044
5068
|
operand(this, where, delta, data, value);
|
|
5045
5069
|
} else {
|
|
5046
|
-
if (this.$__.primitiveAtomics
|
|
5070
|
+
if (this.$__.primitiveAtomics?.[data.path] != null) {
|
|
5047
5071
|
const val = this.$__.primitiveAtomics[data.path];
|
|
5048
5072
|
const op = firstKey(val);
|
|
5049
5073
|
operand(this, where, delta, data, val[op], op);
|
|
@@ -5069,7 +5093,7 @@ Document.prototype.$__delta = function $__delta() {
|
|
|
5069
5093
|
this.$__version(where, delta);
|
|
5070
5094
|
}
|
|
5071
5095
|
|
|
5072
|
-
if (
|
|
5096
|
+
if (utils.hasOwnKeys(delta) === false) {
|
|
5073
5097
|
return [where, null];
|
|
5074
5098
|
}
|
|
5075
5099
|
|
|
@@ -5114,14 +5138,14 @@ function checkDivergentArray(doc, path, array) {
|
|
|
5114
5138
|
// elements of the array and potentially would overwrite data.
|
|
5115
5139
|
const check = pop.options.match ||
|
|
5116
5140
|
pop.options.options && Object.hasOwn(pop.options.options, 'limit') || // 0 is not permitted
|
|
5117
|
-
pop.options.options
|
|
5141
|
+
pop.options.options?.skip || // 0 is permitted
|
|
5118
5142
|
pop.options.select && // deselected _id?
|
|
5119
5143
|
(pop.options.select._id === 0 ||
|
|
5120
5144
|
/\s?-_id\s?/.test(pop.options.select));
|
|
5121
5145
|
|
|
5122
5146
|
if (check) {
|
|
5123
5147
|
const atomics = array[arrayAtomicsSymbol];
|
|
5124
|
-
if (
|
|
5148
|
+
if (utils.hasOwnKeys(atomics) === false || atomics.$set || atomics.$pop) {
|
|
5125
5149
|
return path;
|
|
5126
5150
|
}
|
|
5127
5151
|
}
|
|
@@ -5154,7 +5178,11 @@ function operand(self, where, delta, data, val, op) {
|
|
|
5154
5178
|
// already marked for versioning?
|
|
5155
5179
|
if (VERSION_ALL === (VERSION_ALL & self.$__.version)) return;
|
|
5156
5180
|
|
|
5157
|
-
if (
|
|
5181
|
+
if (
|
|
5182
|
+
self.$__schema.options.optimisticConcurrency === true ||
|
|
5183
|
+
Array.isArray(self.$__schema.options.optimisticConcurrency) ||
|
|
5184
|
+
Array.isArray(self.$__schema.options.optimisticConcurrency?.exclude)
|
|
5185
|
+
) {
|
|
5158
5186
|
return;
|
|
5159
5187
|
}
|
|
5160
5188
|
|
|
@@ -5208,11 +5236,20 @@ function operand(self, where, delta, data, val, op) {
|
|
|
5208
5236
|
*/
|
|
5209
5237
|
|
|
5210
5238
|
function handleAtomics(self, where, delta, data, value) {
|
|
5211
|
-
if (delta.$set
|
|
5239
|
+
if (delta.$set?.[data.path]) {
|
|
5212
5240
|
// $set has precedence over other atomics
|
|
5213
5241
|
return;
|
|
5214
5242
|
}
|
|
5215
5243
|
|
|
5244
|
+
if (typeof value.getAtomics === 'function') {
|
|
5245
|
+
value.getAtomics().forEach(function(atomic) {
|
|
5246
|
+
const op = atomic[0];
|
|
5247
|
+
const val = atomic[1];
|
|
5248
|
+
operand(self, where, delta, data, val, op);
|
|
5249
|
+
});
|
|
5250
|
+
return;
|
|
5251
|
+
}
|
|
5252
|
+
|
|
5216
5253
|
if (typeof value.$__getAtomics === 'function') {
|
|
5217
5254
|
value.$__getAtomics().forEach(function(atomic) {
|
|
5218
5255
|
const op = atomic[0];
|
|
@@ -5301,7 +5338,7 @@ Document.prototype.$clone = function() {
|
|
|
5301
5338
|
const clonedDoc = new Model();
|
|
5302
5339
|
clonedDoc.$isNew = this.$isNew;
|
|
5303
5340
|
if (this._doc) {
|
|
5304
|
-
clonedDoc._doc = clone(this._doc, { retainDocuments: true });
|
|
5341
|
+
clonedDoc._doc = clone(this._doc, { retainDocuments: true, parentDoc: clonedDoc });
|
|
5305
5342
|
}
|
|
5306
5343
|
if (this.$__) {
|
|
5307
5344
|
const Cache = this.$__.constructor;
|
|
@@ -5312,7 +5349,10 @@ Document.prototype.$clone = function() {
|
|
|
5312
5349
|
}
|
|
5313
5350
|
clonedCache[key] = clone(this.$__[key]);
|
|
5314
5351
|
}
|
|
5315
|
-
Object.assign(
|
|
5352
|
+
Object.assign(
|
|
5353
|
+
clonedCache.activePaths,
|
|
5354
|
+
clone({ ...this.$__.activePaths })
|
|
5355
|
+
);
|
|
5316
5356
|
clonedDoc.$__ = clonedCache;
|
|
5317
5357
|
}
|
|
5318
5358
|
return clonedDoc;
|