@depup/mongoose 9.8.0-depup.0 → 9.9.0-depup.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/README.md +2 -2
- package/changes.json +1 -1
- package/lib/connection.js +1 -9
- package/lib/document.js +229 -130
- package/lib/helpers/document/applyDefaults.js +71 -7
- package/lib/helpers/model/castBulkWrite.js +2 -2
- package/lib/helpers/parallelLimit.js +41 -16
- package/lib/helpers/query/castUpdate.js +27 -10
- package/lib/helpers/schema/idGetter.js +3 -0
- package/lib/helpers/timestamps/setupTimestamps.js +1 -0
- package/lib/helpers/update/applyTimestampsToUpdate.js +4 -5
- package/lib/model.js +71 -52
- package/lib/schema.js +44 -2
- package/lib/schemaType.js +4 -3
- package/lib/stateMachine.js +22 -3
- package/lib/utils.js +3 -2
- package/package.json +3 -3
- package/types/index.d.ts +2 -0
- package/types/inferhydrateddoctype.d.ts +19 -3
- package/types/inferrawdoctype.d.ts +19 -3
- package/types/models.d.ts +11 -2
- package/types/schemaoptions.d.ts +1 -0
- package/types/schematypes.d.ts +1 -1
package/README.md
CHANGED
|
@@ -13,8 +13,8 @@ npm install @depup/mongoose
|
|
|
13
13
|
|
|
14
14
|
| Field | Value |
|
|
15
15
|
|-------|-------|
|
|
16
|
-
| Original | [mongoose](https://www.npmjs.com/package/mongoose) @ 9.
|
|
17
|
-
| Processed | 2026-07-
|
|
16
|
+
| Original | [mongoose](https://www.npmjs.com/package/mongoose) @ 9.9.0 |
|
|
17
|
+
| Processed | 2026-07-30 |
|
|
18
18
|
| Smoke test | passed |
|
|
19
19
|
| Deps updated | 0 |
|
|
20
20
|
|
package/changes.json
CHANGED
package/lib/connection.js
CHANGED
|
@@ -779,16 +779,8 @@ function _resetSessionDocuments(session) {
|
|
|
779
779
|
doc.set(doc.schema.options.versionKey, state.versionKey);
|
|
780
780
|
}
|
|
781
781
|
|
|
782
|
-
if (state.modifiedPaths.length > 0 && doc.$__.activePaths.states.modify == null) {
|
|
783
|
-
doc.$__.activePaths.states.modify = {};
|
|
784
|
-
}
|
|
785
782
|
for (const path of state.modifiedPaths) {
|
|
786
|
-
|
|
787
|
-
if (currentState != null) {
|
|
788
|
-
delete doc.$__.activePaths[currentState][path];
|
|
789
|
-
}
|
|
790
|
-
doc.$__.activePaths.paths[path] = 'modify';
|
|
791
|
-
doc.$__.activePaths.states.modify[path] = true;
|
|
783
|
+
doc.$__.activePaths.modify(path);
|
|
792
784
|
}
|
|
793
785
|
|
|
794
786
|
for (const path of state.atomics.keys()) {
|
package/lib/document.js
CHANGED
|
@@ -49,6 +49,8 @@ const isPromise = require('./helpers/isPromise');
|
|
|
49
49
|
const deepEqual = utils.deepEqual;
|
|
50
50
|
const isMongooseObject = utils.isMongooseObject;
|
|
51
51
|
|
|
52
|
+
const applyDefaultsBeforeSettersOptions = Object.freeze({ skipParentChangeTracking: true });
|
|
53
|
+
|
|
52
54
|
const arrayAtomicsBackupSymbol = require('./helpers/symbols').arrayAtomicsBackupSymbol;
|
|
53
55
|
const arrayAtomicsSymbol = require('./helpers/symbols').arrayAtomicsSymbol;
|
|
54
56
|
const documentArrayParent = require('./helpers/symbols').documentArrayParent;
|
|
@@ -91,7 +93,7 @@ function Document(obj, fields, options) {
|
|
|
91
93
|
if (typeof options === 'boolean') {
|
|
92
94
|
throw new Error('The skipId parameter has been removed. Use { skipId: true } in the options parameter instead.');
|
|
93
95
|
}
|
|
94
|
-
options = Object.assign({}, options);
|
|
96
|
+
options = options == null ? {} : Object.assign({}, options);
|
|
95
97
|
let skipId = options.skipId;
|
|
96
98
|
|
|
97
99
|
this.$__ = new InternalCache();
|
|
@@ -143,7 +145,7 @@ function Document(obj, fields, options) {
|
|
|
143
145
|
this.$__.strictMode = schema.options.strict;
|
|
144
146
|
}
|
|
145
147
|
|
|
146
|
-
const requiredPaths = schema.requiredPaths(
|
|
148
|
+
const requiredPaths = schema.requiredPaths();
|
|
147
149
|
for (const path of requiredPaths) {
|
|
148
150
|
this.$__.activePaths.require(path);
|
|
149
151
|
}
|
|
@@ -162,15 +164,14 @@ function Document(obj, fields, options) {
|
|
|
162
164
|
$__hasIncludedChildren(fields) :
|
|
163
165
|
null;
|
|
164
166
|
|
|
167
|
+
let hasPostSetterDefaults = true;
|
|
165
168
|
if (this._doc == null) {
|
|
166
169
|
this.$__buildDoc(obj, fields, skipId, exclude, hasIncludedChildren, false);
|
|
167
170
|
|
|
168
171
|
// By default, defaults get applied **before** setting initial values
|
|
169
172
|
// Re: gh-6155
|
|
170
173
|
if (defaults) {
|
|
171
|
-
applyDefaults(this, fields, exclude, hasIncludedChildren, true, null,
|
|
172
|
-
skipParentChangeTracking: true
|
|
173
|
-
});
|
|
174
|
+
hasPostSetterDefaults = applyDefaults(this, fields, exclude, hasIncludedChildren, true, null, applyDefaultsBeforeSettersOptions);
|
|
174
175
|
}
|
|
175
176
|
}
|
|
176
177
|
if (obj) {
|
|
@@ -181,7 +182,7 @@ function Document(obj, fields, options) {
|
|
|
181
182
|
this.$set(obj, undefined, true, options);
|
|
182
183
|
}
|
|
183
184
|
|
|
184
|
-
if (obj instanceof Document) {
|
|
185
|
+
if (obj.$__ != null && obj instanceof Document) {
|
|
185
186
|
this.$isNew = obj.$isNew;
|
|
186
187
|
}
|
|
187
188
|
}
|
|
@@ -193,7 +194,7 @@ function Document(obj, fields, options) {
|
|
|
193
194
|
if (options.skipDefaults) {
|
|
194
195
|
this.$__.skipDefaults = options.skipDefaults;
|
|
195
196
|
}
|
|
196
|
-
} else if (defaults) {
|
|
197
|
+
} else if (defaults && hasPostSetterDefaults) {
|
|
197
198
|
applyDefaults(this, fields, exclude, hasIncludedChildren, false, options.skipDefaults);
|
|
198
199
|
}
|
|
199
200
|
|
|
@@ -560,6 +561,14 @@ function $applyDefaultsToNested(val, path, doc) {
|
|
|
560
561
|
*/
|
|
561
562
|
|
|
562
563
|
Document.prototype.$__buildDoc = function(obj, fields, skipId, exclude, hasIncludedChildren) {
|
|
564
|
+
// This function only creates intermediate objects for nested paths (e.g.
|
|
565
|
+
// `{ nested: {} }` for path `nested.name`), so if the schema has no nested
|
|
566
|
+
// paths then `_doc` starts out empty.
|
|
567
|
+
if (!utils.hasOwnKeys(this.$__schema.nested)) {
|
|
568
|
+
this._doc = {};
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
|
|
563
572
|
const doc = {};
|
|
564
573
|
|
|
565
574
|
const paths = Object.keys(this.$__schema.paths);
|
|
@@ -1927,7 +1936,13 @@ Document.prototype.$inc = function $inc(path, val) {
|
|
|
1927
1936
|
* @api private
|
|
1928
1937
|
*/
|
|
1929
1938
|
|
|
1930
|
-
Document.prototype.$__setValue = function(path, val) {
|
|
1939
|
+
Document.prototype.$__setValue = function $__setValue(path, val) {
|
|
1940
|
+
if (Array.isArray(path) && path.length === 1) {
|
|
1941
|
+
// Fast path: if pre-split paths array of length 1, avoid all
|
|
1942
|
+
// setValue overhead and just set the value directly.
|
|
1943
|
+
this._doc[path[0]] = val;
|
|
1944
|
+
return this;
|
|
1945
|
+
}
|
|
1931
1946
|
utils.setValue(path, val, this._doc);
|
|
1932
1947
|
return this;
|
|
1933
1948
|
};
|
|
@@ -2007,7 +2022,7 @@ Document.prototype.get = function(path, type, options) {
|
|
|
2007
2022
|
return undefined;
|
|
2008
2023
|
}
|
|
2009
2024
|
|
|
2010
|
-
if (obj
|
|
2025
|
+
if (obj && obj._doc) {
|
|
2011
2026
|
obj = obj._doc;
|
|
2012
2027
|
}
|
|
2013
2028
|
|
|
@@ -2582,18 +2597,18 @@ Document.prototype.isSelected = function isSelected(path) {
|
|
|
2582
2597
|
return inclusive;
|
|
2583
2598
|
}
|
|
2584
2599
|
|
|
2585
|
-
const
|
|
2600
|
+
const pathHasDot = path.indexOf('.') !== -1;
|
|
2586
2601
|
|
|
2587
2602
|
for (const cur of paths) {
|
|
2588
2603
|
if (cur === '_id') {
|
|
2589
2604
|
continue;
|
|
2590
2605
|
}
|
|
2591
2606
|
|
|
2592
|
-
if (cur.
|
|
2593
|
-
return inclusive || cur !==
|
|
2607
|
+
if (cur.charAt(path.length) === '.' && cur.slice(0, path.length) === path) {
|
|
2608
|
+
return inclusive || cur !== path + '.';
|
|
2594
2609
|
}
|
|
2595
2610
|
|
|
2596
|
-
if (
|
|
2611
|
+
if (pathHasDot && path.charAt(cur.length) === '.' && path.slice(0, cur.length) === cur) {
|
|
2597
2612
|
return inclusive;
|
|
2598
2613
|
}
|
|
2599
2614
|
}
|
|
@@ -2713,11 +2728,22 @@ Document.prototype.validate = async function validate(pathsToValidate, options)
|
|
|
2713
2728
|
this.$__.validating = true;
|
|
2714
2729
|
}
|
|
2715
2730
|
|
|
2731
|
+
const hasValidateHooks = this.$__middleware.hasHooks('validate');
|
|
2716
2732
|
try {
|
|
2717
2733
|
try {
|
|
2718
|
-
|
|
2734
|
+
if (hasValidateHooks) {
|
|
2735
|
+
[options] = await this._execDocumentPreHooks('validate', options, [options]);
|
|
2736
|
+
} else if (!_skipParallelValidateCheck) {
|
|
2737
|
+
// Even with no validate hooks, preserve the async boundary that the pre
|
|
2738
|
+
// hook `await` used to provide so that the parallel validate check still
|
|
2739
|
+
// observes `$__.validating` across a tick (gh-8468). insertMany's per-doc
|
|
2740
|
+
// validate passes `_skipParallelValidateCheck` and stays fully synchronous.
|
|
2741
|
+
await Promise.resolve();
|
|
2742
|
+
}
|
|
2719
2743
|
} catch (error) {
|
|
2720
|
-
|
|
2744
|
+
if (hasValidateHooks) {
|
|
2745
|
+
await this._execDocumentPostHooks('validate', options, error);
|
|
2746
|
+
}
|
|
2721
2747
|
return;
|
|
2722
2748
|
}
|
|
2723
2749
|
|
|
@@ -2789,7 +2815,11 @@ Document.prototype.validate = async function validate(pathsToValidate, options)
|
|
|
2789
2815
|
if (paths.length === 0) {
|
|
2790
2816
|
const error = _completeValidate(this);
|
|
2791
2817
|
|
|
2792
|
-
|
|
2818
|
+
if (hasValidateHooks) {
|
|
2819
|
+
await this._execDocumentPostHooks('validate', options, error);
|
|
2820
|
+
} else if (error != null) {
|
|
2821
|
+
throw error;
|
|
2822
|
+
}
|
|
2793
2823
|
return;
|
|
2794
2824
|
}
|
|
2795
2825
|
|
|
@@ -2884,7 +2914,11 @@ Document.prototype.validate = async function validate(pathsToValidate, options)
|
|
|
2884
2914
|
|
|
2885
2915
|
const error = _completeValidate(this);
|
|
2886
2916
|
|
|
2887
|
-
|
|
2917
|
+
if (hasValidateHooks) {
|
|
2918
|
+
await this._execDocumentPostHooks('validate', options, error);
|
|
2919
|
+
} else if (error != null) {
|
|
2920
|
+
throw error;
|
|
2921
|
+
}
|
|
2888
2922
|
} finally {
|
|
2889
2923
|
// Assign rather than `delete` to avoid putting `$__` in dictionary mode
|
|
2890
2924
|
this.$__.validateModifiedOnly = undefined;
|
|
@@ -2947,25 +2981,8 @@ function _completeValidate(doc) {
|
|
|
2947
2981
|
return error;
|
|
2948
2982
|
}
|
|
2949
2983
|
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
let i = 0;
|
|
2953
|
-
const len = requiredFields.length;
|
|
2954
|
-
for (i = 0; i < len; ++i) {
|
|
2955
|
-
const path = requiredFields[i];
|
|
2956
|
-
|
|
2957
|
-
const p = doc.$__schema.path(path);
|
|
2958
|
-
|
|
2959
|
-
if (typeof p?.originalRequiredValue === 'function') {
|
|
2960
|
-
doc.$__.cachedRequired = doc.$__.cachedRequired || {};
|
|
2961
|
-
try {
|
|
2962
|
-
doc.$__.cachedRequired[path] = p.originalRequiredValue.call(doc, doc);
|
|
2963
|
-
} catch (err) {
|
|
2964
|
-
doc.invalidate(path, err);
|
|
2965
|
-
}
|
|
2966
|
-
}
|
|
2967
|
-
}
|
|
2968
|
-
}
|
|
2984
|
+
const STATES_TO_VALIDATE = Object.freeze(['init', 'default', 'modify']);
|
|
2985
|
+
const STAR_CHAR_CODE = '*'.charCodeAt(0);
|
|
2969
2986
|
|
|
2970
2987
|
/*!
|
|
2971
2988
|
* ignore
|
|
@@ -2973,65 +2990,103 @@ function _evaluateRequiredFunctions(doc) {
|
|
|
2973
2990
|
|
|
2974
2991
|
function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate) {
|
|
2975
2992
|
const doValidateOptions = {};
|
|
2993
|
+
const schema = doc.$__schema;
|
|
2994
|
+
const schemaPaths = schema.paths;
|
|
2995
|
+
const activeStates = doc.$__.activePaths.states;
|
|
2996
|
+
|
|
2997
|
+
// gh-16379: compute the modified-path set at most once and reuse it below, so
|
|
2998
|
+
// checking many required paths doesn't rebuild it per-path (O(required x modified)).
|
|
2999
|
+
let _modifiedPaths;
|
|
3000
|
+
const getModifiedPaths = () => (_modifiedPaths ??= doc.modifiedPaths());
|
|
2976
3001
|
|
|
2977
|
-
_evaluateRequiredFunctions(doc);
|
|
2978
3002
|
// only validate required fields when necessary
|
|
2979
|
-
let paths =
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
//
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
3003
|
+
let paths = [];
|
|
3004
|
+
const requireStates = activeStates.require;
|
|
3005
|
+
if (requireStates != null) {
|
|
3006
|
+
let modifiedPaths = null;
|
|
3007
|
+
for (const path in requireStates) {
|
|
3008
|
+
// Evaluate function-valued `required` for every required path, before any
|
|
3009
|
+
// filtering, so `invalidate()` calls and `cachedRequired` entries stay
|
|
3010
|
+
// consistent no matter which paths end up validated.
|
|
3011
|
+
const type = Object.hasOwn(schemaPaths, path) ? schemaPaths[path] : schema.path(path);
|
|
3012
|
+
if (typeof type?.originalRequiredValue === 'function') {
|
|
3013
|
+
const cachedRequired = doc.$__.cachedRequired ?? (doc.$__.cachedRequired = {});
|
|
3014
|
+
try {
|
|
3015
|
+
cachedRequired[path] = type.originalRequiredValue.call(doc, doc);
|
|
3016
|
+
} catch (err) {
|
|
3017
|
+
doc.invalidate(path, err);
|
|
3018
|
+
}
|
|
3019
|
+
}
|
|
3020
|
+
|
|
3021
|
+
if (!doc.$__isSelected(path)) {
|
|
3022
|
+
if (modifiedPaths === null) {
|
|
3023
|
+
modifiedPaths = doc.modifiedPaths();
|
|
3024
|
+
}
|
|
3025
|
+
if (!doc.$isModified(path, null, modifiedPaths)) {
|
|
3026
|
+
continue;
|
|
3027
|
+
}
|
|
3028
|
+
}
|
|
3029
|
+
if (path.charCodeAt(path.length - 1) === STAR_CHAR_CODE && path.endsWith('.$*')) {
|
|
3030
|
+
// Skip $* paths - they represent map schemas, not actual document paths
|
|
3031
|
+
continue;
|
|
3032
|
+
}
|
|
3033
|
+
const cachedRequired = doc.$__.cachedRequired;
|
|
3034
|
+
if (cachedRequired != null && path in cachedRequired) {
|
|
3035
|
+
if (cachedRequired[path]) {
|
|
3036
|
+
paths.push(path);
|
|
3037
|
+
}
|
|
3038
|
+
} else {
|
|
3039
|
+
paths.push(path);
|
|
3040
|
+
}
|
|
2989
3041
|
}
|
|
2990
|
-
|
|
2991
|
-
}));
|
|
3042
|
+
}
|
|
2992
3043
|
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
if (p.endsWith('.$*')) {
|
|
2998
|
-
// Skip $* paths - they represent map schemas, not actual document paths
|
|
2999
|
-
return;
|
|
3044
|
+
for (let i = 0; i < STATES_TO_VALIDATE.length; ++i) {
|
|
3045
|
+
const statePaths = activeStates[STATES_TO_VALIDATE[i]];
|
|
3046
|
+
if (statePaths == null) {
|
|
3047
|
+
continue;
|
|
3000
3048
|
}
|
|
3049
|
+
for (const p in statePaths) {
|
|
3050
|
+
if (p.charCodeAt(p.length - 1) === STAR_CHAR_CODE && p.endsWith('.$*')) {
|
|
3051
|
+
// Skip $* paths - they represent map schemas, not actual document paths
|
|
3052
|
+
continue;
|
|
3053
|
+
}
|
|
3001
3054
|
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3055
|
+
const _pathType = Object.hasOwn(schemaPaths, p) ? schemaPaths[p] : schema.path(p);
|
|
3056
|
+
|
|
3057
|
+
// Optimization: if primitive path with no validators, or array of primitives
|
|
3058
|
+
// with no validators, skip validating this path entirely.
|
|
3059
|
+
// Note: paths with no _pathType (e.g. sub-paths under Mixed) must still be
|
|
3060
|
+
// added, as they trigger validation of the parent Mixed path.
|
|
3061
|
+
if (_pathType) {
|
|
3062
|
+
if (!_pathType.schema &&
|
|
3063
|
+
!_pathType.embeddedSchemaType &&
|
|
3064
|
+
_pathType.validators.length === 0 &&
|
|
3065
|
+
!_pathType.$parentSchemaDocArray &&
|
|
3066
|
+
// gh-15957: skip this optimization for SchemaMap as maps can contain subdocuments
|
|
3067
|
+
// that need validation even if the map itself has no validators
|
|
3068
|
+
!_pathType.$isSchemaMap &&
|
|
3069
|
+
!_pathType.$isSchemaUnion) {
|
|
3070
|
+
continue;
|
|
3071
|
+
} else if (_pathType.$isMongooseArray &&
|
|
3072
|
+
!_pathType.$isMongooseDocumentArray && // Skip document arrays...
|
|
3073
|
+
!_pathType.embeddedSchemaType.$isMongooseArray && // and arrays of arrays
|
|
3074
|
+
_pathType.validators.length === 0 && // and arrays with top-level validators
|
|
3075
|
+
_pathType.embeddedSchemaType.validators.length === 0) {
|
|
3076
|
+
continue;
|
|
3077
|
+
}
|
|
3024
3078
|
}
|
|
3025
|
-
}
|
|
3026
3079
|
|
|
3027
|
-
|
|
3080
|
+
paths.push(p);
|
|
3081
|
+
}
|
|
3028
3082
|
}
|
|
3029
3083
|
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
return [[], doValidateOptions];
|
|
3084
|
+
if (paths.length === 0 && doc.$__hasOnlyPrimitiveValues()) {
|
|
3085
|
+
return [paths, doValidateOptions];
|
|
3033
3086
|
}
|
|
3034
3087
|
|
|
3088
|
+
paths = new Set(paths);
|
|
3089
|
+
|
|
3035
3090
|
if (!isNestedValidate) {
|
|
3036
3091
|
// If we're validating a subdocument, all this logic will run anyway on the top-level document, so skip for subdocuments.
|
|
3037
3092
|
// But only run for top-level subdocuments, because we're looking for subdocuments that are not modified at top-level but
|
|
@@ -3056,7 +3111,19 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate
|
|
|
3056
3111
|
}
|
|
3057
3112
|
}
|
|
3058
3113
|
}
|
|
3059
|
-
const modifiedPaths =
|
|
3114
|
+
const modifiedPaths = getModifiedPaths();
|
|
3115
|
+
|
|
3116
|
+
// gh-6818: if a document array that has array-level validators has any
|
|
3117
|
+
// modified element, validate the array itself so those validators run.
|
|
3118
|
+
for (const modifiedPath of modifiedPaths) {
|
|
3119
|
+
const modifiedPathType = doc.$__schema.path(modifiedPath);
|
|
3120
|
+
if (modifiedPathType != null &&
|
|
3121
|
+
modifiedPathType.$isMongooseDocumentArray &&
|
|
3122
|
+
modifiedPathType.validators.length > 0) {
|
|
3123
|
+
paths.add(modifiedPath);
|
|
3124
|
+
}
|
|
3125
|
+
}
|
|
3126
|
+
|
|
3060
3127
|
for (const subdoc of topLevelSubdocs) {
|
|
3061
3128
|
if (subdoc.$basePath) {
|
|
3062
3129
|
const fullPathToSubdoc = subdoc.$__pathRelativeToParent();
|
|
@@ -3096,7 +3163,7 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate
|
|
|
3096
3163
|
}
|
|
3097
3164
|
}
|
|
3098
3165
|
|
|
3099
|
-
if (!
|
|
3166
|
+
if (!doc.$__hasOnlyPrimitiveValues()) {
|
|
3100
3167
|
for (const path of paths) {
|
|
3101
3168
|
const _pathType = doc.$__schema.path(path);
|
|
3102
3169
|
if (_pathType && _pathType.$isMongooseDocumentArray) {
|
|
@@ -3135,8 +3202,8 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate
|
|
|
3135
3202
|
// Re: gh-8468
|
|
3136
3203
|
const singleNestedPaths = doc.$__schema.singleNestedPaths;
|
|
3137
3204
|
for (const path of Object.keys(flat)) {
|
|
3138
|
-
if (!Object.hasOwn(singleNestedPaths, path)) {
|
|
3139
|
-
|
|
3205
|
+
if (!Object.hasOwn(singleNestedPaths, path) && !path.endsWith('.$*')) {
|
|
3206
|
+
paths.add(path);
|
|
3140
3207
|
}
|
|
3141
3208
|
}
|
|
3142
3209
|
}
|
|
@@ -3628,23 +3695,23 @@ Document.prototype.$isValid = function(path) {
|
|
|
3628
3695
|
* Resets the internal modified state of this document.
|
|
3629
3696
|
*
|
|
3630
3697
|
* @api private
|
|
3698
|
+
* @param {boolean} [skipBackup] If `true`, skips the backup of modified paths for performance
|
|
3699
|
+
* @param {boolean} [hasOnlyPrimitiveValues] Precalculate `$__hasOnlyPrimitiveValues()` for performance
|
|
3631
3700
|
* @return {Document} this
|
|
3632
3701
|
* @method $__reset
|
|
3633
3702
|
* @memberOf Document
|
|
3634
3703
|
* @instance
|
|
3635
3704
|
*/
|
|
3636
3705
|
|
|
3637
|
-
Document.prototype.$__reset = function reset() {
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
const onlyPrimitiveValues = this.$__hasOnlyPrimitiveValues();
|
|
3706
|
+
Document.prototype.$__reset = function reset(skipBackup, hasOnlyPrimitiveValues) {
|
|
3707
|
+
hasOnlyPrimitiveValues = hasOnlyPrimitiveValues ?? this.$__hasOnlyPrimitiveValues();
|
|
3641
3708
|
|
|
3642
3709
|
// Skip for subdocuments. Also skip if doc only has primitive values,
|
|
3643
3710
|
// because primitives can't be subdocs.
|
|
3644
|
-
const subdocs = !this.$isSubdocument && !
|
|
3711
|
+
const subdocs = !this.$isSubdocument && !hasOnlyPrimitiveValues ? this.$getAllSubdocs({ useCache: true }) : null;
|
|
3645
3712
|
if (subdocs?.length > 0) {
|
|
3646
3713
|
for (const subdoc of subdocs) {
|
|
3647
|
-
subdoc.$__reset();
|
|
3714
|
+
subdoc.$__reset(skipBackup);
|
|
3648
3715
|
}
|
|
3649
3716
|
}
|
|
3650
3717
|
|
|
@@ -3653,27 +3720,32 @@ Document.prototype.$__reset = function reset() {
|
|
|
3653
3720
|
// arrays, a Map, and does parent-path deduplication we don't need here.
|
|
3654
3721
|
// Skip entirely if the doc only has primitive values, because only arrays
|
|
3655
3722
|
// and maps have atomics.
|
|
3656
|
-
if (!
|
|
3723
|
+
if (!hasOnlyPrimitiveValues) {
|
|
3657
3724
|
this.$__resetAtomics();
|
|
3658
3725
|
}
|
|
3659
3726
|
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3727
|
+
if (!skipBackup) {
|
|
3728
|
+
this.$__.backup = {};
|
|
3729
|
+
this.$__.backup.activePaths = {
|
|
3730
|
+
modify: Object.assign({}, this.$__.activePaths.getStatePaths('modify')),
|
|
3731
|
+
default: Object.assign({}, this.$__.activePaths.getStatePaths('default'))
|
|
3732
|
+
};
|
|
3733
|
+
this.$__.backup.validationError = this.$__.validationError;
|
|
3734
|
+
this.$__.backup.errors = this.$errors;
|
|
3735
|
+
}
|
|
3667
3736
|
|
|
3668
3737
|
// Clear 'dirty' cache
|
|
3669
|
-
this.$__.activePaths.
|
|
3670
|
-
this.$__.
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3738
|
+
this.$__.activePaths.clearAllExcept('init');
|
|
3739
|
+
if (this.$__.validationError) {
|
|
3740
|
+
this.$__.validationError = undefined;
|
|
3741
|
+
}
|
|
3742
|
+
if (this.$errors) {
|
|
3743
|
+
this.$errors = undefined;
|
|
3744
|
+
}
|
|
3745
|
+
|
|
3746
|
+
for (const path of this.$__schema.requiredPaths()) {
|
|
3747
|
+
this.$__.activePaths.require(path);
|
|
3748
|
+
}
|
|
3677
3749
|
|
|
3678
3750
|
return this;
|
|
3679
3751
|
};
|
|
@@ -4003,9 +4075,6 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
4003
4075
|
if (depopulate && options._isNested && this.$__.wasPopulated) {
|
|
4004
4076
|
return clone(this.$__.wasPopulated.value || this._doc._id, options);
|
|
4005
4077
|
}
|
|
4006
|
-
if (depopulate) {
|
|
4007
|
-
options.depopulate = true;
|
|
4008
|
-
}
|
|
4009
4078
|
|
|
4010
4079
|
// merge default options with input options.
|
|
4011
4080
|
if (defaultOptions != null) {
|
|
@@ -4017,7 +4086,6 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
4017
4086
|
}
|
|
4018
4087
|
options._isNested = true;
|
|
4019
4088
|
options.json = json;
|
|
4020
|
-
options.minimize = _minimize;
|
|
4021
4089
|
|
|
4022
4090
|
const parentOptions = options._parentOptions;
|
|
4023
4091
|
// Parent options should only bubble down for subdocuments, not populated docs
|
|
@@ -4025,7 +4093,7 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
4025
4093
|
|
|
4026
4094
|
const schemaFieldsOnly = options._calledWithOptions.schemaFieldsOnly
|
|
4027
4095
|
?? options.schemaFieldsOnly
|
|
4028
|
-
?? defaultOptions
|
|
4096
|
+
?? defaultOptions?.schemaFieldsOnly
|
|
4029
4097
|
?? false;
|
|
4030
4098
|
|
|
4031
4099
|
let ret;
|
|
@@ -4062,7 +4130,7 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
4062
4130
|
|
|
4063
4131
|
const getters = options._calledWithOptions.getters
|
|
4064
4132
|
?? options.getters
|
|
4065
|
-
?? defaultOptions
|
|
4133
|
+
?? defaultOptions?.getters
|
|
4066
4134
|
?? false;
|
|
4067
4135
|
|
|
4068
4136
|
if (getters) {
|
|
@@ -4074,7 +4142,7 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
4074
4142
|
}
|
|
4075
4143
|
|
|
4076
4144
|
const virtuals = options._calledWithOptions.virtuals
|
|
4077
|
-
?? defaultOptions
|
|
4145
|
+
?? defaultOptions?.virtuals
|
|
4078
4146
|
?? parentOptions?.virtuals
|
|
4079
4147
|
?? undefined;
|
|
4080
4148
|
|
|
@@ -4089,7 +4157,7 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
4089
4157
|
const transform = options._calledWithOptions.transform ?? true;
|
|
4090
4158
|
let transformFunction = undefined;
|
|
4091
4159
|
if (transform === true) {
|
|
4092
|
-
transformFunction = defaultOptions
|
|
4160
|
+
transformFunction = defaultOptions?.transform;
|
|
4093
4161
|
} else if (typeof transform === 'function') {
|
|
4094
4162
|
transformFunction = transform;
|
|
4095
4163
|
}
|
|
@@ -4402,6 +4470,32 @@ function applyGetters(self, json) {
|
|
|
4402
4470
|
while (i--) {
|
|
4403
4471
|
path = paths[i];
|
|
4404
4472
|
|
|
4473
|
+
const schemaType = schema.paths[path];
|
|
4474
|
+
// Skip if no getters, including `$__isSelected()` because that can be expensive
|
|
4475
|
+
if (!schemaType.getters?.length && !schemaType.embeddedSchemaType?.getters?.length) {
|
|
4476
|
+
continue;
|
|
4477
|
+
}
|
|
4478
|
+
|
|
4479
|
+
if (!self.$__isSelected(path)) {
|
|
4480
|
+
continue;
|
|
4481
|
+
}
|
|
4482
|
+
|
|
4483
|
+
if (path.indexOf('.') === -1) {
|
|
4484
|
+
json[path] = schemaType.applyGetters(
|
|
4485
|
+
json[path],
|
|
4486
|
+
self
|
|
4487
|
+
);
|
|
4488
|
+
if (Array.isArray(json[path]) && schemaType.embeddedSchemaType) {
|
|
4489
|
+
for (let i = 0; i < json[path].length; ++i) {
|
|
4490
|
+
json[path][i] = schemaType.embeddedSchemaType.applyGetters(
|
|
4491
|
+
json[path][i],
|
|
4492
|
+
self
|
|
4493
|
+
);
|
|
4494
|
+
}
|
|
4495
|
+
}
|
|
4496
|
+
continue;
|
|
4497
|
+
}
|
|
4498
|
+
|
|
4405
4499
|
const parts = path.split('.');
|
|
4406
4500
|
|
|
4407
4501
|
const plen = parts.length;
|
|
@@ -4410,10 +4504,6 @@ function applyGetters(self, json) {
|
|
|
4410
4504
|
let part;
|
|
4411
4505
|
cur = self._doc;
|
|
4412
4506
|
|
|
4413
|
-
if (!self.$__isSelected(path)) {
|
|
4414
|
-
continue;
|
|
4415
|
-
}
|
|
4416
|
-
|
|
4417
4507
|
for (let ii = 0; ii < plen; ++ii) {
|
|
4418
4508
|
part = parts[ii];
|
|
4419
4509
|
v = cur[part];
|
|
@@ -4423,13 +4513,13 @@ function applyGetters(self, json) {
|
|
|
4423
4513
|
if (branch != null && typeof branch !== 'object') {
|
|
4424
4514
|
break;
|
|
4425
4515
|
} else if (ii === last) {
|
|
4426
|
-
branch[part] =
|
|
4516
|
+
branch[part] = schemaType.applyGetters(
|
|
4427
4517
|
branch[part],
|
|
4428
4518
|
self
|
|
4429
4519
|
);
|
|
4430
|
-
if (Array.isArray(branch[part]) &&
|
|
4520
|
+
if (Array.isArray(branch[part]) && schemaType.embeddedSchemaType) {
|
|
4431
4521
|
for (let i = 0; i < branch[part].length; ++i) {
|
|
4432
|
-
branch[part][i] =
|
|
4522
|
+
branch[part][i] = schemaType.embeddedSchemaType.applyGetters(
|
|
4433
4523
|
branch[part][i],
|
|
4434
4524
|
self
|
|
4435
4525
|
);
|
|
@@ -4461,10 +4551,10 @@ function applyGetters(self, json) {
|
|
|
4461
4551
|
|
|
4462
4552
|
function applySchemaTypeTransforms(self, json) {
|
|
4463
4553
|
const schema = self.$__schema;
|
|
4464
|
-
const paths =
|
|
4554
|
+
const paths = schema.pathsWithTransforms();
|
|
4465
4555
|
const cur = self._doc;
|
|
4466
4556
|
|
|
4467
|
-
if (!cur) {
|
|
4557
|
+
if (!cur || !paths) {
|
|
4468
4558
|
return json;
|
|
4469
4559
|
}
|
|
4470
4560
|
|
|
@@ -5659,13 +5749,22 @@ Document.prototype.$clearModifiedPaths = function $clearModifiedPaths() {
|
|
|
5659
5749
|
*/
|
|
5660
5750
|
|
|
5661
5751
|
Document.prototype.$__hasOnlyPrimitiveValues = function $__hasOnlyPrimitiveValues() {
|
|
5662
|
-
|
|
5663
|
-
return
|
|
5752
|
+
if (this.$__.populated) {
|
|
5753
|
+
return false;
|
|
5754
|
+
}
|
|
5755
|
+
const doc = this._doc;
|
|
5756
|
+
for (const key in doc) {
|
|
5757
|
+
const v = doc[key];
|
|
5758
|
+
if (v == null
|
|
5664
5759
|
|| typeof v !== 'object'
|
|
5665
5760
|
|| (utils.isNativeObject(v) && !Array.isArray(v))
|
|
5666
5761
|
|| isBsonType(v, 'ObjectId')
|
|
5667
|
-
|| isBsonType(v, 'Decimal128')
|
|
5668
|
-
|
|
5762
|
+
|| isBsonType(v, 'Decimal128')) {
|
|
5763
|
+
continue;
|
|
5764
|
+
}
|
|
5765
|
+
return false;
|
|
5766
|
+
}
|
|
5767
|
+
return true;
|
|
5669
5768
|
};
|
|
5670
5769
|
|
|
5671
5770
|
/*!
|