@depup/mongoose 9.8.1-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 +223 -128
- 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/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/package.json +3 -3
- package/types/inferhydrateddoctype.d.ts +19 -3
- package/types/inferrawdoctype.d.ts +19 -3
- 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();
|
|
@@ -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,69 +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;
|
|
2976
2996
|
|
|
2977
|
-
_evaluateRequiredFunctions(doc);
|
|
2978
2997
|
// gh-16379: compute the modified-path set at most once and reuse it below, so
|
|
2979
2998
|
// checking many required paths doesn't rebuild it per-path (O(required x modified)).
|
|
2980
2999
|
let _modifiedPaths;
|
|
2981
3000
|
const getModifiedPaths = () => (_modifiedPaths ??= doc.modifiedPaths());
|
|
3001
|
+
|
|
2982
3002
|
// only validate required fields when necessary
|
|
2983
|
-
let paths =
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
//
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
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
|
+
}
|
|
2993
3041
|
}
|
|
2994
|
-
|
|
2995
|
-
}));
|
|
3042
|
+
}
|
|
2996
3043
|
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
if (p.endsWith('.$*')) {
|
|
3002
|
-
// Skip $* paths - they represent map schemas, not actual document paths
|
|
3003
|
-
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;
|
|
3004
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
|
+
}
|
|
3005
3054
|
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
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
|
+
}
|
|
3028
3078
|
}
|
|
3029
|
-
}
|
|
3030
3079
|
|
|
3031
|
-
|
|
3080
|
+
paths.push(p);
|
|
3081
|
+
}
|
|
3032
3082
|
}
|
|
3033
3083
|
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
return [[], doValidateOptions];
|
|
3084
|
+
if (paths.length === 0 && doc.$__hasOnlyPrimitiveValues()) {
|
|
3085
|
+
return [paths, doValidateOptions];
|
|
3037
3086
|
}
|
|
3038
3087
|
|
|
3088
|
+
paths = new Set(paths);
|
|
3089
|
+
|
|
3039
3090
|
if (!isNestedValidate) {
|
|
3040
3091
|
// If we're validating a subdocument, all this logic will run anyway on the top-level document, so skip for subdocuments.
|
|
3041
3092
|
// But only run for top-level subdocuments, because we're looking for subdocuments that are not modified at top-level but
|
|
@@ -3061,6 +3112,18 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate
|
|
|
3061
3112
|
}
|
|
3062
3113
|
}
|
|
3063
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
|
+
|
|
3064
3127
|
for (const subdoc of topLevelSubdocs) {
|
|
3065
3128
|
if (subdoc.$basePath) {
|
|
3066
3129
|
const fullPathToSubdoc = subdoc.$__pathRelativeToParent();
|
|
@@ -3100,7 +3163,7 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate
|
|
|
3100
3163
|
}
|
|
3101
3164
|
}
|
|
3102
3165
|
|
|
3103
|
-
if (!
|
|
3166
|
+
if (!doc.$__hasOnlyPrimitiveValues()) {
|
|
3104
3167
|
for (const path of paths) {
|
|
3105
3168
|
const _pathType = doc.$__schema.path(path);
|
|
3106
3169
|
if (_pathType && _pathType.$isMongooseDocumentArray) {
|
|
@@ -3139,8 +3202,8 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate
|
|
|
3139
3202
|
// Re: gh-8468
|
|
3140
3203
|
const singleNestedPaths = doc.$__schema.singleNestedPaths;
|
|
3141
3204
|
for (const path of Object.keys(flat)) {
|
|
3142
|
-
if (!Object.hasOwn(singleNestedPaths, path)) {
|
|
3143
|
-
|
|
3205
|
+
if (!Object.hasOwn(singleNestedPaths, path) && !path.endsWith('.$*')) {
|
|
3206
|
+
paths.add(path);
|
|
3144
3207
|
}
|
|
3145
3208
|
}
|
|
3146
3209
|
}
|
|
@@ -3632,23 +3695,23 @@ Document.prototype.$isValid = function(path) {
|
|
|
3632
3695
|
* Resets the internal modified state of this document.
|
|
3633
3696
|
*
|
|
3634
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
|
|
3635
3700
|
* @return {Document} this
|
|
3636
3701
|
* @method $__reset
|
|
3637
3702
|
* @memberOf Document
|
|
3638
3703
|
* @instance
|
|
3639
3704
|
*/
|
|
3640
3705
|
|
|
3641
|
-
Document.prototype.$__reset = function reset() {
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
const onlyPrimitiveValues = this.$__hasOnlyPrimitiveValues();
|
|
3706
|
+
Document.prototype.$__reset = function reset(skipBackup, hasOnlyPrimitiveValues) {
|
|
3707
|
+
hasOnlyPrimitiveValues = hasOnlyPrimitiveValues ?? this.$__hasOnlyPrimitiveValues();
|
|
3645
3708
|
|
|
3646
3709
|
// Skip for subdocuments. Also skip if doc only has primitive values,
|
|
3647
3710
|
// because primitives can't be subdocs.
|
|
3648
|
-
const subdocs = !this.$isSubdocument && !
|
|
3711
|
+
const subdocs = !this.$isSubdocument && !hasOnlyPrimitiveValues ? this.$getAllSubdocs({ useCache: true }) : null;
|
|
3649
3712
|
if (subdocs?.length > 0) {
|
|
3650
3713
|
for (const subdoc of subdocs) {
|
|
3651
|
-
subdoc.$__reset();
|
|
3714
|
+
subdoc.$__reset(skipBackup);
|
|
3652
3715
|
}
|
|
3653
3716
|
}
|
|
3654
3717
|
|
|
@@ -3657,27 +3720,32 @@ Document.prototype.$__reset = function reset() {
|
|
|
3657
3720
|
// arrays, a Map, and does parent-path deduplication we don't need here.
|
|
3658
3721
|
// Skip entirely if the doc only has primitive values, because only arrays
|
|
3659
3722
|
// and maps have atomics.
|
|
3660
|
-
if (!
|
|
3723
|
+
if (!hasOnlyPrimitiveValues) {
|
|
3661
3724
|
this.$__resetAtomics();
|
|
3662
3725
|
}
|
|
3663
3726
|
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
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
|
+
}
|
|
3671
3736
|
|
|
3672
3737
|
// Clear 'dirty' cache
|
|
3673
|
-
this.$__.activePaths.
|
|
3674
|
-
this.$__.
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
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
|
+
}
|
|
3681
3749
|
|
|
3682
3750
|
return this;
|
|
3683
3751
|
};
|
|
@@ -4007,9 +4075,6 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
4007
4075
|
if (depopulate && options._isNested && this.$__.wasPopulated) {
|
|
4008
4076
|
return clone(this.$__.wasPopulated.value || this._doc._id, options);
|
|
4009
4077
|
}
|
|
4010
|
-
if (depopulate) {
|
|
4011
|
-
options.depopulate = true;
|
|
4012
|
-
}
|
|
4013
4078
|
|
|
4014
4079
|
// merge default options with input options.
|
|
4015
4080
|
if (defaultOptions != null) {
|
|
@@ -4021,7 +4086,6 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
4021
4086
|
}
|
|
4022
4087
|
options._isNested = true;
|
|
4023
4088
|
options.json = json;
|
|
4024
|
-
options.minimize = _minimize;
|
|
4025
4089
|
|
|
4026
4090
|
const parentOptions = options._parentOptions;
|
|
4027
4091
|
// Parent options should only bubble down for subdocuments, not populated docs
|
|
@@ -4029,7 +4093,7 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
4029
4093
|
|
|
4030
4094
|
const schemaFieldsOnly = options._calledWithOptions.schemaFieldsOnly
|
|
4031
4095
|
?? options.schemaFieldsOnly
|
|
4032
|
-
?? defaultOptions
|
|
4096
|
+
?? defaultOptions?.schemaFieldsOnly
|
|
4033
4097
|
?? false;
|
|
4034
4098
|
|
|
4035
4099
|
let ret;
|
|
@@ -4066,7 +4130,7 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
4066
4130
|
|
|
4067
4131
|
const getters = options._calledWithOptions.getters
|
|
4068
4132
|
?? options.getters
|
|
4069
|
-
?? defaultOptions
|
|
4133
|
+
?? defaultOptions?.getters
|
|
4070
4134
|
?? false;
|
|
4071
4135
|
|
|
4072
4136
|
if (getters) {
|
|
@@ -4078,7 +4142,7 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
4078
4142
|
}
|
|
4079
4143
|
|
|
4080
4144
|
const virtuals = options._calledWithOptions.virtuals
|
|
4081
|
-
?? defaultOptions
|
|
4145
|
+
?? defaultOptions?.virtuals
|
|
4082
4146
|
?? parentOptions?.virtuals
|
|
4083
4147
|
?? undefined;
|
|
4084
4148
|
|
|
@@ -4093,7 +4157,7 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
4093
4157
|
const transform = options._calledWithOptions.transform ?? true;
|
|
4094
4158
|
let transformFunction = undefined;
|
|
4095
4159
|
if (transform === true) {
|
|
4096
|
-
transformFunction = defaultOptions
|
|
4160
|
+
transformFunction = defaultOptions?.transform;
|
|
4097
4161
|
} else if (typeof transform === 'function') {
|
|
4098
4162
|
transformFunction = transform;
|
|
4099
4163
|
}
|
|
@@ -4406,6 +4470,32 @@ function applyGetters(self, json) {
|
|
|
4406
4470
|
while (i--) {
|
|
4407
4471
|
path = paths[i];
|
|
4408
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
|
+
|
|
4409
4499
|
const parts = path.split('.');
|
|
4410
4500
|
|
|
4411
4501
|
const plen = parts.length;
|
|
@@ -4414,10 +4504,6 @@ function applyGetters(self, json) {
|
|
|
4414
4504
|
let part;
|
|
4415
4505
|
cur = self._doc;
|
|
4416
4506
|
|
|
4417
|
-
if (!self.$__isSelected(path)) {
|
|
4418
|
-
continue;
|
|
4419
|
-
}
|
|
4420
|
-
|
|
4421
4507
|
for (let ii = 0; ii < plen; ++ii) {
|
|
4422
4508
|
part = parts[ii];
|
|
4423
4509
|
v = cur[part];
|
|
@@ -4427,13 +4513,13 @@ function applyGetters(self, json) {
|
|
|
4427
4513
|
if (branch != null && typeof branch !== 'object') {
|
|
4428
4514
|
break;
|
|
4429
4515
|
} else if (ii === last) {
|
|
4430
|
-
branch[part] =
|
|
4516
|
+
branch[part] = schemaType.applyGetters(
|
|
4431
4517
|
branch[part],
|
|
4432
4518
|
self
|
|
4433
4519
|
);
|
|
4434
|
-
if (Array.isArray(branch[part]) &&
|
|
4520
|
+
if (Array.isArray(branch[part]) && schemaType.embeddedSchemaType) {
|
|
4435
4521
|
for (let i = 0; i < branch[part].length; ++i) {
|
|
4436
|
-
branch[part][i] =
|
|
4522
|
+
branch[part][i] = schemaType.embeddedSchemaType.applyGetters(
|
|
4437
4523
|
branch[part][i],
|
|
4438
4524
|
self
|
|
4439
4525
|
);
|
|
@@ -4465,10 +4551,10 @@ function applyGetters(self, json) {
|
|
|
4465
4551
|
|
|
4466
4552
|
function applySchemaTypeTransforms(self, json) {
|
|
4467
4553
|
const schema = self.$__schema;
|
|
4468
|
-
const paths =
|
|
4554
|
+
const paths = schema.pathsWithTransforms();
|
|
4469
4555
|
const cur = self._doc;
|
|
4470
4556
|
|
|
4471
|
-
if (!cur) {
|
|
4557
|
+
if (!cur || !paths) {
|
|
4472
4558
|
return json;
|
|
4473
4559
|
}
|
|
4474
4560
|
|
|
@@ -5663,13 +5749,22 @@ Document.prototype.$clearModifiedPaths = function $clearModifiedPaths() {
|
|
|
5663
5749
|
*/
|
|
5664
5750
|
|
|
5665
5751
|
Document.prototype.$__hasOnlyPrimitiveValues = function $__hasOnlyPrimitiveValues() {
|
|
5666
|
-
|
|
5667
|
-
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
|
|
5668
5759
|
|| typeof v !== 'object'
|
|
5669
5760
|
|| (utils.isNativeObject(v) && !Array.isArray(v))
|
|
5670
5761
|
|| isBsonType(v, 'ObjectId')
|
|
5671
|
-
|| isBsonType(v, 'Decimal128')
|
|
5672
|
-
|
|
5762
|
+
|| isBsonType(v, 'Decimal128')) {
|
|
5763
|
+
continue;
|
|
5764
|
+
}
|
|
5765
|
+
return false;
|
|
5766
|
+
}
|
|
5767
|
+
return true;
|
|
5673
5768
|
};
|
|
5674
5769
|
|
|
5675
5770
|
/*!
|