mongoose 8.2.4 → 8.3.1
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/dist/browser.umd.js +1 -1
- package/lib/document.js +141 -56
- package/lib/helpers/discriminator/applyEmbeddedDiscriminators.js +7 -3
- package/lib/helpers/model/discriminator.js +2 -2
- package/lib/model.js +53 -3
- package/lib/mongoose.js +10 -0
- package/lib/query.js +11 -3
- package/lib/schema/documentArray.js +2 -2
- package/lib/schema/subdocument.js +1 -1
- package/lib/schema.js +10 -5
- package/lib/schemaType.js +19 -2
- package/package.json +11 -11
- package/types/index.d.ts +5 -31
- package/types/middlewares.d.ts +5 -4
- package/types/query.d.ts +4 -1
- package/types/schematypes.d.ts +11 -3
- package/types/validation.d.ts +1 -0
package/lib/document.js
CHANGED
|
@@ -2756,47 +2756,7 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip) {
|
|
|
2756
2756
|
|
|
2757
2757
|
// gh-661: if a whole array is modified, make sure to run validation on all
|
|
2758
2758
|
// the children as well
|
|
2759
|
-
|
|
2760
|
-
const _pathType = doc.$__schema.path(path);
|
|
2761
|
-
if (!_pathType) {
|
|
2762
|
-
continue;
|
|
2763
|
-
}
|
|
2764
|
-
|
|
2765
|
-
if (!_pathType.$isMongooseArray ||
|
|
2766
|
-
// To avoid potential performance issues, skip doc arrays whose children
|
|
2767
|
-
// are not required. `getPositionalPathType()` may be slow, so avoid
|
|
2768
|
-
// it unless we have a case of #6364
|
|
2769
|
-
(!Array.isArray(_pathType) &&
|
|
2770
|
-
_pathType.$isMongooseDocumentArray &&
|
|
2771
|
-
!(_pathType && _pathType.schemaOptions && _pathType.schemaOptions.required))) {
|
|
2772
|
-
continue;
|
|
2773
|
-
}
|
|
2774
|
-
|
|
2775
|
-
// gh-11380: optimization. If the array isn't a document array and there's no validators
|
|
2776
|
-
// on the array type, there's no need to run validation on the individual array elements.
|
|
2777
|
-
if (_pathType.$isMongooseArray &&
|
|
2778
|
-
!_pathType.$isMongooseDocumentArray && // Skip document arrays...
|
|
2779
|
-
!_pathType.$embeddedSchemaType.$isMongooseArray && // and arrays of arrays
|
|
2780
|
-
_pathType.$embeddedSchemaType.validators.length === 0) {
|
|
2781
|
-
continue;
|
|
2782
|
-
}
|
|
2783
|
-
|
|
2784
|
-
const val = doc.$__getValue(path);
|
|
2785
|
-
_pushNestedArrayPaths(val, paths, path);
|
|
2786
|
-
}
|
|
2787
|
-
|
|
2788
|
-
function _pushNestedArrayPaths(val, paths, path) {
|
|
2789
|
-
if (val != null) {
|
|
2790
|
-
const numElements = val.length;
|
|
2791
|
-
for (let j = 0; j < numElements; ++j) {
|
|
2792
|
-
if (Array.isArray(val[j])) {
|
|
2793
|
-
_pushNestedArrayPaths(val[j], paths, path + '.' + j);
|
|
2794
|
-
} else {
|
|
2795
|
-
paths.add(path + '.' + j);
|
|
2796
|
-
}
|
|
2797
|
-
}
|
|
2798
|
-
}
|
|
2799
|
-
}
|
|
2759
|
+
_addArrayPathsToValidate(doc, paths);
|
|
2800
2760
|
|
|
2801
2761
|
const flattenOptions = { skipArrays: true };
|
|
2802
2762
|
for (const pathToCheck of paths) {
|
|
@@ -2841,12 +2801,58 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip) {
|
|
|
2841
2801
|
return [paths, doValidateOptions];
|
|
2842
2802
|
}
|
|
2843
2803
|
|
|
2804
|
+
function _addArrayPathsToValidate(doc, paths) {
|
|
2805
|
+
for (const path of paths) {
|
|
2806
|
+
const _pathType = doc.$__schema.path(path);
|
|
2807
|
+
if (!_pathType) {
|
|
2808
|
+
continue;
|
|
2809
|
+
}
|
|
2810
|
+
|
|
2811
|
+
if (!_pathType.$isMongooseArray ||
|
|
2812
|
+
// To avoid potential performance issues, skip doc arrays whose children
|
|
2813
|
+
// are not required. `getPositionalPathType()` may be slow, so avoid
|
|
2814
|
+
// it unless we have a case of #6364
|
|
2815
|
+
(!Array.isArray(_pathType) &&
|
|
2816
|
+
_pathType.$isMongooseDocumentArray &&
|
|
2817
|
+
!(_pathType && _pathType.schemaOptions && _pathType.schemaOptions.required))) {
|
|
2818
|
+
continue;
|
|
2819
|
+
}
|
|
2820
|
+
|
|
2821
|
+
// gh-11380: optimization. If the array isn't a document array and there's no validators
|
|
2822
|
+
// on the array type, there's no need to run validation on the individual array elements.
|
|
2823
|
+
if (_pathType.$isMongooseArray &&
|
|
2824
|
+
!_pathType.$isMongooseDocumentArray && // Skip document arrays...
|
|
2825
|
+
!_pathType.$embeddedSchemaType.$isMongooseArray && // and arrays of arrays
|
|
2826
|
+
_pathType.$embeddedSchemaType.validators.length === 0) {
|
|
2827
|
+
continue;
|
|
2828
|
+
}
|
|
2829
|
+
|
|
2830
|
+
const val = doc.$__getValue(path);
|
|
2831
|
+
_pushNestedArrayPaths(val, paths, path);
|
|
2832
|
+
}
|
|
2833
|
+
}
|
|
2834
|
+
|
|
2835
|
+
function _pushNestedArrayPaths(val, paths, path) {
|
|
2836
|
+
if (val != null) {
|
|
2837
|
+
const numElements = val.length;
|
|
2838
|
+
for (let j = 0; j < numElements; ++j) {
|
|
2839
|
+
if (Array.isArray(val[j])) {
|
|
2840
|
+
_pushNestedArrayPaths(val[j], paths, path + '.' + j);
|
|
2841
|
+
} else {
|
|
2842
|
+
paths.add(path + '.' + j);
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
|
|
2844
2848
|
/*!
|
|
2845
2849
|
* ignore
|
|
2846
2850
|
*/
|
|
2847
2851
|
|
|
2848
2852
|
Document.prototype.$__validate = function(pathsToValidate, options, callback) {
|
|
2849
|
-
if (
|
|
2853
|
+
if (this.$__.saveOptions && this.$__.saveOptions.pathsToSave && !pathsToValidate) {
|
|
2854
|
+
pathsToValidate = [...this.$__.saveOptions.pathsToSave];
|
|
2855
|
+
} else if (typeof pathsToValidate === 'function') {
|
|
2850
2856
|
callback = pathsToValidate;
|
|
2851
2857
|
options = null;
|
|
2852
2858
|
pathsToValidate = null;
|
|
@@ -2868,6 +2874,19 @@ Document.prototype.$__validate = function(pathsToValidate, options, callback) {
|
|
|
2868
2874
|
shouldValidateModifiedOnly = this.$__schema.options.validateModifiedOnly;
|
|
2869
2875
|
}
|
|
2870
2876
|
|
|
2877
|
+
const validateAllPaths = options && options.validateAllPaths;
|
|
2878
|
+
if (validateAllPaths) {
|
|
2879
|
+
if (pathsToSkip) {
|
|
2880
|
+
throw new TypeError('Cannot set both `validateAllPaths` and `pathsToSkip`');
|
|
2881
|
+
}
|
|
2882
|
+
if (pathsToValidate) {
|
|
2883
|
+
throw new TypeError('Cannot set both `validateAllPaths` and `pathsToValidate`');
|
|
2884
|
+
}
|
|
2885
|
+
if (hasValidateModifiedOnlyOption && shouldValidateModifiedOnly) {
|
|
2886
|
+
throw new TypeError('Cannot set both `validateAllPaths` and `validateModifiedOnly`');
|
|
2887
|
+
}
|
|
2888
|
+
}
|
|
2889
|
+
|
|
2871
2890
|
const _this = this;
|
|
2872
2891
|
const _complete = () => {
|
|
2873
2892
|
let validationError = this.$__.validationError;
|
|
@@ -2905,11 +2924,33 @@ Document.prototype.$__validate = function(pathsToValidate, options, callback) {
|
|
|
2905
2924
|
};
|
|
2906
2925
|
|
|
2907
2926
|
// only validate required fields when necessary
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2927
|
+
let paths;
|
|
2928
|
+
let doValidateOptionsByPath;
|
|
2929
|
+
if (validateAllPaths) {
|
|
2930
|
+
paths = new Set(Object.keys(this.$__schema.paths));
|
|
2931
|
+
// gh-661: if a whole array is modified, make sure to run validation on all
|
|
2932
|
+
// the children as well
|
|
2933
|
+
for (const path of paths) {
|
|
2934
|
+
const schemaType = this.$__schema.path(path);
|
|
2935
|
+
if (!schemaType || !schemaType.$isMongooseArray) {
|
|
2936
|
+
continue;
|
|
2937
|
+
}
|
|
2938
|
+
const val = this.$__getValue(path);
|
|
2939
|
+
if (!val) {
|
|
2940
|
+
continue;
|
|
2941
|
+
}
|
|
2942
|
+
_pushNestedArrayPaths(val, paths, path);
|
|
2943
|
+
}
|
|
2944
|
+
paths = [...paths];
|
|
2945
|
+
doValidateOptionsByPath = {};
|
|
2946
|
+
} else {
|
|
2947
|
+
const pathDetails = _getPathsToValidate(this, pathsToValidate, pathsToSkip);
|
|
2948
|
+
paths = shouldValidateModifiedOnly ?
|
|
2949
|
+
pathDetails[0].filter((path) => this.$isModified(path)) :
|
|
2950
|
+
pathDetails[0];
|
|
2951
|
+
doValidateOptionsByPath = pathDetails[1];
|
|
2952
|
+
}
|
|
2953
|
+
|
|
2913
2954
|
if (typeof pathsToValidate === 'string') {
|
|
2914
2955
|
pathsToValidate = pathsToValidate.split(' ');
|
|
2915
2956
|
}
|
|
@@ -2929,8 +2970,19 @@ Document.prototype.$__validate = function(pathsToValidate, options, callback) {
|
|
|
2929
2970
|
const validated = {};
|
|
2930
2971
|
let total = 0;
|
|
2931
2972
|
|
|
2932
|
-
|
|
2933
|
-
|
|
2973
|
+
let pathsToSave = this.$__.saveOptions?.pathsToSave;
|
|
2974
|
+
if (Array.isArray(pathsToSave)) {
|
|
2975
|
+
pathsToSave = new Set(pathsToSave);
|
|
2976
|
+
for (const path of paths) {
|
|
2977
|
+
if (!pathsToSave.has(path)) {
|
|
2978
|
+
continue;
|
|
2979
|
+
}
|
|
2980
|
+
validatePath(path);
|
|
2981
|
+
}
|
|
2982
|
+
} else {
|
|
2983
|
+
for (const path of paths) {
|
|
2984
|
+
validatePath(path);
|
|
2985
|
+
}
|
|
2934
2986
|
}
|
|
2935
2987
|
|
|
2936
2988
|
function validatePath(path) {
|
|
@@ -2979,7 +3031,8 @@ Document.prototype.$__validate = function(pathsToValidate, options, callback) {
|
|
|
2979
3031
|
const doValidateOptions = {
|
|
2980
3032
|
...doValidateOptionsByPath[path],
|
|
2981
3033
|
path: path,
|
|
2982
|
-
validateModifiedOnly: shouldValidateModifiedOnly
|
|
3034
|
+
validateModifiedOnly: shouldValidateModifiedOnly,
|
|
3035
|
+
validateAllPaths
|
|
2983
3036
|
};
|
|
2984
3037
|
|
|
2985
3038
|
schemaType.doValidate(val, function(err) {
|
|
@@ -3097,6 +3150,16 @@ Document.prototype.validateSync = function(pathsToValidate, options) {
|
|
|
3097
3150
|
|
|
3098
3151
|
let pathsToSkip = options && options.pathsToSkip;
|
|
3099
3152
|
|
|
3153
|
+
const validateAllPaths = options && options.validateAllPaths;
|
|
3154
|
+
if (validateAllPaths) {
|
|
3155
|
+
if (pathsToSkip) {
|
|
3156
|
+
throw new TypeError('Cannot set both `validateAllPaths` and `pathsToSkip`');
|
|
3157
|
+
}
|
|
3158
|
+
if (pathsToValidate) {
|
|
3159
|
+
throw new TypeError('Cannot set both `validateAllPaths` and `pathsToValidate`');
|
|
3160
|
+
}
|
|
3161
|
+
}
|
|
3162
|
+
|
|
3100
3163
|
if (typeof pathsToValidate === 'string') {
|
|
3101
3164
|
const isOnePathOnly = pathsToValidate.indexOf(' ') === -1;
|
|
3102
3165
|
pathsToValidate = isOnePathOnly ? [pathsToValidate] : pathsToValidate.split(' ');
|
|
@@ -3105,11 +3168,32 @@ Document.prototype.validateSync = function(pathsToValidate, options) {
|
|
|
3105
3168
|
}
|
|
3106
3169
|
|
|
3107
3170
|
// only validate required fields when necessary
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3171
|
+
let paths;
|
|
3172
|
+
let skipSchemaValidators;
|
|
3173
|
+
if (validateAllPaths) {
|
|
3174
|
+
paths = new Set(Object.keys(this.$__schema.paths));
|
|
3175
|
+
// gh-661: if a whole array is modified, make sure to run validation on all
|
|
3176
|
+
// the children as well
|
|
3177
|
+
for (const path of paths) {
|
|
3178
|
+
const schemaType = this.$__schema.path(path);
|
|
3179
|
+
if (!schemaType || !schemaType.$isMongooseArray) {
|
|
3180
|
+
continue;
|
|
3181
|
+
}
|
|
3182
|
+
const val = this.$__getValue(path);
|
|
3183
|
+
if (!val) {
|
|
3184
|
+
continue;
|
|
3185
|
+
}
|
|
3186
|
+
_pushNestedArrayPaths(val, paths, path);
|
|
3187
|
+
}
|
|
3188
|
+
paths = [...paths];
|
|
3189
|
+
skipSchemaValidators = {};
|
|
3190
|
+
} else {
|
|
3191
|
+
const pathDetails = _getPathsToValidate(this, pathsToValidate, pathsToSkip);
|
|
3192
|
+
paths = shouldValidateModifiedOnly ?
|
|
3193
|
+
pathDetails[0].filter((path) => this.$isModified(path)) :
|
|
3194
|
+
pathDetails[0];
|
|
3195
|
+
skipSchemaValidators = pathDetails[1];
|
|
3196
|
+
}
|
|
3113
3197
|
|
|
3114
3198
|
const validating = {};
|
|
3115
3199
|
|
|
@@ -3134,7 +3218,8 @@ Document.prototype.validateSync = function(pathsToValidate, options) {
|
|
|
3134
3218
|
const err = p.doValidateSync(val, _this, {
|
|
3135
3219
|
skipSchemaValidators: skipSchemaValidators[path],
|
|
3136
3220
|
path: path,
|
|
3137
|
-
validateModifiedOnly: shouldValidateModifiedOnly
|
|
3221
|
+
validateModifiedOnly: shouldValidateModifiedOnly,
|
|
3222
|
+
validateAllPaths
|
|
3138
3223
|
});
|
|
3139
3224
|
if (err) {
|
|
3140
3225
|
const isSubdoc = p.$isSingleNested ||
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module.exports = applyEmbeddedDiscriminators;
|
|
4
4
|
|
|
5
|
-
function applyEmbeddedDiscriminators(schema, seen = new WeakSet()) {
|
|
5
|
+
function applyEmbeddedDiscriminators(schema, seen = new WeakSet(), overwriteExisting = false) {
|
|
6
6
|
if (seen.has(schema)) {
|
|
7
7
|
return;
|
|
8
8
|
}
|
|
@@ -16,13 +16,17 @@ function applyEmbeddedDiscriminators(schema, seen = new WeakSet()) {
|
|
|
16
16
|
if (!schemaType.schema._applyDiscriminators) {
|
|
17
17
|
continue;
|
|
18
18
|
}
|
|
19
|
-
if (schemaType._appliedDiscriminators) {
|
|
19
|
+
if (schemaType._appliedDiscriminators && !overwriteExisting) {
|
|
20
20
|
continue;
|
|
21
21
|
}
|
|
22
22
|
for (const discriminatorKey of schemaType.schema._applyDiscriminators.keys()) {
|
|
23
23
|
const discriminatorSchema = schemaType.schema._applyDiscriminators.get(discriminatorKey);
|
|
24
24
|
applyEmbeddedDiscriminators(discriminatorSchema, seen);
|
|
25
|
-
schemaType.discriminator(
|
|
25
|
+
schemaType.discriminator(
|
|
26
|
+
discriminatorKey,
|
|
27
|
+
discriminatorSchema,
|
|
28
|
+
overwriteExisting ? { overwriteExisting: true } : null
|
|
29
|
+
);
|
|
26
30
|
}
|
|
27
31
|
schemaType._appliedDiscriminators = true;
|
|
28
32
|
}
|
|
@@ -21,7 +21,7 @@ const CUSTOMIZABLE_DISCRIMINATOR_OPTIONS = {
|
|
|
21
21
|
* ignore
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
module.exports = function discriminator(model, name, schema, tiedValue, applyPlugins, mergeHooks) {
|
|
24
|
+
module.exports = function discriminator(model, name, schema, tiedValue, applyPlugins, mergeHooks, overwriteExisting) {
|
|
25
25
|
if (!(schema && schema.instanceOfSchema)) {
|
|
26
26
|
throw new Error('You must pass a valid discriminator Schema');
|
|
27
27
|
}
|
|
@@ -205,7 +205,7 @@ module.exports = function discriminator(model, name, schema, tiedValue, applyPlu
|
|
|
205
205
|
|
|
206
206
|
model.schema.discriminators[name] = schema;
|
|
207
207
|
|
|
208
|
-
if (model.discriminators[name] && !schema.options.overwriteModels) {
|
|
208
|
+
if (model.discriminators[name] && !schema.options.overwriteModels && !overwriteExisting) {
|
|
209
209
|
throw new Error('Discriminator with name "' + name + '" already exists');
|
|
210
210
|
}
|
|
211
211
|
|
package/lib/model.js
CHANGED
|
@@ -23,6 +23,7 @@ const VersionError = require('./error/version');
|
|
|
23
23
|
const ParallelSaveError = require('./error/parallelSave');
|
|
24
24
|
const applyDefaultsHelper = require('./helpers/document/applyDefaults');
|
|
25
25
|
const applyDefaultsToPOJO = require('./helpers/model/applyDefaultsToPOJO');
|
|
26
|
+
const applyEmbeddedDiscriminators = require('./helpers/discriminator/applyEmbeddedDiscriminators');
|
|
26
27
|
const applyHooks = require('./helpers/model/applyHooks');
|
|
27
28
|
const applyMethods = require('./helpers/model/applyMethods');
|
|
28
29
|
const applyProjection = require('./helpers/projection/applyProjection');
|
|
@@ -298,7 +299,6 @@ Model.prototype.$__handleSave = function(options, callback) {
|
|
|
298
299
|
if (!saveOptions.hasOwnProperty('session') && session != null) {
|
|
299
300
|
saveOptions.session = session;
|
|
300
301
|
}
|
|
301
|
-
|
|
302
302
|
if (this.$isNew) {
|
|
303
303
|
// send entire doc
|
|
304
304
|
const obj = this.toObject(saveToObjectOptions);
|
|
@@ -335,6 +335,18 @@ Model.prototype.$__handleSave = function(options, callback) {
|
|
|
335
335
|
// since it already exists
|
|
336
336
|
this.$__.inserting = false;
|
|
337
337
|
const delta = this.$__delta();
|
|
338
|
+
|
|
339
|
+
if (options.pathsToSave) {
|
|
340
|
+
for (const key in delta[1]['$set']) {
|
|
341
|
+
if (options.pathsToSave.includes(key)) {
|
|
342
|
+
continue;
|
|
343
|
+
} else if (options.pathsToSave.some(pathToSave => key.slice(0, pathToSave.length) === pathToSave && key.charAt(pathToSave.length) === '.')) {
|
|
344
|
+
continue;
|
|
345
|
+
} else {
|
|
346
|
+
delete delta[1]['$set'][key];
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
338
350
|
if (delta) {
|
|
339
351
|
if (delta instanceof MongooseError) {
|
|
340
352
|
callback(delta);
|
|
@@ -364,7 +376,9 @@ Model.prototype.$__handleSave = function(options, callback) {
|
|
|
364
376
|
}
|
|
365
377
|
minimize(updateOp[key]);
|
|
366
378
|
if (Object.keys(updateOp[key]).length === 0) {
|
|
367
|
-
updateOp[key]
|
|
379
|
+
delete updateOp[key];
|
|
380
|
+
update.$unset = update.$unset || {};
|
|
381
|
+
update.$unset[key] = 1;
|
|
368
382
|
}
|
|
369
383
|
}
|
|
370
384
|
}
|
|
@@ -521,6 +535,7 @@ function generateVersionError(doc, modifiedPaths) {
|
|
|
521
535
|
* @param {Number} [options.wtimeout] sets a [timeout for the write concern](https://www.mongodb.com/docs/manual/reference/write-concern/#wtimeout). Overrides the [schema-level `writeConcern` option](https://mongoosejs.com/docs/guide.html#writeConcern).
|
|
522
536
|
* @param {Boolean} [options.checkKeys=true] the MongoDB driver prevents you from saving keys that start with '$' or contain '.' by default. Set this option to `false` to skip that check. See [restrictions on field names](https://docs.mongodb.com/manual/reference/limits/#mongodb-limit-Restrictions-on-Field-Names)
|
|
523
537
|
* @param {Boolean} [options.timestamps=true] if `false` and [timestamps](https://mongoosejs.com/docs/guide.html#timestamps) are enabled, skip timestamps for this `save()`.
|
|
538
|
+
* @param {Array} [options.pathsToSave] An array of paths that tell mongoose to only validate and save the paths in `pathsToSave`.
|
|
524
539
|
* @throws {DocumentNotFoundError} if this [save updates an existing document](https://mongoosejs.com/docs/api/document.html#Document.prototype.isNew) but the document doesn't exist in the database. For example, you will get this error if the document is [deleted between when you retrieved the document and when you saved it](documents.html#updating).
|
|
525
540
|
* @return {Promise}
|
|
526
541
|
* @api public
|
|
@@ -747,7 +762,6 @@ function handleAtomics(self, where, delta, data, value) {
|
|
|
747
762
|
|
|
748
763
|
Model.prototype.$__delta = function() {
|
|
749
764
|
const dirty = this.$__dirty();
|
|
750
|
-
|
|
751
765
|
const optimisticConcurrency = this.$__schema.options.optimisticConcurrency;
|
|
752
766
|
if (optimisticConcurrency) {
|
|
753
767
|
if (Array.isArray(optimisticConcurrency)) {
|
|
@@ -4882,6 +4896,34 @@ Model.compile = function compile(name, schema, collectionName, connection, base)
|
|
|
4882
4896
|
return model;
|
|
4883
4897
|
};
|
|
4884
4898
|
|
|
4899
|
+
/**
|
|
4900
|
+
* Update this model to use the new connection, including updating all internal
|
|
4901
|
+
* references and creating a new `Collection` instance using the new connection.
|
|
4902
|
+
* Not for external use, only used by `setDriver()` to ensure that you can still
|
|
4903
|
+
* call `setDriver()` after creating a model using `mongoose.model()`.
|
|
4904
|
+
*
|
|
4905
|
+
* @param {Connection} newConnection the new connection to use
|
|
4906
|
+
* @api private
|
|
4907
|
+
*/
|
|
4908
|
+
|
|
4909
|
+
Model.$__updateConnection = function $__updateConnection(newConnection) {
|
|
4910
|
+
this.db = newConnection;
|
|
4911
|
+
this.prototype.db = newConnection;
|
|
4912
|
+
this.prototype[modelDbSymbol] = newConnection;
|
|
4913
|
+
|
|
4914
|
+
const collection = newConnection.collection(
|
|
4915
|
+
this.collection.collectionName,
|
|
4916
|
+
this.collection.opts
|
|
4917
|
+
);
|
|
4918
|
+
|
|
4919
|
+
this.prototype.collection = collection;
|
|
4920
|
+
this.prototype.$collection = collection;
|
|
4921
|
+
this.prototype[modelCollectionSymbol] = collection;
|
|
4922
|
+
|
|
4923
|
+
this.collection = collection;
|
|
4924
|
+
this.$__collection = collection;
|
|
4925
|
+
};
|
|
4926
|
+
|
|
4885
4927
|
/**
|
|
4886
4928
|
* Register custom query methods for this model
|
|
4887
4929
|
*
|
|
@@ -4990,6 +5032,14 @@ Model.__subclass = function subclass(conn, schema, collection) {
|
|
|
4990
5032
|
|
|
4991
5033
|
Model.recompileSchema = function recompileSchema() {
|
|
4992
5034
|
this.prototype.$__setSchema(this.schema);
|
|
5035
|
+
|
|
5036
|
+
if (this.schema._applyDiscriminators != null) {
|
|
5037
|
+
for (const disc of this.schema._applyDiscriminators.keys()) {
|
|
5038
|
+
this.discriminator(disc, this.schema._applyDiscriminators.get(disc));
|
|
5039
|
+
}
|
|
5040
|
+
}
|
|
5041
|
+
|
|
5042
|
+
applyEmbeddedDiscriminators(this.schema, new WeakSet(), true);
|
|
4993
5043
|
};
|
|
4994
5044
|
|
|
4995
5045
|
/**
|
package/lib/mongoose.js
CHANGED
|
@@ -166,9 +166,19 @@ Mongoose.prototype.setDriver = function setDriver(driver) {
|
|
|
166
166
|
_mongoose.__driver = driver;
|
|
167
167
|
|
|
168
168
|
const Connection = driver.Connection;
|
|
169
|
+
const oldDefaultConnection = _mongoose.connections[0];
|
|
169
170
|
_mongoose.connections = [new Connection(_mongoose)];
|
|
170
171
|
_mongoose.connections[0].models = _mongoose.models;
|
|
171
172
|
|
|
173
|
+
// Update all models that pointed to the old default connection to
|
|
174
|
+
// the new default connection, including collections
|
|
175
|
+
for (const model of Object.values(_mongoose.models)) {
|
|
176
|
+
if (model.db !== oldDefaultConnection) {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
model.$__updateConnection(_mongoose.connections[0]);
|
|
180
|
+
}
|
|
181
|
+
|
|
172
182
|
return _mongoose;
|
|
173
183
|
};
|
|
174
184
|
|
package/lib/query.js
CHANGED
|
@@ -2861,19 +2861,27 @@ Query.prototype.distinct = function(field, conditions) {
|
|
|
2861
2861
|
* Cannot be used with `distinct()`
|
|
2862
2862
|
*
|
|
2863
2863
|
* @param {Object|String|Array<Array<(string | number)>>} arg
|
|
2864
|
+
* @param {Object} [options]
|
|
2865
|
+
* @param {Boolean} [options.override=false] If true, replace existing sort options with `arg`
|
|
2864
2866
|
* @return {Query} this
|
|
2865
2867
|
* @see cursor.sort https://www.mongodb.com/docs/manual/reference/method/cursor.sort/
|
|
2866
2868
|
* @api public
|
|
2867
2869
|
*/
|
|
2868
2870
|
|
|
2869
|
-
Query.prototype.sort = function(arg) {
|
|
2870
|
-
if (arguments.length >
|
|
2871
|
-
throw new Error('sort()
|
|
2871
|
+
Query.prototype.sort = function(arg, options) {
|
|
2872
|
+
if (arguments.length > 2) {
|
|
2873
|
+
throw new Error('sort() takes at most 2 arguments');
|
|
2874
|
+
}
|
|
2875
|
+
if (options != null && typeof options !== 'object') {
|
|
2876
|
+
throw new Error('sort() options argument must be an object or nullish');
|
|
2872
2877
|
}
|
|
2873
2878
|
|
|
2874
2879
|
if (this.options.sort == null) {
|
|
2875
2880
|
this.options.sort = {};
|
|
2876
2881
|
}
|
|
2882
|
+
if (options && options.override) {
|
|
2883
|
+
this.options.sort = {};
|
|
2884
|
+
}
|
|
2877
2885
|
const sort = this.options.sort;
|
|
2878
2886
|
if (typeof arg === 'string') {
|
|
2879
2887
|
const properties = arg.indexOf(' ') === -1 ? [arg] : arg.split(' ');
|
|
@@ -279,7 +279,7 @@ SchemaDocumentArray.prototype.doValidate = function(array, fn, scope, options) {
|
|
|
279
279
|
continue;
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
-
doc.$__validate(callback);
|
|
282
|
+
doc.$__validate(null, options, callback);
|
|
283
283
|
}
|
|
284
284
|
}
|
|
285
285
|
};
|
|
@@ -330,7 +330,7 @@ SchemaDocumentArray.prototype.doValidateSync = function(array, scope, options) {
|
|
|
330
330
|
continue;
|
|
331
331
|
}
|
|
332
332
|
|
|
333
|
-
const subdocValidateError = doc.validateSync();
|
|
333
|
+
const subdocValidateError = doc.validateSync(options);
|
|
334
334
|
|
|
335
335
|
if (subdocValidateError && resultError == null) {
|
|
336
336
|
resultError = subdocValidateError;
|
|
@@ -325,7 +325,7 @@ SchemaSubdocument.prototype.discriminator = function(name, schema, options) {
|
|
|
325
325
|
schema = schema.clone();
|
|
326
326
|
}
|
|
327
327
|
|
|
328
|
-
schema = discriminator(this.caster, name, schema, value);
|
|
328
|
+
schema = discriminator(this.caster, name, schema, value, null, null, options.overwriteExisting);
|
|
329
329
|
|
|
330
330
|
this.caster.discriminators[name] = _createConstructor(schema, this.caster);
|
|
331
331
|
|
package/lib/schema.js
CHANGED
|
@@ -1300,6 +1300,7 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
|
|
|
1300
1300
|
return clone;
|
|
1301
1301
|
}
|
|
1302
1302
|
|
|
1303
|
+
|
|
1303
1304
|
// If this schema has an associated Mongoose object, use the Mongoose object's
|
|
1304
1305
|
// copy of SchemaTypes re: gh-7158 gh-6933
|
|
1305
1306
|
const MongooseTypes = this.base != null ? this.base.Schema.Types : Schema.Types;
|
|
@@ -1365,9 +1366,13 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
|
|
|
1365
1366
|
}
|
|
1366
1367
|
return new MongooseTypes.DocumentArray(path, cast[options.typeKey], obj, cast);
|
|
1367
1368
|
}
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1369
|
+
if (typeof cast !== 'undefined') {
|
|
1370
|
+
if (Array.isArray(cast) || cast.type === Array || cast.type == 'Array') {
|
|
1371
|
+
if (cast && cast.type == 'Array') {
|
|
1372
|
+
cast.type = Array;
|
|
1373
|
+
}
|
|
1374
|
+
return new MongooseTypes.Array(path, this.interpretAsType(path, cast, options), obj);
|
|
1375
|
+
}
|
|
1371
1376
|
}
|
|
1372
1377
|
|
|
1373
1378
|
// Handle both `new Schema({ arr: [{ subpath: String }] })` and `new Schema({ arr: [{ type: { subpath: string } }] })`
|
|
@@ -1418,7 +1423,6 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
|
|
|
1418
1423
|
type = cast[options.typeKey] && (options.typeKey !== 'type' || !cast.type.type)
|
|
1419
1424
|
? cast[options.typeKey]
|
|
1420
1425
|
: cast;
|
|
1421
|
-
|
|
1422
1426
|
if (Array.isArray(type)) {
|
|
1423
1427
|
return new MongooseTypes.Array(path, this.interpretAsType(path, type, options), obj);
|
|
1424
1428
|
}
|
|
@@ -1948,6 +1952,7 @@ Schema.prototype.plugin = function(fn, opts) {
|
|
|
1948
1952
|
'got "' + (typeof fn) + '"');
|
|
1949
1953
|
}
|
|
1950
1954
|
|
|
1955
|
+
|
|
1951
1956
|
if (opts && opts.deduplicate) {
|
|
1952
1957
|
for (const plugin of this.plugins) {
|
|
1953
1958
|
if (plugin.fn === fn) {
|
|
@@ -2751,7 +2756,7 @@ function isArrayFilter(piece) {
|
|
|
2751
2756
|
*/
|
|
2752
2757
|
|
|
2753
2758
|
Schema.prototype._preCompile = function _preCompile() {
|
|
2754
|
-
idGetter
|
|
2759
|
+
this.plugin(idGetter, { deduplicate: true });
|
|
2755
2760
|
};
|
|
2756
2761
|
|
|
2757
2762
|
/*!
|
package/lib/schemaType.js
CHANGED
|
@@ -803,6 +803,21 @@ SchemaType.prototype.get = function(fn) {
|
|
|
803
803
|
return this;
|
|
804
804
|
};
|
|
805
805
|
|
|
806
|
+
/**
|
|
807
|
+
* Adds multiple validators for this document path.
|
|
808
|
+
* Calls `validate()` for every element in validators.
|
|
809
|
+
*
|
|
810
|
+
* @param {Array<RegExp|Function|Object>} validators
|
|
811
|
+
* @returns this
|
|
812
|
+
*/
|
|
813
|
+
|
|
814
|
+
SchemaType.prototype.validateAll = function(validators) {
|
|
815
|
+
for (let i = 0; i < validators.length; i++) {
|
|
816
|
+
this.validate(validators[i]);
|
|
817
|
+
}
|
|
818
|
+
return this;
|
|
819
|
+
};
|
|
820
|
+
|
|
806
821
|
/**
|
|
807
822
|
* Adds validator(s) for this document path.
|
|
808
823
|
*
|
|
@@ -863,7 +878,7 @@ SchemaType.prototype.get = function(fn) {
|
|
|
863
878
|
*
|
|
864
879
|
* schema.path('name').validate({
|
|
865
880
|
* validator: function() { throw new Error('Oops!'); },
|
|
866
|
-
* // `errors['name']` will be "Oops!"
|
|
881
|
+
* // `errors['name'].message` will be "Oops!"
|
|
867
882
|
* message: function(props) { return props.reason.message; }
|
|
868
883
|
* });
|
|
869
884
|
*
|
|
@@ -1285,6 +1300,9 @@ SchemaType.prototype.select = function select(val) {
|
|
|
1285
1300
|
SchemaType.prototype.doValidate = function(value, fn, scope, options) {
|
|
1286
1301
|
let err = false;
|
|
1287
1302
|
const path = this.path;
|
|
1303
|
+
if (typeof fn !== 'function') {
|
|
1304
|
+
throw new TypeError(`Must pass callback function to doValidate(), got ${typeof fn}`);
|
|
1305
|
+
}
|
|
1288
1306
|
|
|
1289
1307
|
// Avoid non-object `validators`
|
|
1290
1308
|
const validators = this.validators.
|
|
@@ -1419,7 +1437,6 @@ SchemaType.prototype.doValidateSync = function(value, scope, options) {
|
|
|
1419
1437
|
let i = 0;
|
|
1420
1438
|
const len = validators.length;
|
|
1421
1439
|
for (i = 0; i < len; ++i) {
|
|
1422
|
-
|
|
1423
1440
|
const v = validators[i];
|
|
1424
1441
|
|
|
1425
1442
|
if (v === null || typeof v !== 'object') {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mongoose",
|
|
3
3
|
"description": "Mongoose MongoDB ODM",
|
|
4
|
-
"version": "8.
|
|
4
|
+
"version": "8.3.1",
|
|
5
5
|
"author": "Guillermo Rauch <guillermo@learnboost.com>",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"mongodb",
|
|
@@ -19,17 +19,17 @@
|
|
|
19
19
|
],
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"bson": "^6.
|
|
23
|
-
"kareem": "2.
|
|
24
|
-
"mongodb": "6.
|
|
22
|
+
"bson": "^6.5.0",
|
|
23
|
+
"kareem": "2.6.3",
|
|
24
|
+
"mongodb": "6.5.0",
|
|
25
25
|
"mpath": "0.9.0",
|
|
26
26
|
"mquery": "5.0.0",
|
|
27
27
|
"ms": "2.1.3",
|
|
28
28
|
"sift": "16.0.1"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@babel/core": "7.24.
|
|
32
|
-
"@babel/preset-env": "7.24.
|
|
31
|
+
"@babel/core": "7.24.3",
|
|
32
|
+
"@babel/preset-env": "7.24.3",
|
|
33
33
|
"@typescript-eslint/eslint-plugin": "^6.2.1",
|
|
34
34
|
"@typescript-eslint/parser": "^6.2.1",
|
|
35
35
|
"acquit": "1.3.0",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"dotenv": "16.4.5",
|
|
47
47
|
"dox": "1.0.0",
|
|
48
48
|
"eslint": "8.57.0",
|
|
49
|
-
"eslint-plugin-markdown": "^
|
|
49
|
+
"eslint-plugin-markdown": "^4.0.1",
|
|
50
50
|
"eslint-plugin-mocha-no-only": "1.1.1",
|
|
51
51
|
"express": "^4.18.1",
|
|
52
52
|
"fs-extra": "~11.2.0",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"markdownlint-cli2": "^0.12.1",
|
|
57
57
|
"marked": "4.3.0",
|
|
58
58
|
"mkdirp": "^3.0.1",
|
|
59
|
-
"mocha": "10.
|
|
59
|
+
"mocha": "10.4.0",
|
|
60
60
|
"moment": "2.x",
|
|
61
61
|
"mongodb-memory-server": "8.15.1",
|
|
62
62
|
"ncp": "^2.0.0",
|
|
@@ -65,10 +65,10 @@
|
|
|
65
65
|
"q": "1.5.1",
|
|
66
66
|
"sinon": "17.0.1",
|
|
67
67
|
"stream-browserify": "3.0.0",
|
|
68
|
-
"tsd": "0.
|
|
69
|
-
"typescript": "5.
|
|
68
|
+
"tsd": "0.31.0",
|
|
69
|
+
"typescript": "5.4.3",
|
|
70
70
|
"uuid": "9.0.1",
|
|
71
|
-
"webpack": "5.
|
|
71
|
+
"webpack": "5.91.0"
|
|
72
72
|
},
|
|
73
73
|
"directories": {
|
|
74
74
|
"lib": "./lib/mongoose"
|