mongoose 9.0.1 → 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 +126 -79
- package/lib/drivers/node-mongodb-native/collection.js +33 -126
- 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 +42 -48
- 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 +3 -2
- package/types/index.d.ts +26 -9
- package/types/inferrawdoctype.d.ts +9 -3
- package/types/inferschematype.d.ts +20 -27
- package/types/middlewares.d.ts +11 -0
- package/types/models.d.ts +15 -5
- package/types/query.d.ts +1 -1
- package/types/schemaoptions.d.ts +4 -2
- package/types/utility.d.ts +1 -1
- package/types/virtuals.d.ts +3 -3
|
@@ -26,7 +26,7 @@ const getConstructor = require('../helpers/discriminator/getConstructor');
|
|
|
26
26
|
*/
|
|
27
27
|
|
|
28
28
|
function SchemaDocumentArrayElement(path, schema, options, parentSchema) {
|
|
29
|
-
this.$parentSchemaType = options
|
|
29
|
+
this.$parentSchemaType = options?.$parentSchemaType;
|
|
30
30
|
if (!this.$parentSchemaType) {
|
|
31
31
|
throw new MongooseError('Cannot create DocumentArrayElement schematype without a parent');
|
|
32
32
|
}
|
|
@@ -35,7 +35,7 @@ function SchemaDocumentArrayElement(path, schema, options, parentSchema) {
|
|
|
35
35
|
SchemaType.call(this, path, options, 'DocumentArrayElement', parentSchema);
|
|
36
36
|
|
|
37
37
|
this.$isMongooseDocumentArrayElement = true;
|
|
38
|
-
this.Constructor = options
|
|
38
|
+
this.Constructor = options?.Constructor;
|
|
39
39
|
this.schema = schema;
|
|
40
40
|
}
|
|
41
41
|
|
|
@@ -76,7 +76,7 @@ SchemaDocumentArrayElement.prototype.doValidate = async function doValidate(valu
|
|
|
76
76
|
const Constructor = getConstructor(this.Constructor, value);
|
|
77
77
|
|
|
78
78
|
if (value && !(value instanceof Constructor)) {
|
|
79
|
-
value = new Constructor(value, scope, null, null, options
|
|
79
|
+
value = new Constructor(value, scope, null, null, options?.index ?? null);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
return SchemaSubdocument.prototype.doValidate.call(this, value, scope, options);
|
package/lib/schema/map.js
CHANGED
|
@@ -172,7 +172,7 @@ SchemaMap.prototype._createNestedSchemaType = function _createNestedSchemaType(s
|
|
|
172
172
|
let _mapType = { type: {} };
|
|
173
173
|
if (utils.hasUserDefinedProperty(obj, 'of')) {
|
|
174
174
|
const isInlineSchema = utils.isPOJO(obj.of) &&
|
|
175
|
-
|
|
175
|
+
utils.hasOwnKeys(obj.of) &&
|
|
176
176
|
!utils.hasUserDefinedProperty(obj.of, schema.options.typeKey);
|
|
177
177
|
if (isInlineSchema) {
|
|
178
178
|
_mapType = { [schema.options.typeKey]: new Schema(obj.of) };
|
package/lib/schema/mixed.js
CHANGED
|
@@ -21,12 +21,12 @@ const utils = require('../utils');
|
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
function SchemaMixed(path, options, _schemaOptions, parentSchema) {
|
|
24
|
-
if (options
|
|
24
|
+
if (options?.default) {
|
|
25
25
|
const def = options.default;
|
|
26
26
|
if (Array.isArray(def) && def.length === 0) {
|
|
27
27
|
// make sure empty array defaults are handled
|
|
28
28
|
options.default = Array;
|
|
29
|
-
} else if (!options.shared && isObject(def) &&
|
|
29
|
+
} else if (!options.shared && isObject(def) && utils.hasOwnKeys(def) === false) {
|
|
30
30
|
// prevent odd "shared" objects between documents
|
|
31
31
|
options.default = function() {
|
|
32
32
|
return {};
|
package/lib/schema/number.js
CHANGED
|
@@ -221,7 +221,7 @@ SchemaNumber.prototype.min = function(value, message) {
|
|
|
221
221
|
}, this);
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
-
if (value
|
|
224
|
+
if (value != null) {
|
|
225
225
|
let msg = message || MongooseError.messages.Number.min;
|
|
226
226
|
msg = msg.replace(/{MIN}/, value);
|
|
227
227
|
this.validators.push({
|
|
@@ -275,7 +275,7 @@ SchemaNumber.prototype.max = function(value, message) {
|
|
|
275
275
|
}, this);
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
-
if (value
|
|
278
|
+
if (value != null) {
|
|
279
279
|
let msg = message || MongooseError.messages.Number.max;
|
|
280
280
|
msg = msg.replace(/{MAX}/, value);
|
|
281
281
|
this.validators.push({
|
|
@@ -335,7 +335,25 @@ SchemaNumber.prototype.enum = function(values, message) {
|
|
|
335
335
|
}
|
|
336
336
|
|
|
337
337
|
if (utils.isPOJO(values)) {
|
|
338
|
-
|
|
338
|
+
// TypeScript numeric enums produce objects with reverse
|
|
339
|
+
// mappings, e.g. { 0: 'Zero', 1: 'One', Zero: 0, One: 1 }.
|
|
340
|
+
// Object.values on that will yield ['Zero','One',0,1].
|
|
341
|
+
// For Number schema enums we only want the numeric values,
|
|
342
|
+
// otherwise casting the name strings to Number will throw.
|
|
343
|
+
const keys = Object.keys(values).sort();
|
|
344
|
+
const objVals = Object.values(values).sort();
|
|
345
|
+
// If keys and values are equal and half of values are numbers,
|
|
346
|
+
// this is likely a TS enum with reverse mapping, so use only the numbers.
|
|
347
|
+
if (
|
|
348
|
+
keys.length === objVals.length &&
|
|
349
|
+
keys.every((k, i) => k === String(objVals[i])) &&
|
|
350
|
+
objVals.filter(v => typeof v === 'number').length === Math.floor(objVals.length / 2)
|
|
351
|
+
) {
|
|
352
|
+
values = objVals.filter(v => typeof v === 'number');
|
|
353
|
+
} else {
|
|
354
|
+
// Avoid sorting the values to preserve user-specified order
|
|
355
|
+
values = Object.values(values);
|
|
356
|
+
}
|
|
339
357
|
}
|
|
340
358
|
message = message || MongooseError.messages.Number.enum;
|
|
341
359
|
}
|
|
@@ -376,7 +394,7 @@ SchemaNumber.prototype.cast = function(value, doc, init, prev, options) {
|
|
|
376
394
|
}
|
|
377
395
|
}
|
|
378
396
|
|
|
379
|
-
const val = value
|
|
397
|
+
const val = value?._id !== undefined ?
|
|
380
398
|
value._id : // documents
|
|
381
399
|
value;
|
|
382
400
|
|
package/lib/schema/objectId.js
CHANGED
|
@@ -29,7 +29,7 @@ let Document;
|
|
|
29
29
|
|
|
30
30
|
function SchemaObjectId(key, options, _schemaOptions, parentSchema) {
|
|
31
31
|
const isKeyHexStr = typeof key === 'string' && key.length === 24 && /^[a-f0-9]+$/i.test(key);
|
|
32
|
-
const suppressWarning = options
|
|
32
|
+
const suppressWarning = options?.suppressWarning;
|
|
33
33
|
if ((isKeyHexStr || typeof key === 'undefined') && !suppressWarning) {
|
|
34
34
|
utils.warn('mongoose: To create a new ObjectId please try ' +
|
|
35
35
|
'`Mongoose.Types.ObjectId` instead of using ' +
|
package/lib/schema/string.js
CHANGED
|
@@ -416,7 +416,7 @@ SchemaString.prototype.minlength = function(value, message) {
|
|
|
416
416
|
}, this);
|
|
417
417
|
}
|
|
418
418
|
|
|
419
|
-
if (value
|
|
419
|
+
if (value != null) {
|
|
420
420
|
let msg = message || MongooseError.messages.String.minlength;
|
|
421
421
|
msg = msg.replace(/{MINLENGTH}/, value);
|
|
422
422
|
this.validators.push({
|
|
@@ -472,7 +472,7 @@ SchemaString.prototype.maxlength = function(value, message) {
|
|
|
472
472
|
}, this);
|
|
473
473
|
}
|
|
474
474
|
|
|
475
|
-
if (value
|
|
475
|
+
if (value != null) {
|
|
476
476
|
let msg = message || MongooseError.messages.String.maxlength;
|
|
477
477
|
msg = msg.replace(/{MAXLENGTH}/, value);
|
|
478
478
|
this.validators.push({
|
|
@@ -41,8 +41,7 @@ function SchemaSubdocument(schema, path, options, parentSchema) {
|
|
|
41
41
|
if (schema.options.timeseries) {
|
|
42
42
|
throw new InvalidSchemaOptionError(path, 'timeseries');
|
|
43
43
|
}
|
|
44
|
-
const schemaTypeIdOption = SchemaSubdocument.defaultOptions
|
|
45
|
-
SchemaSubdocument.defaultOptions._id;
|
|
44
|
+
const schemaTypeIdOption = SchemaSubdocument.defaultOptions?._id;
|
|
46
45
|
if (schemaTypeIdOption != null) {
|
|
47
46
|
options = options || {};
|
|
48
47
|
options._id = schemaTypeIdOption;
|
|
@@ -87,7 +86,7 @@ function _createConstructor(schema, baseClass, options) {
|
|
|
87
86
|
|
|
88
87
|
schema._preCompile();
|
|
89
88
|
|
|
90
|
-
const proto = baseClass
|
|
89
|
+
const proto = baseClass?.prototype ?? SubdocumentType.prototype;
|
|
91
90
|
_embedded.prototype = Object.create(proto);
|
|
92
91
|
_embedded.prototype.$__setSchema(schema);
|
|
93
92
|
_embedded.prototype.constructor = _embedded;
|
|
@@ -177,7 +176,7 @@ Object.defineProperty(SchemaSubdocument.prototype, '$conditionalHandlers', {
|
|
|
177
176
|
*/
|
|
178
177
|
|
|
179
178
|
SchemaSubdocument.prototype.cast = function(val, doc, init, priorVal, options) {
|
|
180
|
-
if (val
|
|
179
|
+
if (val?.$isSingleNested && val.parent === doc) {
|
|
181
180
|
return val;
|
|
182
181
|
}
|
|
183
182
|
|
|
@@ -192,7 +191,7 @@ SchemaSubdocument.prototype.cast = function(val, doc, init, priorVal, options) {
|
|
|
192
191
|
let subdoc;
|
|
193
192
|
|
|
194
193
|
// Only pull relevant selected paths and pull out the base path
|
|
195
|
-
const parentSelected = doc
|
|
194
|
+
const parentSelected = doc?.$__?.selected;
|
|
196
195
|
const path = this.path;
|
|
197
196
|
const selected = parentSelected == null ? null : Object.keys(parentSelected).reduce((obj, key) => {
|
|
198
197
|
if (key.startsWith(path + '.')) {
|
|
@@ -216,7 +215,7 @@ SchemaSubdocument.prototype.cast = function(val, doc, init, priorVal, options) {
|
|
|
216
215
|
applyDefaults(subdoc, selected, exclude);
|
|
217
216
|
} else {
|
|
218
217
|
options = Object.assign({}, options, { priorDoc: priorVal });
|
|
219
|
-
if (
|
|
218
|
+
if (utils.hasOwnKeys(val) === false) {
|
|
220
219
|
return new Constructor({}, selected, doc, options);
|
|
221
220
|
}
|
|
222
221
|
|
|
@@ -256,9 +255,7 @@ SchemaSubdocument.prototype.castForQuery = function($conditional, val, context,
|
|
|
256
255
|
val = this._applySetters(val, context);
|
|
257
256
|
}
|
|
258
257
|
|
|
259
|
-
const overrideStrict = options
|
|
260
|
-
options.strict :
|
|
261
|
-
void 0;
|
|
258
|
+
const overrideStrict = options?.strict ?? void 0;
|
|
262
259
|
|
|
263
260
|
try {
|
|
264
261
|
val = new Constructor(val, overrideStrict);
|
|
@@ -282,10 +279,10 @@ SchemaSubdocument.prototype.doValidate = async function doValidate(value, scope,
|
|
|
282
279
|
const Constructor = getConstructor(this.Constructor, value);
|
|
283
280
|
|
|
284
281
|
if (value && !(value instanceof Constructor)) {
|
|
285
|
-
value = new Constructor(value, null,
|
|
282
|
+
value = new Constructor(value, null, scope?.$__ != null ? scope : null);
|
|
286
283
|
}
|
|
287
284
|
|
|
288
|
-
if (options
|
|
285
|
+
if (options?.skipSchemaValidators) {
|
|
289
286
|
if (!value) {
|
|
290
287
|
return;
|
|
291
288
|
}
|
|
@@ -305,7 +302,7 @@ SchemaSubdocument.prototype.doValidate = async function doValidate(value, scope,
|
|
|
305
302
|
*/
|
|
306
303
|
|
|
307
304
|
SchemaSubdocument.prototype.doValidateSync = function(value, scope, options) {
|
|
308
|
-
if (!options
|
|
305
|
+
if (!options?.skipSchemaValidators) {
|
|
309
306
|
const schemaTypeError = SchemaType.prototype.doValidateSync.call(this, value, scope);
|
|
310
307
|
if (schemaTypeError) {
|
|
311
308
|
return schemaTypeError;
|
package/lib/schema/union.js
CHANGED
|
@@ -24,7 +24,7 @@ class Union extends SchemaType {
|
|
|
24
24
|
*/
|
|
25
25
|
constructor(key, options, schemaOptions, parentSchema) {
|
|
26
26
|
super(key, options, 'Union', parentSchema);
|
|
27
|
-
if (!
|
|
27
|
+
if (!Array.isArray(options?.of) || options.of.length === 0) {
|
|
28
28
|
throw new Error('Union schema type requires an array of types');
|
|
29
29
|
}
|
|
30
30
|
this.schemaTypes = options.of.map(obj => parentSchema.interpretAsType(key, obj, schemaOptions));
|
package/lib/schema.js
CHANGED
|
@@ -78,7 +78,7 @@ const numberRE = /^\d+$/;
|
|
|
78
78
|
* - [validateBeforeSave](https://mongoosejs.com/docs/guide.html#validateBeforeSave) - bool - defaults to `true`
|
|
79
79
|
* - [validateModifiedOnly](https://mongoosejs.com/docs/api/document.html#Document.prototype.validate()) - bool - defaults to `false`
|
|
80
80
|
* - [versionKey](https://mongoosejs.com/docs/guide.html#versionKey): string or object - defaults to "__v"
|
|
81
|
-
* - [optimisticConcurrency](https://mongoosejs.com/docs/guide.html#optimisticConcurrency): bool or string[] or { exclude: string[] } - defaults to false. Set to true to enable [optimistic concurrency](https://thecodebarbarian.com/whats-new-in-mongoose-5-10-optimistic-concurrency.html). Set to string array to enable optimistic concurrency for
|
|
81
|
+
* - [optimisticConcurrency](https://mongoosejs.com/docs/guide.html#optimisticConcurrency): bool or string[] or { exclude: string[] } - defaults to false. Set to true to enable [optimistic concurrency](https://thecodebarbarian.com/whats-new-in-mongoose-5-10-optimistic-concurrency.html) for all fields. Set to a string array to enable optimistic concurrency only for the specified fields; note that this **replaces** the default array versioning behavior. Set to `{ exclude: string[] }` to enable optimistic concurrency for all fields except the specified ones; this also replaces the default array versioning.
|
|
82
82
|
* - [collation](https://mongoosejs.com/docs/guide.html#collation): object - defaults to null (which means use no collation)
|
|
83
83
|
* - [timeseries](https://mongoosejs.com/docs/guide.html#timeseries): object - defaults to null (which means this schema's collection won't be a timeseries collection)
|
|
84
84
|
* - [selectPopulatedPaths](https://mongoosejs.com/docs/guide.html#selectPopulatedPaths): boolean - defaults to `true`
|
|
@@ -88,6 +88,7 @@ const numberRE = /^\d+$/;
|
|
|
88
88
|
* - [virtuals](https://mongoosejs.com/docs/tutorials/virtuals.html#virtuals-via-schema-options): object - virtuals to define, alias for [`.virtual`](https://mongoosejs.com/docs/api/schema.html#Schema.prototype.virtual())
|
|
89
89
|
* - [collectionOptions]: object with options passed to [`createCollection()`](https://www.mongodb.com/docs/manual/reference/method/db.createCollection/) when calling `Model.createCollection()` or `autoCreate` set to true.
|
|
90
90
|
* - [encryptionType]: the encryption type for the schema. Valid options are `csfle` or `queryableEncryption`. See https://mongoosejs.com/docs/field-level-encryption.
|
|
91
|
+
* - [lean]: boolean - set to true to make all queries use [lean](https://mongoosejs.com/docs/tutorials/lean.html) by default. Defaults to false.
|
|
91
92
|
*
|
|
92
93
|
* #### Options for Nested Schemas:
|
|
93
94
|
*
|
|
@@ -120,11 +121,11 @@ function Schema(obj, options) {
|
|
|
120
121
|
this.callQueue = [];
|
|
121
122
|
this._indexes = [];
|
|
122
123
|
this._searchIndexes = [];
|
|
123
|
-
this.methods =
|
|
124
|
+
this.methods = options?.methods || {};
|
|
124
125
|
this.methodOptions = {};
|
|
125
|
-
this.statics =
|
|
126
|
+
this.statics = options?.statics || {};
|
|
126
127
|
this.tree = {};
|
|
127
|
-
this.query =
|
|
128
|
+
this.query = options?.query || {};
|
|
128
129
|
this.childSchemas = [];
|
|
129
130
|
this.plugins = [];
|
|
130
131
|
// For internal debugging. Do not use this to try to save a schema in MDB.
|
|
@@ -147,7 +148,7 @@ function Schema(obj, options) {
|
|
|
147
148
|
}
|
|
148
149
|
|
|
149
150
|
// build virtual paths
|
|
150
|
-
if (options
|
|
151
|
+
if (options?.virtuals) {
|
|
151
152
|
const virtuals = options.virtuals;
|
|
152
153
|
const pathNames = Object.keys(virtuals);
|
|
153
154
|
for (const pathName of pathNames) {
|
|
@@ -165,7 +166,7 @@ function Schema(obj, options) {
|
|
|
165
166
|
}
|
|
166
167
|
|
|
167
168
|
// check if _id's value is a subdocument (gh-2276)
|
|
168
|
-
const _idSubDoc = obj
|
|
169
|
+
const _idSubDoc = obj?._id && utils.isObject(obj._id);
|
|
169
170
|
|
|
170
171
|
// ensure the documents get an auto _id unless disabled
|
|
171
172
|
const auto_id = !this.paths['_id'] &&
|
|
@@ -602,7 +603,7 @@ Schema.prototype.omit = function(paths, options) {
|
|
|
602
603
|
|
|
603
604
|
Schema.prototype.defaultOptions = function(options) {
|
|
604
605
|
this._userProvidedOptions = options == null ? {} : clone(options);
|
|
605
|
-
const baseOptions = this.base
|
|
606
|
+
const baseOptions = this.base?.options || {};
|
|
606
607
|
const strict = 'strict' in baseOptions ? baseOptions.strict : true;
|
|
607
608
|
const strictQuery = 'strictQuery' in baseOptions ? baseOptions.strictQuery : false;
|
|
608
609
|
const id = 'id' in baseOptions ? baseOptions.id : true;
|
|
@@ -722,9 +723,7 @@ Schema.prototype._defaultToObjectOptions = function(json) {
|
|
|
722
723
|
return this._defaultToObjectOptionsMap[path];
|
|
723
724
|
}
|
|
724
725
|
|
|
725
|
-
const baseOptions = this.base
|
|
726
|
-
this.base.options &&
|
|
727
|
-
this.base.options[path] || {};
|
|
726
|
+
const baseOptions = this.base?.options?.[path] || {};
|
|
728
727
|
const schemaOptions = this.options[path] || {};
|
|
729
728
|
// merge base default options with Schema's set default options if available.
|
|
730
729
|
// `clone` is necessary here because `utils.options` directly modifies the second input.
|
|
@@ -771,7 +770,7 @@ Schema.prototype.encryptionType = function encryptionType(encryptionType) {
|
|
|
771
770
|
*/
|
|
772
771
|
|
|
773
772
|
Schema.prototype.add = function add(obj, prefix) {
|
|
774
|
-
if (obj instanceof Schema ||
|
|
773
|
+
if (obj instanceof Schema || obj?.instanceOfSchema) {
|
|
775
774
|
merge(this, obj);
|
|
776
775
|
return this;
|
|
777
776
|
}
|
|
@@ -811,7 +810,7 @@ Schema.prototype.add = function add(obj, prefix) {
|
|
|
811
810
|
let isMongooseTypeString = false;
|
|
812
811
|
if (typeof val === 'string') {
|
|
813
812
|
// Handle the case in which the type is specified as a string (eg. 'date', 'oid', ...)
|
|
814
|
-
const MongooseTypes = this.base
|
|
813
|
+
const MongooseTypes = this.base?.Schema.Types ?? Schema.Types;
|
|
815
814
|
const upperVal = val.charAt(0).toUpperCase() + val.substring(1);
|
|
816
815
|
isMongooseTypeString = MongooseTypes[upperVal] != null;
|
|
817
816
|
}
|
|
@@ -824,7 +823,7 @@ Schema.prototype.add = function add(obj, prefix) {
|
|
|
824
823
|
`a valid type at path \`${key}\`. See ` +
|
|
825
824
|
'https://bit.ly/mongoose-schematypes for a list of valid schema types.');
|
|
826
825
|
}
|
|
827
|
-
if (val instanceof VirtualType || (val.constructor
|
|
826
|
+
if (val instanceof VirtualType || (val.constructor?.name ?? null) === 'VirtualType') {
|
|
828
827
|
this.virtual(val);
|
|
829
828
|
continue;
|
|
830
829
|
}
|
|
@@ -841,13 +840,13 @@ Schema.prototype.add = function add(obj, prefix) {
|
|
|
841
840
|
this.nested[prefix.substring(0, prefix.length - 1)] = true;
|
|
842
841
|
}
|
|
843
842
|
this.path(prefix + key, val);
|
|
844
|
-
if (
|
|
843
|
+
if (!val[0]?.instanceOfSchema && utils.isPOJO(val[0]?.discriminators)) {
|
|
845
844
|
const schemaType = this.path(prefix + key);
|
|
846
845
|
for (const key in val[0].discriminators) {
|
|
847
846
|
schemaType.discriminator(key, val[0].discriminators[key]);
|
|
848
847
|
}
|
|
849
848
|
}
|
|
850
|
-
} else if (
|
|
849
|
+
} else if (utils.hasOwnKeys(val) === false) {
|
|
851
850
|
// Special-case: {} always interpreted as Mixed path so leaf at this node
|
|
852
851
|
if (prefix) {
|
|
853
852
|
this.nested[prefix.substring(0, prefix.length - 1)] = true;
|
|
@@ -862,7 +861,7 @@ Schema.prototype.add = function add(obj, prefix) {
|
|
|
862
861
|
} else {
|
|
863
862
|
// There IS a bona-fide type key that may also be a POJO
|
|
864
863
|
const _typeDef = val[typeKey];
|
|
865
|
-
if (isPOJO(_typeDef) &&
|
|
864
|
+
if (isPOJO(_typeDef) && utils.hasOwnKeys(_typeDef)) {
|
|
866
865
|
// If a POJO is the value of a type key, make it a subdocument
|
|
867
866
|
if (prefix) {
|
|
868
867
|
this.nested[prefix.substring(0, prefix.length - 1)] = true;
|
|
@@ -893,7 +892,7 @@ Schema.prototype.add = function add(obj, prefix) {
|
|
|
893
892
|
this.nested[prefix.substring(0, prefix.length - 1)] = true;
|
|
894
893
|
}
|
|
895
894
|
this.path(prefix + key, val);
|
|
896
|
-
if (
|
|
895
|
+
if (!val?.instanceOfSchema && utils.isPOJO(val?.discriminators)) {
|
|
897
896
|
const schemaType = this.path(prefix + key);
|
|
898
897
|
for (const key in val.discriminators) {
|
|
899
898
|
schemaType.discriminator(key, val.discriminators[key]);
|
|
@@ -965,7 +964,7 @@ Schema.prototype._removeEncryptedField = function _removeEncryptedField(path) {
|
|
|
965
964
|
* @returns {boolean}
|
|
966
965
|
*/
|
|
967
966
|
Schema.prototype._hasEncryptedFields = function _hasEncryptedFields() {
|
|
968
|
-
return
|
|
967
|
+
return utils.hasOwnKeys(this.encryptedFields);
|
|
969
968
|
};
|
|
970
969
|
|
|
971
970
|
/**
|
|
@@ -1585,8 +1584,8 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
|
|
|
1585
1584
|
|
|
1586
1585
|
// If this schema has an associated Mongoose object, use the Mongoose object's
|
|
1587
1586
|
// copy of SchemaTypes re: gh-7158 gh-6933
|
|
1588
|
-
const MongooseTypes = this.base
|
|
1589
|
-
const Types = this.base
|
|
1587
|
+
const MongooseTypes = this.base?.Schema.Types ?? Schema.Types;
|
|
1588
|
+
const Types = this.base?.Types ?? require('./types');
|
|
1590
1589
|
|
|
1591
1590
|
if (!utils.isPOJO(obj) && !(obj instanceof SchemaTypeOptions)) {
|
|
1592
1591
|
const constructorName = utils.getFunctionName(obj.constructor);
|
|
@@ -1626,7 +1625,7 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
|
|
|
1626
1625
|
: type[0];
|
|
1627
1626
|
|
|
1628
1627
|
// new Schema({ path: [new Schema({ ... })] })
|
|
1629
|
-
if (cast
|
|
1628
|
+
if (cast?.instanceOfSchema) {
|
|
1630
1629
|
if (!(cast instanceof Schema)) {
|
|
1631
1630
|
if (this.options._isMerging) {
|
|
1632
1631
|
cast = new Schema(cast);
|
|
@@ -1660,7 +1659,7 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
|
|
|
1660
1659
|
}
|
|
1661
1660
|
if (typeof cast !== 'undefined') {
|
|
1662
1661
|
if (Array.isArray(cast) || cast.type === Array || cast.type == 'Array') {
|
|
1663
|
-
if (cast
|
|
1662
|
+
if (cast?.type == 'Array') {
|
|
1664
1663
|
cast.type = Array;
|
|
1665
1664
|
}
|
|
1666
1665
|
return new MongooseTypes.Array(path, this.interpretAsType(path, cast, options), obj, null, this);
|
|
@@ -1674,7 +1673,7 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
|
|
|
1674
1673
|
if (typeof cast === 'string') {
|
|
1675
1674
|
cast = MongooseTypes[cast.charAt(0).toUpperCase() + cast.substring(1)];
|
|
1676
1675
|
} else if (utils.isPOJO(castFromTypeKey)) {
|
|
1677
|
-
if (
|
|
1676
|
+
if (utils.hasOwnKeys(castFromTypeKey)) {
|
|
1678
1677
|
// The `minimize` and `typeKey` options propagate to child schemas
|
|
1679
1678
|
// declared inline, like `{ arr: [{ val: { $type: String } }] }`.
|
|
1680
1679
|
// See gh-3560
|
|
@@ -1747,7 +1746,7 @@ Schema.prototype.interpretAsType = function(path, obj, options) {
|
|
|
1747
1746
|
return new MongooseTypes.Array(path, cast || MongooseTypes.Mixed, obj, options, this);
|
|
1748
1747
|
}
|
|
1749
1748
|
|
|
1750
|
-
if (type
|
|
1749
|
+
if (type?.instanceOfSchema) {
|
|
1751
1750
|
return new MongooseTypes.Subdocument(type, path, obj, this);
|
|
1752
1751
|
}
|
|
1753
1752
|
|
|
@@ -2008,7 +2007,7 @@ function getPositionalPathType(self, path, cleanPath) {
|
|
|
2008
2007
|
continue;
|
|
2009
2008
|
}
|
|
2010
2009
|
|
|
2011
|
-
if (!
|
|
2010
|
+
if (!val?.schema) {
|
|
2012
2011
|
val = undefined;
|
|
2013
2012
|
break;
|
|
2014
2013
|
}
|
|
@@ -2206,7 +2205,7 @@ Schema.prototype.plugin = function(fn, opts) {
|
|
|
2206
2205
|
}
|
|
2207
2206
|
|
|
2208
2207
|
|
|
2209
|
-
if (opts
|
|
2208
|
+
if (opts?.deduplicate) {
|
|
2210
2209
|
for (const plugin of this.plugins) {
|
|
2211
2210
|
if (plugin.fn === fn) {
|
|
2212
2211
|
return this;
|
|
@@ -2655,9 +2654,9 @@ Schema.prototype.virtual = function(name, options) {
|
|
|
2655
2654
|
return mem[part];
|
|
2656
2655
|
}, this.tree);
|
|
2657
2656
|
|
|
2658
|
-
if (options
|
|
2657
|
+
if (options?.applyToArray && parts.length > 1) {
|
|
2659
2658
|
const path = this.path(parts.slice(0, -1).join('.'));
|
|
2660
|
-
if (path
|
|
2659
|
+
if (path?.$isMongooseArray) {
|
|
2661
2660
|
return path.virtual(parts[parts.length - 1], options);
|
|
2662
2661
|
} else {
|
|
2663
2662
|
throw new MongooseError(`Path "${path}" is not an array`);
|
package/lib/schemaType.js
CHANGED
|
@@ -416,7 +416,7 @@ SchemaType.prototype.default = function(val) {
|
|
|
416
416
|
return void 0;
|
|
417
417
|
}
|
|
418
418
|
|
|
419
|
-
if (val
|
|
419
|
+
if (val?.instanceOfSchema) {
|
|
420
420
|
throw new MongooseError('Cannot set default value of path `' + this.path +
|
|
421
421
|
'` to a mongoose Schema instance.');
|
|
422
422
|
}
|
|
@@ -1112,7 +1112,7 @@ SchemaType.prototype.required = function(required, message) {
|
|
|
1112
1112
|
this.isRequired = true;
|
|
1113
1113
|
|
|
1114
1114
|
this.requiredValidator = function(v) {
|
|
1115
|
-
const cachedRequired = this
|
|
1115
|
+
const cachedRequired = this?.$__?.cachedRequired;
|
|
1116
1116
|
|
|
1117
1117
|
// no validation when this path wasn't selected in the query.
|
|
1118
1118
|
if (cachedRequired != null && !this.$__isSelected(_this.path) && !this[documentIsModified](_this.path)) {
|
|
@@ -1209,12 +1209,12 @@ SchemaType.prototype.getDefault = function(scope, init, options) {
|
|
|
1209
1209
|
ret = this.defaultValue;
|
|
1210
1210
|
}
|
|
1211
1211
|
|
|
1212
|
-
if (ret
|
|
1213
|
-
if (typeof ret === 'object' &&
|
|
1212
|
+
if (ret != null) {
|
|
1213
|
+
if (typeof ret === 'object' && !this.options?.shared) {
|
|
1214
1214
|
ret = clone(ret);
|
|
1215
1215
|
}
|
|
1216
1216
|
|
|
1217
|
-
if (options
|
|
1217
|
+
if (options?.skipCast) {
|
|
1218
1218
|
return this._applySetters(ret, scope);
|
|
1219
1219
|
}
|
|
1220
1220
|
|
|
@@ -1359,7 +1359,7 @@ SchemaType.prototype.doValidate = async function doValidate(value, scope, option
|
|
|
1359
1359
|
let ok;
|
|
1360
1360
|
|
|
1361
1361
|
const validatorProperties = isSimpleValidator(v) ? Object.assign({}, v) : clone(v);
|
|
1362
|
-
validatorProperties.path = options
|
|
1362
|
+
validatorProperties.path = options?.path || path;
|
|
1363
1363
|
validatorProperties.fullPath = this.$fullPath;
|
|
1364
1364
|
validatorProperties.value = value;
|
|
1365
1365
|
if (typeof value === 'string') {
|
|
@@ -1399,7 +1399,7 @@ SchemaType.prototype.doValidate = async function doValidate(value, scope, option
|
|
|
1399
1399
|
}
|
|
1400
1400
|
}
|
|
1401
1401
|
|
|
1402
|
-
if (
|
|
1402
|
+
if (typeof ok?.then === 'function') {
|
|
1403
1403
|
promises.push(
|
|
1404
1404
|
ok.then(
|
|
1405
1405
|
function(ok) {
|
|
@@ -1485,7 +1485,7 @@ SchemaType.prototype.doValidateSync = function(value, scope, options) {
|
|
|
1485
1485
|
|
|
1486
1486
|
const validator = v.validator;
|
|
1487
1487
|
const validatorProperties = isSimpleValidator(v) ? Object.assign({}, v) : clone(v);
|
|
1488
|
-
validatorProperties.path = options
|
|
1488
|
+
validatorProperties.path = options?.path || path;
|
|
1489
1489
|
validatorProperties.fullPath = this.$fullPath;
|
|
1490
1490
|
validatorProperties.value = value;
|
|
1491
1491
|
if (typeof value === 'string') {
|
|
@@ -1524,7 +1524,7 @@ SchemaType.prototype.doValidateSync = function(value, scope, options) {
|
|
|
1524
1524
|
|
|
1525
1525
|
// Skip any validators that return a promise, we can't handle those
|
|
1526
1526
|
// synchronously
|
|
1527
|
-
if (
|
|
1527
|
+
if (typeof ok?.then === 'function') {
|
|
1528
1528
|
continue;
|
|
1529
1529
|
}
|
|
1530
1530
|
err = _validate(ok, validatorProperties);
|
|
@@ -1549,9 +1549,9 @@ SchemaType.prototype.doValidateSync = function(value, scope, options) {
|
|
|
1549
1549
|
|
|
1550
1550
|
SchemaType._isRef = function(self, value, doc, init) {
|
|
1551
1551
|
// fast path
|
|
1552
|
-
let ref = init &&
|
|
1552
|
+
let ref = init && (self.options?.ref || self.options?.refPath);
|
|
1553
1553
|
|
|
1554
|
-
if (!ref && doc
|
|
1554
|
+
if (!ref && doc?.$__ != null) {
|
|
1555
1555
|
// checks for
|
|
1556
1556
|
// - this populated with adhoc model and no ref was set in schema OR
|
|
1557
1557
|
// - setting / pushing values after population
|
package/lib/types/array/index.js
CHANGED
|
@@ -72,7 +72,7 @@ function MongooseArray(values, path, doc, schematype) {
|
|
|
72
72
|
internals[arrayAtomicsSymbol] = values[arrayAtomicsSymbol];
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
if (doc
|
|
75
|
+
if (doc?.$__) {
|
|
76
76
|
internals[arrayParentSymbol] = doc;
|
|
77
77
|
internals[arraySchemaSymbol] = schematype || doc.schema.path(path);
|
|
78
78
|
}
|
|
@@ -85,7 +85,7 @@ function MongooseArray(values, path, doc, schematype) {
|
|
|
85
85
|
if (Object.hasOwn(mongooseArrayMethods, prop)) {
|
|
86
86
|
return mongooseArrayMethods[prop];
|
|
87
87
|
}
|
|
88
|
-
if (schematype
|
|
88
|
+
if (schematype?.virtuals && Object.hasOwn(schematype.virtuals, prop)) {
|
|
89
89
|
return schematype.virtuals[prop].applyGetters(undefined, target);
|
|
90
90
|
}
|
|
91
91
|
if (typeof prop === 'string' && numberRE.test(prop) && schematype?.embeddedSchemaType != null) {
|
|
@@ -10,6 +10,7 @@ const mpath = require('mpath');
|
|
|
10
10
|
const utils = require('../../../utils');
|
|
11
11
|
const isBsonType = require('../../../helpers/isBsonType');
|
|
12
12
|
|
|
13
|
+
const arrayAtomicsBackupSymbol = require('../../../helpers/symbols').arrayAtomicsBackupSymbol;
|
|
13
14
|
const arrayAtomicsSymbol = require('../../../helpers/symbols').arrayAtomicsSymbol;
|
|
14
15
|
const arrayParentSymbol = require('../../../helpers/symbols').arrayParentSymbol;
|
|
15
16
|
const arrayPathSymbol = require('../../../helpers/symbols').arrayPathSymbol;
|
|
@@ -59,9 +60,9 @@ const methods = {
|
|
|
59
60
|
val = val.toObject(opts);
|
|
60
61
|
} else if (Array.isArray(val)) {
|
|
61
62
|
val = this.toObject.call(val, opts);
|
|
62
|
-
} else if (
|
|
63
|
+
} else if (Array.isArray(val?.$each)) {
|
|
63
64
|
val.$each = this.toObject.call(val.$each, opts);
|
|
64
|
-
} else if (
|
|
65
|
+
} else if (typeof val?.valueOf === 'function') {
|
|
65
66
|
val = val.valueOf();
|
|
66
67
|
}
|
|
67
68
|
|
|
@@ -75,6 +76,36 @@ const methods = {
|
|
|
75
76
|
return ret;
|
|
76
77
|
},
|
|
77
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Public API for getting atomics. Alias for $__getAtomics() that can be
|
|
81
|
+
* implemented by custom container types.
|
|
82
|
+
*
|
|
83
|
+
* @return {Array}
|
|
84
|
+
* @method getAtomics
|
|
85
|
+
* @memberOf MongooseArray
|
|
86
|
+
* @instance
|
|
87
|
+
* @api public
|
|
88
|
+
*/
|
|
89
|
+
|
|
90
|
+
getAtomics() {
|
|
91
|
+
return this.$__getAtomics();
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Clears all pending atomic operations. Called by Mongoose after save().
|
|
96
|
+
*
|
|
97
|
+
* @return {void}
|
|
98
|
+
* @method clearAtomics
|
|
99
|
+
* @memberOf MongooseArray
|
|
100
|
+
* @instance
|
|
101
|
+
* @api public
|
|
102
|
+
*/
|
|
103
|
+
|
|
104
|
+
clearAtomics() {
|
|
105
|
+
this[arrayAtomicsBackupSymbol] = this[arrayAtomicsSymbol];
|
|
106
|
+
this[arrayAtomicsSymbol] = {};
|
|
107
|
+
},
|
|
108
|
+
|
|
78
109
|
/*!
|
|
79
110
|
* ignore
|
|
80
111
|
*/
|
|
@@ -230,7 +261,7 @@ const methods = {
|
|
|
230
261
|
populated = parent.$populated(this[arrayPathSymbol], true);
|
|
231
262
|
}
|
|
232
263
|
|
|
233
|
-
if (populated && value
|
|
264
|
+
if (populated && value != null) {
|
|
234
265
|
// cast to the populated Models schema
|
|
235
266
|
Model = populated.options[populateModelSymbol];
|
|
236
267
|
if (Model == null) {
|
|
@@ -246,8 +277,7 @@ const methods = {
|
|
|
246
277
|
|
|
247
278
|
// gh-2399
|
|
248
279
|
// we should cast model only when it's not a discriminator
|
|
249
|
-
const isDisc = value.schema
|
|
250
|
-
value.schema.discriminatorMapping.key !== undefined;
|
|
280
|
+
const isDisc = value.schema?.discriminatorMapping?.key !== undefined;
|
|
251
281
|
if (!isDisc) {
|
|
252
282
|
value = new Model(value);
|
|
253
283
|
}
|
|
@@ -338,7 +368,7 @@ const methods = {
|
|
|
338
368
|
|
|
339
369
|
// check for impossible $atomic combos (Mongo denies more than one
|
|
340
370
|
// $atomic op on a single path
|
|
341
|
-
if (atomics.$set ||
|
|
371
|
+
if (atomics.$set || utils.hasOwnKeys(atomics) && !(op in atomics)) {
|
|
342
372
|
// a different op was previously registered.
|
|
343
373
|
// save the entire thing.
|
|
344
374
|
this[arrayAtomicsSymbol] = { $set: this };
|
|
@@ -895,7 +925,7 @@ const methods = {
|
|
|
895
925
|
|
|
896
926
|
toObject(options) {
|
|
897
927
|
const arr = utils.isMongooseArray(this) ? this.__array : this;
|
|
898
|
-
if (options
|
|
928
|
+
if (options?.depopulate) {
|
|
899
929
|
options = clone(options);
|
|
900
930
|
options._isNested = true;
|
|
901
931
|
// Ensure return value is a vanilla array, because in Node.js 6+ `map()`
|
|
@@ -995,7 +1025,7 @@ function _minimizePath(obj, parts, i) {
|
|
|
995
1025
|
}
|
|
996
1026
|
|
|
997
1027
|
_minimizePath(obj[parts[0]], parts, i + 1);
|
|
998
|
-
if (obj[parts[0]] != null && typeof obj[parts[0]] === 'object' &&
|
|
1028
|
+
if (obj[parts[0]] != null && typeof obj[parts[0]] === 'object' && utils.hasOwnKeys(obj[parts[0]]) === false) {
|
|
999
1029
|
delete obj[parts[0]];
|
|
1000
1030
|
}
|
|
1001
1031
|
}
|