@depup/mongoose 9.3.3-depup.0 → 9.8.0-depup.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -9
- package/changes.json +3 -8
- package/eslint.config.mjs +4 -1
- package/lib/aggregate.js +54 -24
- package/lib/cast.js +1 -1
- package/lib/connection.js +20 -8
- package/lib/cursor/aggregationCursor.js +47 -16
- package/lib/cursor/queryCursor.js +23 -7
- package/lib/document.js +240 -105
- package/lib/drivers/node-mongodb-native/collection.js +47 -14
- package/lib/drivers/node-mongodb-native/connection.js +13 -0
- package/lib/error/cast.js +18 -9
- package/lib/error/divergentArray.js +1 -1
- package/lib/error/index.js +1 -1
- package/lib/error/messages.js +1 -0
- package/lib/helpers/clone.js +22 -5
- package/lib/helpers/document/applyDefaults.js +5 -0
- package/lib/helpers/populate/createPopulateQueryFilter.js +9 -1
- package/lib/helpers/populate/getModelsMapForPopulate.js +8 -6
- package/lib/helpers/populate/splitPopulateQuery.js +81 -0
- package/lib/helpers/query/castUpdate.js +4 -0
- package/lib/helpers/schema/getKeysInSchemaOrder.js +13 -16
- package/lib/helpers/update/applyTimestampsToUpdate.js +4 -2
- package/lib/model.js +159 -41
- package/lib/mongoose.js +3 -3
- package/lib/options/schemaTypeOptions.js +14 -0
- package/lib/plugins/saveSubdocs.js +16 -13
- package/lib/query.js +208 -102
- package/lib/queryHelpers.js +13 -12
- package/lib/schema/array.js +4 -6
- package/lib/schema/bigint.js +1 -3
- package/lib/schema/boolean.js +1 -3
- package/lib/schema/buffer.js +1 -3
- package/lib/schema/date.js +8 -8
- package/lib/schema/decimal128.js +1 -3
- package/lib/schema/documentArray.js +3 -5
- package/lib/schema/double.js +1 -3
- package/lib/schema/int32.js +1 -3
- package/lib/schema/map.js +1 -4
- package/lib/schema/number.js +2 -4
- package/lib/schema/objectId.js +7 -3
- package/lib/schema/string.js +20 -5
- package/lib/schema/subdocument.js +2 -4
- package/lib/schema/union.js +50 -0
- package/lib/schema/uuid.js +1 -3
- package/lib/schema.js +40 -14
- package/lib/schemaType.js +93 -12
- package/lib/standardSchema/convertErrorToIssues.js +20 -0
- package/lib/stateMachine.js +11 -6
- package/lib/tracing.js +38 -0
- package/lib/types/array/methods/index.js +4 -4
- package/lib/types/documentArray/methods/index.js +117 -3
- package/lib/types/subdocument.js +4 -2
- package/lib/utils.js +12 -2
- package/lib/validOptions.js +1 -0
- package/package.json +30 -33
- package/{tstyche.config.json → tstyche.json} +2 -1
- package/types/augmentations.d.ts +2 -2
- package/types/document.d.ts +61 -7
- package/types/expressions.d.ts +16 -0
- package/types/index.d.ts +25 -7
- package/types/inferhydrateddoctype.d.ts +1 -1
- package/types/inferrawdoctype.d.ts +6 -3
- package/types/inferschematype.d.ts +10 -2
- package/types/models.d.ts +30 -13
- package/types/mongooseoptions.d.ts +9 -1
- package/types/populate.d.ts +52 -0
- package/types/query.d.ts +39 -12
- package/types/schemaoptions.d.ts +5 -0
- package/types/schematypes.d.ts +10 -0
- package/types/tracing.d.ts +10 -0
- package/types/utility.d.ts +11 -2
- package/lib/helpers/createJSONSchemaTypeDefinition.js +0 -24
package/lib/schemaType.js
CHANGED
|
@@ -181,6 +181,40 @@ SchemaType.prototype.toJSON = function toJSON() {
|
|
|
181
181
|
return res;
|
|
182
182
|
};
|
|
183
183
|
|
|
184
|
+
/**
|
|
185
|
+
* Helper for creating `{ type: 'object' }` vs `{ bsonType: 'object' }` vs nullable variants.
|
|
186
|
+
*
|
|
187
|
+
* @param {string} type
|
|
188
|
+
* @param {string} bsonType
|
|
189
|
+
* @param {object} [options]
|
|
190
|
+
* @param {boolean} [options.useBsonType=false]
|
|
191
|
+
* @param {boolean} [options._defaultRequired=false]
|
|
192
|
+
* @param {boolean} [options._overrideRequired]
|
|
193
|
+
* @returns {object}
|
|
194
|
+
* @api private
|
|
195
|
+
*/
|
|
196
|
+
|
|
197
|
+
SchemaType.prototype._createJSONSchemaTypeDefinition = function _createJSONSchemaTypeDefinition(type, bsonType, options) {
|
|
198
|
+
const useBsonType = options?.useBsonType;
|
|
199
|
+
const isRequired = options?._overrideRequired ??
|
|
200
|
+
(this.options.required == null ?
|
|
201
|
+
(options?._defaultRequired === true || this.path === '_id') :
|
|
202
|
+
this.options.required && typeof this.options.required !== 'function');
|
|
203
|
+
const allowNull = this.options.allowNull !== false;
|
|
204
|
+
|
|
205
|
+
if (useBsonType) {
|
|
206
|
+
if (isRequired || !allowNull) {
|
|
207
|
+
return { bsonType };
|
|
208
|
+
}
|
|
209
|
+
return { bsonType: [bsonType, 'null'] };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (isRequired || !allowNull) {
|
|
213
|
+
return { type };
|
|
214
|
+
}
|
|
215
|
+
return { type: [type, 'null'] };
|
|
216
|
+
};
|
|
217
|
+
|
|
184
218
|
/**
|
|
185
219
|
* The validators that Mongoose should run to validate properties at this SchemaType's path.
|
|
186
220
|
*
|
|
@@ -380,10 +414,10 @@ SchemaType.get = function(getter) {
|
|
|
380
414
|
* #### Example:
|
|
381
415
|
*
|
|
382
416
|
* // values are cast:
|
|
383
|
-
* const schema = new Schema({
|
|
417
|
+
* const schema = new Schema({ num: { type: Number, default: 4.815162342 }})
|
|
384
418
|
* const M = db.model('M', schema)
|
|
385
419
|
* const m = new M;
|
|
386
|
-
* console.log(m.
|
|
420
|
+
* console.log(m.num) // 4.815162342
|
|
387
421
|
*
|
|
388
422
|
* // default unique objects for Mixed types:
|
|
389
423
|
* const schema = new Schema({ mixed: Schema.Types.Mixed });
|
|
@@ -786,7 +820,7 @@ SchemaType.prototype.set = function(fn) {
|
|
|
786
820
|
* // defining within the schema
|
|
787
821
|
* const s = new Schema({ born: { type: Date, get: dob })
|
|
788
822
|
*
|
|
789
|
-
* // or by
|
|
823
|
+
* // or by retrieving its SchemaType
|
|
790
824
|
* const s = new Schema({ born: Date })
|
|
791
825
|
* s.path('born').get(dob)
|
|
792
826
|
*
|
|
@@ -936,7 +970,7 @@ SchemaType.prototype.validateAll = function(validators) {
|
|
|
936
970
|
* }
|
|
937
971
|
* });
|
|
938
972
|
*
|
|
939
|
-
* You might use asynchronous validators to
|
|
973
|
+
* You might use asynchronous validators to retrieve other documents from the database to validate against or to meet other I/O bound validation needs.
|
|
940
974
|
*
|
|
941
975
|
* Validation occurs `pre('save')` or whenever you manually execute [document#validate](https://mongoosejs.com/docs/api/document.html#Document.prototype.validate()).
|
|
942
976
|
*
|
|
@@ -1109,6 +1143,12 @@ SchemaType.prototype.required = function(required, message) {
|
|
|
1109
1143
|
|
|
1110
1144
|
const _this = this;
|
|
1111
1145
|
this.isRequired = true;
|
|
1146
|
+
this.originalRequiredValue = required;
|
|
1147
|
+
|
|
1148
|
+
if (typeof this.originalRequiredValue !== 'function' &&
|
|
1149
|
+
(utils.hasUserDefinedProperty(this.options, 'allowNull') || this.allowNullValidator != null)) {
|
|
1150
|
+
throw new MongooseError('Path "' + this.path + '" may not have `allowNull` specified when `required` is true');
|
|
1151
|
+
}
|
|
1112
1152
|
|
|
1113
1153
|
this.requiredValidator = function(v) {
|
|
1114
1154
|
const cachedRequired = this?.$__?.cachedRequired;
|
|
@@ -1133,8 +1173,6 @@ SchemaType.prototype.required = function(required, message) {
|
|
|
1133
1173
|
|
|
1134
1174
|
return _this.checkRequired(v, this);
|
|
1135
1175
|
};
|
|
1136
|
-
this.originalRequiredValue = required;
|
|
1137
|
-
|
|
1138
1176
|
if (typeof required === 'string') {
|
|
1139
1177
|
message = required;
|
|
1140
1178
|
required = undefined;
|
|
@@ -1150,6 +1188,54 @@ SchemaType.prototype.required = function(required, message) {
|
|
|
1150
1188
|
return this;
|
|
1151
1189
|
};
|
|
1152
1190
|
|
|
1191
|
+
/**
|
|
1192
|
+
* Adds a validator that disallows `null` for this path without making the path
|
|
1193
|
+
* required. `undefined` values still pass validation.
|
|
1194
|
+
*
|
|
1195
|
+
* #### Example:
|
|
1196
|
+
*
|
|
1197
|
+
* const schema = new Schema({
|
|
1198
|
+
* name: { type: String, allowNull: false }
|
|
1199
|
+
* });
|
|
1200
|
+
*
|
|
1201
|
+
* new Model({}).validateSync(); // OK
|
|
1202
|
+
* new Model({ name: undefined }).validateSync(); // OK, Mongoose strips out `name` when its value is `undefined`
|
|
1203
|
+
* new Model({ name: null }).validateSync(); // ValidationError
|
|
1204
|
+
*
|
|
1205
|
+
* @param {boolean} allowNull
|
|
1206
|
+
* @return {SchemaType} this
|
|
1207
|
+
* @api public
|
|
1208
|
+
*/
|
|
1209
|
+
|
|
1210
|
+
SchemaType.prototype.allowNull = function(allowNull) {
|
|
1211
|
+
if (arguments.length > 0 && this.isRequired && typeof this.originalRequiredValue !== 'function') {
|
|
1212
|
+
throw new MongooseError('Path "' + this.path + '" may not have `allowNull` specified when `required` is true');
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
this.validators = this.validators.filter(function(v) {
|
|
1216
|
+
return v.validator !== this.allowNullValidator;
|
|
1217
|
+
}, this);
|
|
1218
|
+
|
|
1219
|
+
if (allowNull !== false) {
|
|
1220
|
+
delete this.options.allowNull;
|
|
1221
|
+
delete this.allowNullValidator;
|
|
1222
|
+
return this;
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
this.options.allowNull = false;
|
|
1226
|
+
this.allowNullValidator = function(v) {
|
|
1227
|
+
return v !== null;
|
|
1228
|
+
};
|
|
1229
|
+
|
|
1230
|
+
this.validators.push({
|
|
1231
|
+
validator: this.allowNullValidator,
|
|
1232
|
+
message: MongooseError.messages.general.allowNull,
|
|
1233
|
+
type: 'allowNull'
|
|
1234
|
+
});
|
|
1235
|
+
|
|
1236
|
+
return this;
|
|
1237
|
+
};
|
|
1238
|
+
|
|
1153
1239
|
/**
|
|
1154
1240
|
* Set the model that this path refers to. This is the option that [populate](https://mongoosejs.com/docs/populate.html)
|
|
1155
1241
|
* looks at to determine the foreign collection it should query.
|
|
@@ -1371,9 +1457,6 @@ SchemaType.prototype.doValidate = async function doValidate(value, scope, option
|
|
|
1371
1457
|
validatorProperties.value = value;
|
|
1372
1458
|
if (typeof value === 'string') {
|
|
1373
1459
|
validatorProperties.length = value.length;
|
|
1374
|
-
if (validatorProperties.value.length > 30) {
|
|
1375
|
-
validatorProperties.value = validatorProperties.value.slice(0, 30) + '...';
|
|
1376
|
-
}
|
|
1377
1460
|
}
|
|
1378
1461
|
|
|
1379
1462
|
if (value === undefined && validator !== this.requiredValidator) {
|
|
@@ -1497,9 +1580,6 @@ SchemaType.prototype.doValidateSync = function(value, scope, options) {
|
|
|
1497
1580
|
validatorProperties.value = value;
|
|
1498
1581
|
if (typeof value === 'string') {
|
|
1499
1582
|
validatorProperties.length = value.length;
|
|
1500
|
-
if (validatorProperties.value.length > 30) {
|
|
1501
|
-
validatorProperties.value = validatorProperties.value.slice(0, 30) + '...';
|
|
1502
|
-
}
|
|
1503
1583
|
}
|
|
1504
1584
|
let ok = false;
|
|
1505
1585
|
|
|
@@ -1769,6 +1849,7 @@ SchemaType.prototype.clone = function() {
|
|
|
1769
1849
|
const schematype = new this.constructor(this.path, options, this.instance, this.parentSchema);
|
|
1770
1850
|
schematype.validators = this.validators.slice();
|
|
1771
1851
|
if (this.requiredValidator !== undefined) schematype.requiredValidator = this.requiredValidator;
|
|
1852
|
+
if (this.allowNullValidator !== undefined) schematype.allowNullValidator = this.allowNullValidator;
|
|
1772
1853
|
if (this.defaultValue !== undefined) schematype.defaultValue = this.defaultValue;
|
|
1773
1854
|
if (this.$immutable !== undefined && this.options.immutable === undefined) {
|
|
1774
1855
|
schematype.$immutable = this.$immutable;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const ValidationError = require('../error/validation');
|
|
4
|
+
|
|
5
|
+
module.exports = function convertErrorToIssues(error) {
|
|
6
|
+
if (error instanceof ValidationError) {
|
|
7
|
+
return Object.keys(error.errors).map(path => {
|
|
8
|
+
const err = error.errors[path];
|
|
9
|
+
return {
|
|
10
|
+
message: err.message,
|
|
11
|
+
path: path.split('.').map(part => {
|
|
12
|
+
const num = +part;
|
|
13
|
+
return Number.isInteger(num) && String(num) === part ? num : part;
|
|
14
|
+
})
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return [{ message: error.message }];
|
|
20
|
+
};
|
package/lib/stateMachine.js
CHANGED
|
@@ -69,8 +69,10 @@ StateMachine.prototype._changeState = function _changeState(path, nextState) {
|
|
|
69
69
|
if (prevState === nextState) {
|
|
70
70
|
return;
|
|
71
71
|
}
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
if (prevState !== undefined) {
|
|
73
|
+
const prevBucket = this.states[prevState];
|
|
74
|
+
if (prevBucket) delete prevBucket[path];
|
|
75
|
+
}
|
|
74
76
|
|
|
75
77
|
this.paths[path] = nextState;
|
|
76
78
|
this.states[nextState] = this.states[nextState] || {};
|
|
@@ -86,13 +88,16 @@ StateMachine.prototype.clear = function clear(state) {
|
|
|
86
88
|
return;
|
|
87
89
|
}
|
|
88
90
|
const keys = Object.keys(this.states[state]);
|
|
91
|
+
if (keys.length === 0) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
// Replace the bucket rather than deleting each key: repeated `delete` puts
|
|
95
|
+
// the object in dictionary mode, which is significantly slower.
|
|
96
|
+
this.states[state] = {};
|
|
89
97
|
let i = keys.length;
|
|
90
|
-
let path;
|
|
91
98
|
|
|
92
99
|
while (i--) {
|
|
93
|
-
|
|
94
|
-
delete this.states[state][path];
|
|
95
|
-
delete this.paths[path];
|
|
100
|
+
delete this.paths[keys[i]];
|
|
96
101
|
}
|
|
97
102
|
};
|
|
98
103
|
|
package/lib/tracing.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
let dc;
|
|
4
|
+
try {
|
|
5
|
+
dc = (typeof process !== 'undefined' && 'getBuiltinModule' in process)
|
|
6
|
+
? process.getBuiltinModule('node:diagnostics_channel')
|
|
7
|
+
: require('node:diagnostics_channel');
|
|
8
|
+
} catch {
|
|
9
|
+
// diagnostics_channel not available
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const hasTracingChannel = !!dc && typeof dc.tracingChannel === 'function';
|
|
13
|
+
|
|
14
|
+
function shouldTrace(channel) {
|
|
15
|
+
// Node 18 and Bun don't expose hasSubscribers on TracingChannel
|
|
16
|
+
// so undefined means it may or may not have subscribers, so we'll trace anyway
|
|
17
|
+
return !!channel && channel.hasSubscribers !== false;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function createTracedChannel(name) {
|
|
21
|
+
const ch = hasTracingChannel ? dc.tracingChannel(name) : undefined;
|
|
22
|
+
|
|
23
|
+
function trace(fn, contextFactory) {
|
|
24
|
+
if (!shouldTrace(ch)) {
|
|
25
|
+
return fn();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const traced = ch.tracePromise(fn, contextFactory());
|
|
29
|
+
return traced;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return { channel: ch, trace };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = {
|
|
36
|
+
createTracedChannel,
|
|
37
|
+
cursorNextChannel: createTracedChannel('mongoose:cursor:next')
|
|
38
|
+
};
|
|
@@ -572,7 +572,7 @@ const methods = {
|
|
|
572
572
|
*
|
|
573
573
|
* #### Note:
|
|
574
574
|
*
|
|
575
|
-
* _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially
|
|
575
|
+
* _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwriting any changes that happen between when you retrieved the object and when you save it._
|
|
576
576
|
*
|
|
577
577
|
* @param {...any} [args]
|
|
578
578
|
* @api public
|
|
@@ -830,7 +830,7 @@ const methods = {
|
|
|
830
830
|
*
|
|
831
831
|
* #### Note:
|
|
832
832
|
*
|
|
833
|
-
* _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially
|
|
833
|
+
* _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwriting any changes that happen between when you retrieved the object and when you save it._
|
|
834
834
|
*
|
|
835
835
|
* @api public
|
|
836
836
|
* @method shift
|
|
@@ -850,7 +850,7 @@ const methods = {
|
|
|
850
850
|
*
|
|
851
851
|
* #### Note:
|
|
852
852
|
*
|
|
853
|
-
* _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially
|
|
853
|
+
* _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwriting any changes that happen between when you retrieved the object and when you save it._
|
|
854
854
|
*
|
|
855
855
|
* @api public
|
|
856
856
|
* @method sort
|
|
@@ -870,7 +870,7 @@ const methods = {
|
|
|
870
870
|
*
|
|
871
871
|
* #### Note:
|
|
872
872
|
*
|
|
873
|
-
* _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially
|
|
873
|
+
* _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwriting any changes that happen between when you retrieved the object and when you save it._
|
|
874
874
|
*
|
|
875
875
|
* @api public
|
|
876
876
|
* @method splice
|
|
@@ -12,6 +12,7 @@ const arrayPathSymbol = require('../../../helpers/symbols').arrayPathSymbol;
|
|
|
12
12
|
const arraySchemaSymbol = require('../../../helpers/symbols').arraySchemaSymbol;
|
|
13
13
|
const documentArrayParent = require('../../../helpers/symbols').documentArrayParent;
|
|
14
14
|
|
|
15
|
+
const _baseReverse = Array.prototype.reverse;
|
|
15
16
|
const _baseToString = Array.prototype.toString;
|
|
16
17
|
|
|
17
18
|
const methods = {
|
|
@@ -211,7 +212,7 @@ const methods = {
|
|
|
211
212
|
},
|
|
212
213
|
|
|
213
214
|
/**
|
|
214
|
-
* Wraps [`Array#push`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/push) with proper change tracking.
|
|
215
|
+
* Wraps [`Array#push`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) with proper change tracking.
|
|
215
216
|
*
|
|
216
217
|
* @param {...object} [args]
|
|
217
218
|
* @api public
|
|
@@ -220,8 +221,37 @@ const methods = {
|
|
|
220
221
|
*/
|
|
221
222
|
|
|
222
223
|
push() {
|
|
224
|
+
const shouldReindex = _shouldReindexAfterPush(arguments);
|
|
223
225
|
const ret = ArrayMethods.push.apply(this, arguments);
|
|
224
226
|
|
|
227
|
+
if (shouldReindex) {
|
|
228
|
+
_updateSubdocIndexes(this);
|
|
229
|
+
}
|
|
230
|
+
_updateParentPopulated(this);
|
|
231
|
+
|
|
232
|
+
return ret;
|
|
233
|
+
},
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Wraps [`Array#pop`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/pop) with proper change tracking.
|
|
237
|
+
* @api private
|
|
238
|
+
*/
|
|
239
|
+
|
|
240
|
+
pop() {
|
|
241
|
+
const ret = ArrayMethods.pop.apply(this, arguments);
|
|
242
|
+
|
|
243
|
+
_updateParentPopulated(this);
|
|
244
|
+
|
|
245
|
+
return ret;
|
|
246
|
+
},
|
|
247
|
+
|
|
248
|
+
/*!
|
|
249
|
+
* ignore
|
|
250
|
+
*/
|
|
251
|
+
|
|
252
|
+
$pop() {
|
|
253
|
+
const ret = ArrayMethods.$pop.apply(this, arguments);
|
|
254
|
+
|
|
225
255
|
_updateParentPopulated(this);
|
|
226
256
|
|
|
227
257
|
return ret;
|
|
@@ -239,32 +269,96 @@ const methods = {
|
|
|
239
269
|
pull() {
|
|
240
270
|
const ret = ArrayMethods.pull.apply(this, arguments);
|
|
241
271
|
|
|
272
|
+
_updateSubdocIndexes(this);
|
|
242
273
|
_updateParentPopulated(this);
|
|
243
274
|
|
|
244
275
|
return ret;
|
|
245
276
|
},
|
|
246
277
|
|
|
247
278
|
/**
|
|
248
|
-
* Wraps [`Array#shift`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/
|
|
279
|
+
* Wraps [`Array#shift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift) with proper change tracking.
|
|
249
280
|
* @api private
|
|
250
281
|
*/
|
|
251
282
|
|
|
252
283
|
shift() {
|
|
253
284
|
const ret = ArrayMethods.shift.apply(this, arguments);
|
|
254
285
|
|
|
286
|
+
_updateSubdocIndexes(this);
|
|
287
|
+
_updateParentPopulated(this);
|
|
288
|
+
|
|
289
|
+
return ret;
|
|
290
|
+
},
|
|
291
|
+
|
|
292
|
+
/*!
|
|
293
|
+
* ignore
|
|
294
|
+
*/
|
|
295
|
+
|
|
296
|
+
$shift() {
|
|
297
|
+
const ret = ArrayMethods.$shift.apply(this, arguments);
|
|
298
|
+
|
|
299
|
+
_updateSubdocIndexes(this);
|
|
255
300
|
_updateParentPopulated(this);
|
|
256
301
|
|
|
257
302
|
return ret;
|
|
258
303
|
},
|
|
259
304
|
|
|
260
305
|
/**
|
|
261
|
-
* Wraps [`Array#splice`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice) with proper change tracking and casting.
|
|
306
|
+
* Wraps [`Array#splice`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) with proper change tracking and casting.
|
|
262
307
|
* @api private
|
|
263
308
|
*/
|
|
264
309
|
|
|
265
310
|
splice() {
|
|
266
311
|
const ret = ArrayMethods.splice.apply(this, arguments);
|
|
267
312
|
|
|
313
|
+
_updateSubdocIndexes(this);
|
|
314
|
+
_updateParentPopulated(this);
|
|
315
|
+
|
|
316
|
+
return ret;
|
|
317
|
+
},
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Wraps [`Array#reverse`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse)
|
|
321
|
+
* with proper change tracking.
|
|
322
|
+
* @api private
|
|
323
|
+
*/
|
|
324
|
+
|
|
325
|
+
reverse() {
|
|
326
|
+
_baseReverse.call(this.__array);
|
|
327
|
+
this._registerAtomic('$set', this);
|
|
328
|
+
|
|
329
|
+
_updateSubdocIndexes(this);
|
|
330
|
+
_updateParentPopulated(this);
|
|
331
|
+
|
|
332
|
+
return this;
|
|
333
|
+
},
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Wraps [`Array#sort`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)
|
|
337
|
+
* with proper change tracking.
|
|
338
|
+
*
|
|
339
|
+
* @param {Function} [compareFunction]
|
|
340
|
+
* @api private
|
|
341
|
+
*/
|
|
342
|
+
|
|
343
|
+
sort() {
|
|
344
|
+
const ret = ArrayMethods.sort.apply(this, arguments);
|
|
345
|
+
|
|
346
|
+
_updateSubdocIndexes(this);
|
|
347
|
+
_updateParentPopulated(this);
|
|
348
|
+
|
|
349
|
+
return ret;
|
|
350
|
+
},
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Wraps [`Array#unshift`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift)
|
|
354
|
+
* with proper change tracking.
|
|
355
|
+
* @api private
|
|
356
|
+
*/
|
|
357
|
+
|
|
358
|
+
unshift() {
|
|
359
|
+
const ret = ArrayMethods.unshift.apply(this, arguments);
|
|
360
|
+
|
|
361
|
+
_updateSubdocIndexes(this);
|
|
268
362
|
_updateParentPopulated(this);
|
|
269
363
|
|
|
270
364
|
return ret;
|
|
@@ -389,6 +483,26 @@ const methods = {
|
|
|
389
483
|
|
|
390
484
|
module.exports = methods;
|
|
391
485
|
|
|
486
|
+
/*!
|
|
487
|
+
* ignore
|
|
488
|
+
*/
|
|
489
|
+
|
|
490
|
+
function _updateSubdocIndexes(arr) {
|
|
491
|
+
const rawArray = utils.isMongooseArray(arr) ? arr.__array : arr;
|
|
492
|
+
|
|
493
|
+
for (let i = 0; i < rawArray.length; ++i) {
|
|
494
|
+
if (typeof rawArray[i]?.$setIndex === 'function') {
|
|
495
|
+
rawArray[i].$setIndex(i);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
function _shouldReindexAfterPush(args) {
|
|
501
|
+
return args[0] != null &&
|
|
502
|
+
utils.hasUserDefinedProperty(args[0], '$each') &&
|
|
503
|
+
args[0].$position != null;
|
|
504
|
+
}
|
|
505
|
+
|
|
392
506
|
/**
|
|
393
507
|
* If this is a document array, each element may contain single
|
|
394
508
|
* populated paths, so we need to modify the top-level document's
|
package/lib/types/subdocument.js
CHANGED
|
@@ -403,7 +403,9 @@ if (util.inspect.custom) {
|
|
|
403
403
|
|
|
404
404
|
/**
|
|
405
405
|
* Override `$toObject()` to handle minimizing the whole path. Should not minimize if schematype-level minimize
|
|
406
|
-
* is set to false re: gh-11247, gh-14058, gh-14151
|
|
406
|
+
* is set to false re: gh-11247, gh-14058, gh-14151. Should not minimize document array elements: an array
|
|
407
|
+
* element cannot be removed without shifting the array, so minimizing it to `undefined` makes the BSON
|
|
408
|
+
* serializer store `null` re: gh-7322.
|
|
407
409
|
*/
|
|
408
410
|
|
|
409
411
|
Subdocument.prototype.$toObject = function $toObject(options, json) {
|
|
@@ -413,7 +415,7 @@ Subdocument.prototype.$toObject = function $toObject(options, json) {
|
|
|
413
415
|
// If minimize is set, then we can minimize out the whole object.
|
|
414
416
|
if (utils.hasOwnKeys(ret) === false && options?._calledWithOptions != null) {
|
|
415
417
|
const minimize = options._calledWithOptions?.minimize ?? this?.$__schemaTypeOptions?.minimize ?? options.minimize;
|
|
416
|
-
if (minimize && !this.constructor.$__required) {
|
|
418
|
+
if (minimize && !this.constructor.$__required && !this.$isDocumentArrayElement) {
|
|
417
419
|
return undefined;
|
|
418
420
|
}
|
|
419
421
|
}
|
package/lib/utils.js
CHANGED
|
@@ -119,6 +119,16 @@ exports.deepEqual = function deepEqual(a, b) {
|
|
|
119
119
|
deepEqual(Array.from(a.values()), Array.from(b.values()));
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
if (a instanceof Set || b instanceof Set) {
|
|
123
|
+
if (!(a instanceof Set) || !(b instanceof Set)) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
if (a.size !== b.size) {
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
return deepEqual(Array.from(a.values()), Array.from(b.values()));
|
|
130
|
+
}
|
|
131
|
+
|
|
122
132
|
// Handle MongooseNumbers
|
|
123
133
|
if (a instanceof Number && b instanceof Number) {
|
|
124
134
|
return a.valueOf() === b.valueOf();
|
|
@@ -313,8 +323,8 @@ exports.merge = function merge(to, from, options, path) {
|
|
|
313
323
|
// base schema has a given path as a single nested but discriminator schema
|
|
314
324
|
// has the path as a document array, or vice versa (gh-9534)
|
|
315
325
|
if (options.isDiscriminatorSchemaMerge &&
|
|
316
|
-
(from[key].$isSingleNested && to[key].$isMongooseDocumentArray) ||
|
|
317
|
-
(from[key].$isMongooseDocumentArray && to[key].$isSingleNested)) {
|
|
326
|
+
((from[key].$isSingleNested && to[key].$isMongooseDocumentArray) ||
|
|
327
|
+
(from[key].$isMongooseDocumentArray && to[key].$isSingleNested))) {
|
|
318
328
|
continue;
|
|
319
329
|
} else if (from[key].instanceOfSchema) {
|
|
320
330
|
if (to[key].instanceOfSchema) {
|