mongoose 8.20.1 → 8.20.3
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/aggregate.js +1 -1
- package/lib/cast.js +1 -1
- package/lib/connection.js +9 -9
- package/lib/document.js +58 -17
- package/lib/drivers/node-mongodb-native/connection.js +2 -2
- package/lib/error/objectParameter.js +1 -1
- package/lib/helpers/common.js +1 -1
- package/lib/helpers/indexes/applySchemaCollation.js +1 -1
- package/lib/helpers/indexes/isDefaultIdIndex.js +1 -1
- package/lib/helpers/model/applyMethods.js +1 -1
- package/lib/helpers/model/castBulkWrite.js +13 -6
- package/lib/helpers/populate/getModelsMapForPopulate.js +3 -3
- package/lib/helpers/populate/modelNamesFromRefPath.js +1 -1
- package/lib/helpers/populate/removeDeselectedForeignField.js +1 -1
- package/lib/helpers/projection/applyProjection.js +2 -2
- package/lib/helpers/query/getEmbeddedDiscriminatorPath.js +1 -1
- package/lib/helpers/setDefaultsOnInsert.js +2 -2
- package/lib/helpers/timestamps/setupTimestamps.js +1 -1
- package/lib/helpers/update/applyTimestampsToUpdate.js +38 -25
- package/lib/helpers/update/decorateUpdateWithVersionKey.js +1 -1
- package/lib/model.js +12 -15
- package/lib/mongoose.js +3 -4
- package/lib/query.js +3 -3
- package/lib/schema/array.js +1 -1
- package/lib/schema.js +21 -21
- package/lib/schemaType.js +8 -8
- package/lib/types/array/index.js +5 -5
- package/lib/types/documentArray/index.js +6 -6
- package/lib/types/objectid.js +1 -1
- package/lib/utils.js +1 -15
- package/lib/virtualType.js +1 -1
- package/package.json +3 -1
- package/types/index.d.ts +1 -1
- package/types/inferrawdoctype.d.ts +1 -1
- package/types/inferschematype.d.ts +16 -23
- package/types/models.d.ts +38 -85
- package/types/virtuals.d.ts +3 -3
package/lib/aggregate.js
CHANGED
|
@@ -103,7 +103,7 @@ Aggregate.prototype._optionsForExec = function() {
|
|
|
103
103
|
const options = this.options || {};
|
|
104
104
|
|
|
105
105
|
const asyncLocalStorage = this.model()?.db?.base.transactionAsyncLocalStorage?.getStore();
|
|
106
|
-
if (!
|
|
106
|
+
if (!Object.hasOwn(options, 'session') && asyncLocalStorage?.session != null) {
|
|
107
107
|
options.session = asyncLocalStorage.session;
|
|
108
108
|
}
|
|
109
109
|
|
package/lib/cast.js
CHANGED
|
@@ -107,7 +107,7 @@ module.exports = function cast(schema, obj, options, context) {
|
|
|
107
107
|
val = cast(schema, val, options, context);
|
|
108
108
|
} else if (path === '$text') {
|
|
109
109
|
val = castTextSearch(val, path);
|
|
110
|
-
} else if (path === '$comment' && !schema.paths
|
|
110
|
+
} else if (path === '$comment' && !Object.hasOwn(schema.paths, '$comment')) {
|
|
111
111
|
val = castString(val, path);
|
|
112
112
|
obj[path] = val;
|
|
113
113
|
} else {
|
package/lib/connection.js
CHANGED
|
@@ -164,7 +164,7 @@ Object.defineProperty(Connection.prototype, 'readyState', {
|
|
|
164
164
|
*/
|
|
165
165
|
|
|
166
166
|
Connection.prototype.get = function getOption(key) {
|
|
167
|
-
if (this.config
|
|
167
|
+
if (Object.hasOwn(this.config, key)) {
|
|
168
168
|
return this.config[key];
|
|
169
169
|
}
|
|
170
170
|
|
|
@@ -192,7 +192,7 @@ Connection.prototype.get = function getOption(key) {
|
|
|
192
192
|
*/
|
|
193
193
|
|
|
194
194
|
Connection.prototype.set = function setOption(key, val) {
|
|
195
|
-
if (this.config
|
|
195
|
+
if (Object.hasOwn(this.config, key)) {
|
|
196
196
|
this.config[key] = val;
|
|
197
197
|
return val;
|
|
198
198
|
}
|
|
@@ -459,7 +459,7 @@ Connection.prototype.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
459
459
|
|
|
460
460
|
const ordered = options.ordered == null ? true : options.ordered;
|
|
461
461
|
const asyncLocalStorage = this.base.transactionAsyncLocalStorage?.getStore();
|
|
462
|
-
if ((!options || !
|
|
462
|
+
if ((!options || !Object.hasOwn(options, 'session')) && asyncLocalStorage?.session != null) {
|
|
463
463
|
options = { ...options, session: asyncLocalStorage.session };
|
|
464
464
|
}
|
|
465
465
|
|
|
@@ -477,7 +477,7 @@ Connection.prototype.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
477
477
|
if (op.name == null) {
|
|
478
478
|
throw new MongooseError('Must specify operation name in Connection.prototype.bulkWrite()');
|
|
479
479
|
}
|
|
480
|
-
if (!castBulkWrite.cast
|
|
480
|
+
if (!Object.hasOwn(castBulkWrite.cast, op.name)) {
|
|
481
481
|
throw new MongooseError(`Unrecognized bulkWrite() operation name ${op.name}`);
|
|
482
482
|
}
|
|
483
483
|
|
|
@@ -513,7 +513,7 @@ Connection.prototype.bulkWrite = async function bulkWrite(ops, options) {
|
|
|
513
513
|
results[i] = error;
|
|
514
514
|
continue;
|
|
515
515
|
}
|
|
516
|
-
if (!castBulkWrite.cast
|
|
516
|
+
if (!Object.hasOwn(castBulkWrite.cast, op.name)) {
|
|
517
517
|
const error = new MongooseError(`Unrecognized bulkWrite() operation name ${op.name}`);
|
|
518
518
|
validationErrors.push({ index: i, error: error });
|
|
519
519
|
results[i] = error;
|
|
@@ -772,10 +772,10 @@ async function _wrapUserTransaction(fn, session, mongoose) {
|
|
|
772
772
|
function _resetSessionDocuments(session) {
|
|
773
773
|
for (const doc of session[sessionNewDocuments].keys()) {
|
|
774
774
|
const state = session[sessionNewDocuments].get(doc);
|
|
775
|
-
if (
|
|
775
|
+
if (Object.hasOwn(state, 'isNew')) {
|
|
776
776
|
doc.$isNew = state.isNew;
|
|
777
777
|
}
|
|
778
|
-
if (
|
|
778
|
+
if (Object.hasOwn(state, 'versionKey')) {
|
|
779
779
|
doc.set(doc.schema.options.versionKey, state.versionKey);
|
|
780
780
|
}
|
|
781
781
|
|
|
@@ -1013,7 +1013,7 @@ Connection.prototype.onOpen = function() {
|
|
|
1013
1013
|
// avoid having the collection subscribe to our event emitter
|
|
1014
1014
|
// to prevent 0.3 warning
|
|
1015
1015
|
for (const i in this.collections) {
|
|
1016
|
-
if (
|
|
1016
|
+
if (Object.hasOwn(this.collections, i)) {
|
|
1017
1017
|
this.collections[i].onOpen();
|
|
1018
1018
|
}
|
|
1019
1019
|
}
|
|
@@ -1321,7 +1321,7 @@ Connection.prototype.onClose = function onClose(force) {
|
|
|
1321
1321
|
// avoid having the collection subscribe to our event emitter
|
|
1322
1322
|
// to prevent 0.3 warning
|
|
1323
1323
|
for (const i in this.collections) {
|
|
1324
|
-
if (
|
|
1324
|
+
if (Object.hasOwn(this.collections, i)) {
|
|
1325
1325
|
this.collections[i].onClose(force);
|
|
1326
1326
|
}
|
|
1327
1327
|
}
|
package/lib/document.js
CHANGED
|
@@ -648,6 +648,10 @@ Document.prototype.init = function(doc, opts, fn) {
|
|
|
648
648
|
opts = null;
|
|
649
649
|
}
|
|
650
650
|
|
|
651
|
+
if (doc == null) {
|
|
652
|
+
throw new ObjectParameterError(doc, 'doc', 'init');
|
|
653
|
+
}
|
|
654
|
+
|
|
651
655
|
this.$__init(doc, opts);
|
|
652
656
|
|
|
653
657
|
if (fn) {
|
|
@@ -780,7 +784,7 @@ function init(self, obj, doc, opts, prefix) {
|
|
|
780
784
|
}
|
|
781
785
|
} else {
|
|
782
786
|
// Retain order when overwriting defaults
|
|
783
|
-
if (
|
|
787
|
+
if (Object.hasOwn(doc, i) && value !== void 0 && !opts.hydratedPopulatedDocs) {
|
|
784
788
|
delete doc[i];
|
|
785
789
|
}
|
|
786
790
|
if (value === null) {
|
|
@@ -1156,7 +1160,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1156
1160
|
const orderedKeys = Object.keys(this.$__schema.tree);
|
|
1157
1161
|
for (let i = 0, len = orderedKeys.length; i < len; ++i) {
|
|
1158
1162
|
(key = orderedKeys[i]) &&
|
|
1159
|
-
(this._doc
|
|
1163
|
+
(Object.hasOwn(this._doc, key)) &&
|
|
1160
1164
|
(orderedDoc[key] = undefined);
|
|
1161
1165
|
}
|
|
1162
1166
|
this._doc = Object.assign(orderedDoc, this._doc);
|
|
@@ -1206,8 +1210,8 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1206
1210
|
return this;
|
|
1207
1211
|
}
|
|
1208
1212
|
const wasModified = this.$isModified(path);
|
|
1209
|
-
const hasInitialVal = this.$__.savedState != null && this.$__.savedState
|
|
1210
|
-
if (this.$__.savedState != null && !this.$isNew && !this.$__.savedState
|
|
1213
|
+
const hasInitialVal = this.$__.savedState != null && Object.hasOwn(this.$__.savedState, path);
|
|
1214
|
+
if (this.$__.savedState != null && !this.$isNew && !Object.hasOwn(this.$__.savedState, path)) {
|
|
1211
1215
|
const initialVal = this.$__getValue(path);
|
|
1212
1216
|
this.$__.savedState[path] = initialVal;
|
|
1213
1217
|
|
|
@@ -1512,7 +1516,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1512
1516
|
this.$__.session[sessionNewDocuments].get(this).modifiedPaths &&
|
|
1513
1517
|
!this.$__.session[sessionNewDocuments].get(this).modifiedPaths.has(savedStatePath);
|
|
1514
1518
|
if (savedState != null &&
|
|
1515
|
-
|
|
1519
|
+
Object.hasOwn(savedState, savedStatePath) &&
|
|
1516
1520
|
(!isInTransaction || isModifiedWithinTransaction) &&
|
|
1517
1521
|
utils.deepEqual(val, savedState[savedStatePath])) {
|
|
1518
1522
|
this.unmarkModified(path);
|
|
@@ -1994,7 +1998,7 @@ Document.prototype.$get = Document.prototype.get;
|
|
|
1994
1998
|
|
|
1995
1999
|
Document.prototype.$__path = function(path) {
|
|
1996
2000
|
const adhocs = this.$__.adhocPaths;
|
|
1997
|
-
const adhocType = adhocs &&
|
|
2001
|
+
const adhocType = adhocs && Object.hasOwn(adhocs, path) ? adhocs[path] : null;
|
|
1998
2002
|
|
|
1999
2003
|
if (adhocType) {
|
|
2000
2004
|
return adhocType;
|
|
@@ -2038,7 +2042,7 @@ Document.prototype.$__saveInitialState = function $__saveInitialState(path) {
|
|
|
2038
2042
|
if (savedState != null) {
|
|
2039
2043
|
const firstDot = savedStatePath.indexOf('.');
|
|
2040
2044
|
const topLevelPath = firstDot === -1 ? savedStatePath : savedStatePath.slice(0, firstDot);
|
|
2041
|
-
if (!
|
|
2045
|
+
if (!Object.hasOwn(savedState, topLevelPath)) {
|
|
2042
2046
|
savedState[topLevelPath] = clone(this.$__getValue(topLevelPath));
|
|
2043
2047
|
}
|
|
2044
2048
|
}
|
|
@@ -2349,7 +2353,7 @@ Document.prototype.$isDefault = function(path) {
|
|
|
2349
2353
|
}
|
|
2350
2354
|
|
|
2351
2355
|
if (typeof path === 'string' && path.indexOf(' ') === -1) {
|
|
2352
|
-
return this.$__.activePaths.getStatePaths('default')
|
|
2356
|
+
return Object.hasOwn(this.$__.activePaths.getStatePaths('default'), path);
|
|
2353
2357
|
}
|
|
2354
2358
|
|
|
2355
2359
|
let paths = path;
|
|
@@ -2357,7 +2361,7 @@ Document.prototype.$isDefault = function(path) {
|
|
|
2357
2361
|
paths = paths.split(' ');
|
|
2358
2362
|
}
|
|
2359
2363
|
|
|
2360
|
-
return paths.some(path => this.$__.activePaths.getStatePaths('default')
|
|
2364
|
+
return paths.some(path => Object.hasOwn(this.$__.activePaths.getStatePaths('default'), path));
|
|
2361
2365
|
};
|
|
2362
2366
|
|
|
2363
2367
|
/**
|
|
@@ -2411,7 +2415,7 @@ Document.prototype.isDirectModified = function(path) {
|
|
|
2411
2415
|
}
|
|
2412
2416
|
|
|
2413
2417
|
if (typeof path === 'string' && path.indexOf(' ') === -1) {
|
|
2414
|
-
const res = this.$__.activePaths.getStatePaths('modify')
|
|
2418
|
+
const res = Object.hasOwn(this.$__.activePaths.getStatePaths('modify'), path);
|
|
2415
2419
|
if (res || path.indexOf('.') === -1) {
|
|
2416
2420
|
return res;
|
|
2417
2421
|
}
|
|
@@ -2450,7 +2454,7 @@ Document.prototype.isInit = function(path) {
|
|
|
2450
2454
|
}
|
|
2451
2455
|
|
|
2452
2456
|
if (typeof path === 'string' && path.indexOf(' ') === -1) {
|
|
2453
|
-
return this.$__.activePaths.getStatePaths('init')
|
|
2457
|
+
return Object.hasOwn(this.$__.activePaths.getStatePaths('init'), path);
|
|
2454
2458
|
}
|
|
2455
2459
|
|
|
2456
2460
|
let paths = path;
|
|
@@ -2458,7 +2462,7 @@ Document.prototype.isInit = function(path) {
|
|
|
2458
2462
|
paths = paths.split(' ');
|
|
2459
2463
|
}
|
|
2460
2464
|
|
|
2461
|
-
return paths.some(path => this.$__.activePaths.getStatePaths('init')
|
|
2465
|
+
return paths.some(path => Object.hasOwn(this.$__.activePaths.getStatePaths('init'), path));
|
|
2462
2466
|
};
|
|
2463
2467
|
|
|
2464
2468
|
/**
|
|
@@ -2596,7 +2600,7 @@ Document.prototype.isDirectSelected = function isDirectSelected(path) {
|
|
|
2596
2600
|
return true;
|
|
2597
2601
|
}
|
|
2598
2602
|
|
|
2599
|
-
if (this.$__.selected
|
|
2603
|
+
if (Object.hasOwn(this.$__.selected, path)) {
|
|
2600
2604
|
return inclusive;
|
|
2601
2605
|
}
|
|
2602
2606
|
|
|
@@ -2772,7 +2776,7 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate
|
|
|
2772
2776
|
if (doc.$isModified(fullPathToSubdoc, null, modifiedPaths) &&
|
|
2773
2777
|
// Avoid using isDirectModified() here because that does additional checks on whether the parent path
|
|
2774
2778
|
// is direct modified, which can cause performance issues re: gh-14897
|
|
2775
|
-
!subdocParent.$__.activePaths.getStatePaths('modify')
|
|
2779
|
+
!Object.hasOwn(subdocParent.$__.activePaths.getStatePaths('modify'), fullPathToSubdoc) &&
|
|
2776
2780
|
!subdocParent.$isDefault(fullPathToSubdoc)) {
|
|
2777
2781
|
paths.add(fullPathToSubdoc);
|
|
2778
2782
|
|
|
@@ -2843,7 +2847,12 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate
|
|
|
2843
2847
|
// Single nested paths (paths embedded under single nested subdocs) will
|
|
2844
2848
|
// be validated on their own when we call `validate()` on the subdoc itself.
|
|
2845
2849
|
// Re: gh-8468
|
|
2846
|
-
|
|
2850
|
+
const singleNestedPaths = doc.$__schema.singleNestedPaths;
|
|
2851
|
+
for (const path of Object.keys(flat)) {
|
|
2852
|
+
if (!Object.hasOwn(singleNestedPaths, path)) {
|
|
2853
|
+
addToPaths(path);
|
|
2854
|
+
}
|
|
2855
|
+
}
|
|
2847
2856
|
}
|
|
2848
2857
|
}
|
|
2849
2858
|
|
|
@@ -4184,7 +4193,7 @@ function applyVirtuals(self, json, options, toObjectOptions) {
|
|
|
4184
4193
|
}
|
|
4185
4194
|
|
|
4186
4195
|
// Allow skipping aliases with `toObject({ virtuals: true, aliases: false })`
|
|
4187
|
-
if (!aliases && schema.aliases
|
|
4196
|
+
if (!aliases && Object.hasOwn(schema.aliases, path)) {
|
|
4188
4197
|
continue;
|
|
4189
4198
|
}
|
|
4190
4199
|
|
|
@@ -5097,7 +5106,7 @@ function checkDivergentArray(doc, path, array) {
|
|
|
5097
5106
|
// would be similarly destructive as we never received all
|
|
5098
5107
|
// elements of the array and potentially would overwrite data.
|
|
5099
5108
|
const check = pop.options.match ||
|
|
5100
|
-
pop.options.options &&
|
|
5109
|
+
pop.options.options && Object.hasOwn(pop.options.options, 'limit') || // 0 is not permitted
|
|
5101
5110
|
pop.options.options && pop.options.options.skip || // 0 is permitted
|
|
5102
5111
|
pop.options.select && // deselected _id?
|
|
5103
5112
|
(pop.options.select._id === 0 ||
|
|
@@ -5422,6 +5431,38 @@ Document.prototype.$__hasOnlyPrimitiveValues = function $__hasOnlyPrimitiveValue
|
|
|
5422
5431
|
}));
|
|
5423
5432
|
};
|
|
5424
5433
|
|
|
5434
|
+
/*!
|
|
5435
|
+
* Increment this document's version if necessary.
|
|
5436
|
+
*/
|
|
5437
|
+
|
|
5438
|
+
Document.prototype._applyVersionIncrement = function _applyVersionIncrement() {
|
|
5439
|
+
if (!this.$__.version) return;
|
|
5440
|
+
const doIncrement = VERSION_INC === (VERSION_INC & this.$__.version);
|
|
5441
|
+
|
|
5442
|
+
this.$__.version = undefined;
|
|
5443
|
+
if (doIncrement) {
|
|
5444
|
+
const key = this.$__schema.options.versionKey;
|
|
5445
|
+
const version = this.$__getValue(key) || 0;
|
|
5446
|
+
this.$__setValue(key, version + 1); // increment version if was successful
|
|
5447
|
+
}
|
|
5448
|
+
};
|
|
5449
|
+
|
|
5450
|
+
/*!
|
|
5451
|
+
* Increment this document's version if necessary.
|
|
5452
|
+
*/
|
|
5453
|
+
|
|
5454
|
+
Document.prototype._applyVersionIncrement = function _applyVersionIncrement() {
|
|
5455
|
+
if (!this.$__.version) return;
|
|
5456
|
+
const doIncrement = VERSION_INC === (VERSION_INC & this.$__.version);
|
|
5457
|
+
|
|
5458
|
+
this.$__.version = undefined;
|
|
5459
|
+
if (doIncrement) {
|
|
5460
|
+
const key = this.$__schema.options.versionKey;
|
|
5461
|
+
const version = this.$__getValue(key) || 0;
|
|
5462
|
+
this.$__setValue(key, version + 1); // increment version if was successful
|
|
5463
|
+
}
|
|
5464
|
+
};
|
|
5465
|
+
|
|
5425
5466
|
/*!
|
|
5426
5467
|
* Module exports.
|
|
5427
5468
|
*/
|
|
@@ -108,7 +108,7 @@ NativeConnection.prototype.useDb = function(name, options) {
|
|
|
108
108
|
function wireup() {
|
|
109
109
|
newConn.client = _this.client;
|
|
110
110
|
const _opts = {};
|
|
111
|
-
if (
|
|
111
|
+
if (Object.hasOwn(options, 'noListener')) {
|
|
112
112
|
_opts.noListener = options.noListener;
|
|
113
113
|
}
|
|
114
114
|
newConn.db = _this.client.db(name, _opts);
|
|
@@ -515,7 +515,7 @@ function _setClient(conn, client, options, dbName) {
|
|
|
515
515
|
conn.onOpen();
|
|
516
516
|
|
|
517
517
|
for (const i in conn.collections) {
|
|
518
|
-
if (
|
|
518
|
+
if (Object.hasOwn(conn.collections, i)) {
|
|
519
519
|
conn.collections[i].onOpen();
|
|
520
520
|
}
|
|
521
521
|
}
|
|
@@ -20,7 +20,7 @@ class ObjectParameterError extends MongooseError {
|
|
|
20
20
|
|
|
21
21
|
constructor(value, paramName, fnName) {
|
|
22
22
|
super('Parameter "' + paramName + '" to ' + fnName +
|
|
23
|
-
'() must be an object, got "' + value
|
|
23
|
+
'() must be an object, got "' + (value?.toString() ?? (value + '')) + '" (type ' + typeof value + ')');
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
package/lib/helpers/common.js
CHANGED
|
@@ -55,7 +55,7 @@ function flatten(update, path, options, schema) {
|
|
|
55
55
|
if (isNested) {
|
|
56
56
|
const paths = Object.keys(schema.paths);
|
|
57
57
|
for (const p of paths) {
|
|
58
|
-
if (p.startsWith(path + key + '.') && !
|
|
58
|
+
if (p.startsWith(path + key + '.') && !Object.hasOwn(result, p)) {
|
|
59
59
|
result[p] = void 0;
|
|
60
60
|
}
|
|
61
61
|
}
|
|
@@ -7,7 +7,7 @@ module.exports = function applySchemaCollation(indexKeys, indexOptions, schemaOp
|
|
|
7
7
|
return;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
if (
|
|
10
|
+
if (Object.hasOwn(schemaOptions, 'collation') && !Object.hasOwn(indexOptions, 'collation')) {
|
|
11
11
|
indexOptions.collation = schemaOptions.collation;
|
|
12
12
|
}
|
|
13
13
|
};
|
|
@@ -28,7 +28,7 @@ module.exports = function applyMethods(model, schema) {
|
|
|
28
28
|
}
|
|
29
29
|
for (const method of Object.keys(schema.methods)) {
|
|
30
30
|
const fn = schema.methods[method];
|
|
31
|
-
if (schema.tree
|
|
31
|
+
if (Object.hasOwn(schema.tree, method)) {
|
|
32
32
|
throw new Error('You have a method and a property in your schema both ' +
|
|
33
33
|
'named "' + method + '"');
|
|
34
34
|
}
|
|
@@ -118,7 +118,10 @@ module.exports.castUpdateOne = function castUpdateOne(originalModel, updateOne,
|
|
|
118
118
|
if (model.schema.$timestamps != null && doInitTimestamps) {
|
|
119
119
|
const createdAt = model.schema.$timestamps.createdAt;
|
|
120
120
|
const updatedAt = model.schema.$timestamps.updatedAt;
|
|
121
|
-
applyTimestampsToUpdate(now, createdAt, updatedAt, update, {
|
|
121
|
+
applyTimestampsToUpdate(now, createdAt, updatedAt, update, {
|
|
122
|
+
timestamps: updateOne.timestamps,
|
|
123
|
+
overwriteImmutable: updateOne.overwriteImmutable
|
|
124
|
+
});
|
|
122
125
|
}
|
|
123
126
|
|
|
124
127
|
if (doInitTimestamps) {
|
|
@@ -150,7 +153,8 @@ module.exports.castUpdateOne = function castUpdateOne(originalModel, updateOne,
|
|
|
150
153
|
strict: strict,
|
|
151
154
|
upsert: updateOne.upsert,
|
|
152
155
|
arrayFilters: updateOne.arrayFilters,
|
|
153
|
-
overwriteDiscriminatorKey: updateOne.overwriteDiscriminatorKey
|
|
156
|
+
overwriteDiscriminatorKey: updateOne.overwriteDiscriminatorKey,
|
|
157
|
+
overwriteImmutable: updateOne.overwriteImmutable
|
|
154
158
|
}, model, updateOne['filter']);
|
|
155
159
|
|
|
156
160
|
return updateOne;
|
|
@@ -185,7 +189,10 @@ module.exports.castUpdateMany = function castUpdateMany(originalModel, updateMan
|
|
|
185
189
|
if (model.schema.$timestamps != null && doInitTimestamps) {
|
|
186
190
|
const createdAt = model.schema.$timestamps.createdAt;
|
|
187
191
|
const updatedAt = model.schema.$timestamps.updatedAt;
|
|
188
|
-
applyTimestampsToUpdate(now, createdAt, updatedAt, updateMany['update'], {
|
|
192
|
+
applyTimestampsToUpdate(now, createdAt, updatedAt, updateMany['update'], {
|
|
193
|
+
timestamps: updateMany.timestamps,
|
|
194
|
+
overwriteImmutable: updateMany.overwriteImmutable
|
|
195
|
+
});
|
|
189
196
|
}
|
|
190
197
|
if (doInitTimestamps) {
|
|
191
198
|
applyTimestampsToChildren(now, updateMany['update'], model.schema);
|
|
@@ -208,7 +215,8 @@ module.exports.castUpdateMany = function castUpdateMany(originalModel, updateMan
|
|
|
208
215
|
strict: strict,
|
|
209
216
|
upsert: updateMany.upsert,
|
|
210
217
|
arrayFilters: updateMany.arrayFilters,
|
|
211
|
-
overwriteDiscriminatorKey: updateMany.overwriteDiscriminatorKey
|
|
218
|
+
overwriteDiscriminatorKey: updateMany.overwriteDiscriminatorKey,
|
|
219
|
+
overwriteImmutable: updateMany.overwriteImmutable
|
|
212
220
|
}, model, updateMany['filter']);
|
|
213
221
|
};
|
|
214
222
|
|
|
@@ -289,13 +297,12 @@ function _addDiscriminatorToObject(schema, obj) {
|
|
|
289
297
|
|
|
290
298
|
function decideModelByObject(model, object) {
|
|
291
299
|
const discriminatorKey = model.schema.options.discriminatorKey;
|
|
292
|
-
if (object != null &&
|
|
300
|
+
if (object != null && Object.hasOwn(object, discriminatorKey)) {
|
|
293
301
|
model = getDiscriminatorByValue(model.discriminators, object[discriminatorKey]) || model;
|
|
294
302
|
}
|
|
295
303
|
return model;
|
|
296
304
|
}
|
|
297
305
|
|
|
298
|
-
|
|
299
306
|
/**
|
|
300
307
|
* gets timestamps option for a given operation. If the option is set within an individual operation, use it. Otherwise, use the global timestamps option configured in the `bulkWrite` options. Overall default is `true`.
|
|
301
308
|
* @api private
|
|
@@ -386,13 +386,13 @@ function _virtualPopulate(model, docs, options, _virtualRes) {
|
|
|
386
386
|
}
|
|
387
387
|
data.count = virtual.options.count;
|
|
388
388
|
|
|
389
|
-
if (virtual.options.skip != null && !
|
|
389
|
+
if (virtual.options.skip != null && !Object.hasOwn(options, 'skip')) {
|
|
390
390
|
options.skip = virtual.options.skip;
|
|
391
391
|
}
|
|
392
|
-
if (virtual.options.limit != null && !
|
|
392
|
+
if (virtual.options.limit != null && !Object.hasOwn(options, 'limit')) {
|
|
393
393
|
options.limit = virtual.options.limit;
|
|
394
394
|
}
|
|
395
|
-
if (virtual.options.perDocumentLimit != null && !
|
|
395
|
+
if (virtual.options.perDocumentLimit != null && !Object.hasOwn(options, 'perDocumentLimit')) {
|
|
396
396
|
options.perDocumentLimit = virtual.options.perDocumentLimit;
|
|
397
397
|
}
|
|
398
398
|
let foreignField = virtual.options.foreignField;
|
|
@@ -56,7 +56,7 @@ module.exports = function modelNamesFromRefPath(refPath, doc, populatedPath, mod
|
|
|
56
56
|
const refValue = mpath.get(refPath, doc, lookupLocalFields);
|
|
57
57
|
|
|
58
58
|
let modelNames;
|
|
59
|
-
if (modelSchema != null && modelSchema.virtuals
|
|
59
|
+
if (modelSchema != null && Object.hasOwn(modelSchema.virtuals, refPath)) {
|
|
60
60
|
modelNames = [modelSchema.virtuals[refPath].applyGetters(void 0, doc)];
|
|
61
61
|
} else {
|
|
62
62
|
modelNames = Array.isArray(refValue) ? refValue : [refValue];
|
|
@@ -16,7 +16,7 @@ module.exports = function removeDeselectedForeignField(foreignFields, options, d
|
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
18
|
for (const foreignField of foreignFields) {
|
|
19
|
-
if (!
|
|
19
|
+
if (!Object.hasOwn(projection, '-' + foreignField)) {
|
|
20
20
|
continue;
|
|
21
21
|
}
|
|
22
22
|
|
|
@@ -43,7 +43,7 @@ function applyExclusiveProjection(doc, projection, hasIncludedChildren, projecti
|
|
|
43
43
|
|
|
44
44
|
for (const key of Object.keys(ret)) {
|
|
45
45
|
const fullPath = prefix ? prefix + '.' + key : key;
|
|
46
|
-
if (
|
|
46
|
+
if (Object.hasOwn(projection, fullPath) || Object.hasOwn(projectionLimb, key)) {
|
|
47
47
|
if (isPOJO(projection[fullPath]) || isPOJO(projectionLimb[key])) {
|
|
48
48
|
ret[key] = applyExclusiveProjection(ret[key], projection, hasIncludedChildren, projectionLimb[key], fullPath);
|
|
49
49
|
} else {
|
|
@@ -68,7 +68,7 @@ function applyInclusiveProjection(doc, projection, hasIncludedChildren, projecti
|
|
|
68
68
|
|
|
69
69
|
for (const key of Object.keys(ret)) {
|
|
70
70
|
const fullPath = prefix ? prefix + '.' + key : key;
|
|
71
|
-
if (
|
|
71
|
+
if (Object.hasOwn(projection, fullPath) || Object.hasOwn(projectionLimb, key)) {
|
|
72
72
|
if (isPOJO(projection[fullPath]) || isPOJO(projectionLimb[key])) {
|
|
73
73
|
ret[key] = applyInclusiveProjection(ret[key], projection, hasIncludedChildren, projectionLimb[key], fullPath);
|
|
74
74
|
}
|
|
@@ -71,7 +71,7 @@ module.exports = function getEmbeddedDiscriminatorPath(schema, update, filter, p
|
|
|
71
71
|
const schemaKey = updatedPathsByFilter[filterKey] + '.' + key;
|
|
72
72
|
const arrayFilterKey = filterKey + '.' + key;
|
|
73
73
|
if (schemaKey === discriminatorFilterPath) {
|
|
74
|
-
const filter = arrayFilters.find(filter =>
|
|
74
|
+
const filter = arrayFilters.find(filter => Object.hasOwn(filter, arrayFilterKey));
|
|
75
75
|
if (filter != null) {
|
|
76
76
|
discriminatorKey = filter[arrayFilterKey];
|
|
77
77
|
}
|
|
@@ -136,14 +136,14 @@ function pathExistsInUpdate(update, targetPath, pathPieces) {
|
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
// Check exact match
|
|
139
|
-
if (
|
|
139
|
+
if (Object.hasOwn(update, targetPath)) {
|
|
140
140
|
return true;
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
// Check if any parent path exists
|
|
144
144
|
let cur = pathPieces[0];
|
|
145
145
|
for (let i = 1; i < pathPieces.length; ++i) {
|
|
146
|
-
if (
|
|
146
|
+
if (Object.hasOwn(update, cur)) {
|
|
147
147
|
return true;
|
|
148
148
|
}
|
|
149
149
|
cur += '.' + pathPieces[i];
|
|
@@ -23,7 +23,7 @@ module.exports = function setupTimestamps(schema, timestamps) {
|
|
|
23
23
|
}
|
|
24
24
|
const createdAt = handleTimestampOption(timestamps, 'createdAt');
|
|
25
25
|
const updatedAt = handleTimestampOption(timestamps, 'updatedAt');
|
|
26
|
-
const currentTime = timestamps != null &&
|
|
26
|
+
const currentTime = timestamps != null && Object.hasOwn(timestamps, 'currentTime') ?
|
|
27
27
|
timestamps.currentTime :
|
|
28
28
|
null;
|
|
29
29
|
const schemaAdditions = {};
|
|
@@ -74,39 +74,52 @@ function applyTimestampsToUpdate(now, createdAt, updatedAt, currentUpdate, optio
|
|
|
74
74
|
updates.$set[updatedAt] = now;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
if (
|
|
77
|
+
if (Object.hasOwn(updates, updatedAt)) {
|
|
78
78
|
delete updates[updatedAt];
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
if (!skipCreatedAt && createdAt) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
83
|
+
const overwriteImmutable = get(options, 'overwriteImmutable', false);
|
|
84
|
+
const hasUserCreatedAt = currentUpdate[createdAt] != null || currentUpdate?.$set[createdAt] != null;
|
|
85
|
+
|
|
86
|
+
// If overwriteImmutable is true and user provided createdAt, keep their value
|
|
87
|
+
if (overwriteImmutable && hasUserCreatedAt) {
|
|
88
|
+
// Move createdAt from top-level to $set if needed
|
|
89
|
+
if (currentUpdate[createdAt] != null) {
|
|
90
|
+
updates.$set[createdAt] = currentUpdate[createdAt];
|
|
91
|
+
delete currentUpdate[createdAt];
|
|
92
|
+
}
|
|
93
|
+
// User's value is already in $set, nothing more to do
|
|
94
|
+
} else {
|
|
95
|
+
if (currentUpdate[createdAt]) {
|
|
96
|
+
delete currentUpdate[createdAt];
|
|
97
|
+
}
|
|
98
|
+
if (currentUpdate.$set && currentUpdate.$set[createdAt]) {
|
|
99
|
+
delete currentUpdate.$set[createdAt];
|
|
100
|
+
}
|
|
101
|
+
let timestampSet = false;
|
|
102
|
+
if (createdAt.indexOf('.') !== -1) {
|
|
103
|
+
const pieces = createdAt.split('.');
|
|
104
|
+
for (let i = 1; i < pieces.length; ++i) {
|
|
105
|
+
const remnant = pieces.slice(-i).join('.');
|
|
106
|
+
const start = pieces.slice(0, -i).join('.');
|
|
107
|
+
if (currentUpdate[start] != null) {
|
|
108
|
+
currentUpdate[start][remnant] = now;
|
|
109
|
+
timestampSet = true;
|
|
110
|
+
break;
|
|
111
|
+
} else if (currentUpdate.$set && currentUpdate.$set[start]) {
|
|
112
|
+
currentUpdate.$set[start][remnant] = now;
|
|
113
|
+
timestampSet = true;
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
103
116
|
}
|
|
104
117
|
}
|
|
105
|
-
}
|
|
106
118
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
119
|
+
if (!timestampSet) {
|
|
120
|
+
updates.$setOnInsert = updates.$setOnInsert || {};
|
|
121
|
+
updates.$setOnInsert[createdAt] = now;
|
|
122
|
+
}
|
|
110
123
|
}
|
|
111
124
|
}
|
|
112
125
|
|