mongoose 9.11.0 → 9.11.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/lib/cast.js +9 -19
- package/lib/cursor/queryCursor.js +4 -1
- package/lib/document.js +6 -5
- package/lib/helpers/discriminator/getDiscriminatorValueFromFilter.js +30 -0
- package/lib/helpers/document/toObjectRecursive.js +49 -0
- package/lib/helpers/query/getEmbeddedDiscriminatorPath.js +4 -3
- package/lib/helpers/update/castArrayFilters.js +1 -1
- package/lib/schema/array.js +13 -0
- package/lib/schema/documentArray.js +4 -4
- package/package.json +1 -1
- package/types/index.d.ts +1 -1
- package/types/models.d.ts +10 -4
package/lib/cast.js
CHANGED
|
@@ -11,6 +11,7 @@ const cast$expr = require('./helpers/query/cast$expr');
|
|
|
11
11
|
const castString = require('./cast/string');
|
|
12
12
|
const castTextSearch = require('./schema/operators/text');
|
|
13
13
|
const get = require('./helpers/get');
|
|
14
|
+
const getDiscriminatorValueFromFilter = require('./helpers/discriminator/getDiscriminatorValueFromFilter');
|
|
14
15
|
const getSchemaDiscriminatorByValue = require('./helpers/discriminator/getSchemaDiscriminatorByValue');
|
|
15
16
|
const isOperator = require('./helpers/query/isOperator');
|
|
16
17
|
const util = require('util');
|
|
@@ -43,7 +44,8 @@ module.exports = function cast(schema, obj, options, context) {
|
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
if (schema?.discriminators != null && obj[schema.options.discriminatorKey] != null) {
|
|
46
|
-
|
|
47
|
+
const discriminatorValue = getDiscriminatorValueFromFilter(obj[schema.options.discriminatorKey]);
|
|
48
|
+
schema = getSchemaDiscriminatorByValue(schema, discriminatorValue) || schema;
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
const paths = Object.keys(obj);
|
|
@@ -134,18 +136,10 @@ module.exports = function cast(schema, obj, options, context) {
|
|
|
134
136
|
if (_schematype?.schema?.discriminators != null &&
|
|
135
137
|
discriminatorKey != null &&
|
|
136
138
|
pathLastHalf !== discriminatorKey) {
|
|
137
|
-
const discriminatorVal = get(obj, pathFirstHalf + '.' + discriminatorKey);
|
|
139
|
+
const discriminatorVal = getDiscriminatorValueFromFilter(get(obj, pathFirstHalf + '.' + discriminatorKey));
|
|
138
140
|
const discriminators = _schematype.schema.discriminators;
|
|
139
141
|
if (typeof discriminatorVal === 'string' && discriminators[discriminatorVal] != null) {
|
|
140
|
-
|
|
141
142
|
schematype = discriminators[discriminatorVal].path(pathLastHalf);
|
|
142
|
-
} else if (discriminatorVal != null &&
|
|
143
|
-
Object.keys(discriminatorVal).length === 1 &&
|
|
144
|
-
Array.isArray(discriminatorVal.$in) &&
|
|
145
|
-
discriminatorVal.$in.length === 1 &&
|
|
146
|
-
typeof discriminatorVal.$in[0] === 'string' &&
|
|
147
|
-
discriminators[discriminatorVal.$in[0]] != null) {
|
|
148
|
-
schematype = discriminators[discriminatorVal.$in[0]].path(pathLastHalf);
|
|
149
143
|
}
|
|
150
144
|
}
|
|
151
145
|
}
|
|
@@ -329,15 +323,11 @@ module.exports = function cast(schema, obj, options, context) {
|
|
|
329
323
|
if (nested && schematype?.schema != null) {
|
|
330
324
|
cast(schematype.schema, nested, options, context);
|
|
331
325
|
} else if (nested && schematype?.$isMongooseArray) {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
nested,
|
|
338
|
-
context
|
|
339
|
-
);
|
|
340
|
-
}
|
|
326
|
+
val[$cond] = schematype.castForQuery(
|
|
327
|
+
$cond,
|
|
328
|
+
nested,
|
|
329
|
+
context
|
|
330
|
+
);
|
|
341
331
|
}
|
|
342
332
|
} else if ($cond === '$not') {
|
|
343
333
|
if (nested && schematype) {
|
|
@@ -170,6 +170,9 @@ QueryCursor.prototype.getDriverCursor = async function getDriverCursor() {
|
|
|
170
170
|
if (this.cursor) {
|
|
171
171
|
return this.cursor;
|
|
172
172
|
}
|
|
173
|
+
if (this._error) {
|
|
174
|
+
throw this._error;
|
|
175
|
+
}
|
|
173
176
|
|
|
174
177
|
await once(this, 'cursor');
|
|
175
178
|
return this.cursor;
|
|
@@ -278,7 +281,7 @@ QueryCursor.prototype._destroy = function _destroy(_err, callback) {
|
|
|
278
281
|
|
|
279
282
|
waitForCursor
|
|
280
283
|
.then(() => {
|
|
281
|
-
this.cursor.close();
|
|
284
|
+
return this.cursor.close();
|
|
282
285
|
})
|
|
283
286
|
.then(() => {
|
|
284
287
|
this._closed = true;
|
package/lib/document.js
CHANGED
|
@@ -63,6 +63,7 @@ const scopeSymbol = require('./helpers/symbols').scopeSymbol;
|
|
|
63
63
|
const schemaMixedSymbol = require('./schema/symbols').schemaMixedSymbol;
|
|
64
64
|
const getDeepestSubdocumentForPath = require('./helpers/document/getDeepestSubdocumentForPath');
|
|
65
65
|
const sessionNewDocuments = require('./helpers/symbols').sessionNewDocuments;
|
|
66
|
+
const toObjectRecursive = require('./helpers/document/toObjectRecursive');
|
|
66
67
|
|
|
67
68
|
let DocumentArray;
|
|
68
69
|
let Embedded;
|
|
@@ -1253,9 +1254,7 @@ Document.prototype.$set = function $set(path, val, type, options) {
|
|
|
1253
1254
|
|
|
1254
1255
|
if (pathType === 'nested' && val) {
|
|
1255
1256
|
if (typeof val === 'object' && val != null) {
|
|
1256
|
-
|
|
1257
|
-
val = val.toObject(internalToObjectOptions);
|
|
1258
|
-
}
|
|
1257
|
+
val = toObjectRecursive(val, internalToObjectOptions);
|
|
1259
1258
|
if (val == null) {
|
|
1260
1259
|
this.invalidate(path, new MongooseError.CastError('Object', val, path));
|
|
1261
1260
|
return this;
|
|
@@ -4265,9 +4264,11 @@ Document.prototype.$toObject = function(options, json) {
|
|
|
4265
4264
|
?? false;
|
|
4266
4265
|
|
|
4267
4266
|
let ret;
|
|
4268
|
-
if (hasOnlyPrimitiveValues && !options.flattenObjectIds) {
|
|
4267
|
+
if (hasOnlyPrimitiveValues && !options.flattenObjectIds && !options.flattenDecimals) {
|
|
4269
4268
|
// Fast path: if we don't have any nested objects or arrays, we only need a
|
|
4270
|
-
// shallow clone.
|
|
4269
|
+
// shallow clone. Skipped for `flattenObjectIds` and `flattenDecimals`, because
|
|
4270
|
+
// `$__hasOnlyPrimitiveValues()` counts ObjectIds and Decimal128s as primitives
|
|
4271
|
+
// and only the full `clone()` path converts them.
|
|
4271
4272
|
ret = this.$__toObjectShallow(schemaFieldsOnly);
|
|
4272
4273
|
} else if (schemaFieldsOnly) {
|
|
4273
4274
|
ret = {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const isPOJO = require('../isPOJO');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Returns the single discriminator value that a query filter condition selects,
|
|
7
|
+
* like `'Clicked'` for `'Clicked'`, `{ $eq: 'Clicked' }`, or `{ $in: ['Clicked'] }`.
|
|
8
|
+
* Returns the condition unchanged if it does not select exactly one value.
|
|
9
|
+
*
|
|
10
|
+
* @param {any} value the filter condition on the discriminator key
|
|
11
|
+
* @return {any}
|
|
12
|
+
* @api private
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
module.exports = function getDiscriminatorValueFromFilter(value) {
|
|
16
|
+
if (!isPOJO(value)) {
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
const keys = Object.keys(value);
|
|
20
|
+
if (keys.length !== 1) {
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
if (keys[0] === '$eq') {
|
|
24
|
+
return value.$eq;
|
|
25
|
+
}
|
|
26
|
+
if (keys[0] === '$in' && Array.isArray(value.$in) && value.$in.length === 1) {
|
|
27
|
+
return value.$in[0];
|
|
28
|
+
}
|
|
29
|
+
return value;
|
|
30
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const isPOJO = require('../isPOJO');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Convert nested path documents underneath POJOs and arrays to POJOs without
|
|
7
|
+
* modifying the original value. Only clone containers that contain a nested
|
|
8
|
+
* path document. Preserve regular document children so casting can handle
|
|
9
|
+
* populated documents and subdocuments.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
module.exports = function toObjectRecursive(value, options) {
|
|
13
|
+
return _toObjectRecursive(value, options, true, new Set());
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
function _toObjectRecursive(value, options, isRoot, seen) {
|
|
17
|
+
if (value == null) {
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (value.$__ != null && typeof value.toObject === 'function') {
|
|
22
|
+
return isRoot || value.$__isNested ? value.toObject(options) : value;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (!Array.isArray(value) && !isPOJO(value)) {
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (seen.has(value)) {
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
seen.add(value);
|
|
33
|
+
|
|
34
|
+
let ret = value;
|
|
35
|
+
for (const key of Object.keys(value)) {
|
|
36
|
+
const converted = _toObjectRecursive(value[key], options, false, seen);
|
|
37
|
+
if (converted === value[key]) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (ret === value) {
|
|
42
|
+
ret = Array.isArray(value) ? Object.assign([], value) : { ...value };
|
|
43
|
+
}
|
|
44
|
+
ret[key] = converted;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
seen.delete(value);
|
|
48
|
+
return ret;
|
|
49
|
+
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const cleanPositionalOperators = require('../schema/cleanPositionalOperators');
|
|
4
4
|
const get = require('../get');
|
|
5
5
|
const getDiscriminatorByValue = require('../discriminator/getDiscriminatorByValue');
|
|
6
|
+
const getDiscriminatorValueFromFilter = require('../discriminator/getDiscriminatorValueFromFilter');
|
|
6
7
|
const updatedPathsByArrayFilter = require('../update/updatedPathsByArrayFilter');
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -46,16 +47,16 @@ module.exports = function getEmbeddedDiscriminatorPath(schema, update, filter, p
|
|
|
46
47
|
let discriminatorKey = null;
|
|
47
48
|
|
|
48
49
|
if (discriminatorValuePath in filter) {
|
|
49
|
-
discriminatorKey = filter[discriminatorValuePath];
|
|
50
|
+
discriminatorKey = getDiscriminatorValueFromFilter(filter[discriminatorValuePath]);
|
|
50
51
|
}
|
|
51
52
|
if (discriminatorFilterPath in filter) {
|
|
52
|
-
discriminatorKey = filter[discriminatorFilterPath];
|
|
53
|
+
discriminatorKey = getDiscriminatorValueFromFilter(filter[discriminatorFilterPath]);
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
const wrapperPath = subpath.replace(/\.\d+$/, '');
|
|
56
57
|
if (schematype.$isMongooseDocumentArrayElement &&
|
|
57
58
|
get(filter[wrapperPath], '$elemMatch.' + key) != null) {
|
|
58
|
-
discriminatorKey = filter[wrapperPath].$elemMatch[key];
|
|
59
|
+
discriminatorKey = getDiscriminatorValueFromFilter(filter[wrapperPath].$elemMatch[key]);
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
const discriminatorKeyUpdatePath = originalSubpath + '.' + key;
|
package/lib/schema/array.js
CHANGED
|
@@ -611,6 +611,19 @@ function cast$elemMatch(val, context) {
|
|
|
611
611
|
for (let i = 0; i < numKeys; ++i) {
|
|
612
612
|
const key = keys[i];
|
|
613
613
|
const value = val[key];
|
|
614
|
+
if (key === '$not') {
|
|
615
|
+
// `$not` wraps other operators, like `{ $not: { $gt: 5 } }` or
|
|
616
|
+
// `{ $not: { $elemMatch: ... } }`, so cast each wrapped operator.
|
|
617
|
+
// A RegExp is left as-is.
|
|
618
|
+
if (utils.isPOJO(value)) {
|
|
619
|
+
for (const notKey of Object.keys(value)) {
|
|
620
|
+
if (isOperator(notKey) && value[notKey] != null) {
|
|
621
|
+
value[notKey] = this.castForQuery(notKey, value[notKey], context);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
continue;
|
|
626
|
+
}
|
|
614
627
|
if (isOperator(key) && value != null) {
|
|
615
628
|
val[key] = this.castForQuery(key, value, context);
|
|
616
629
|
}
|
|
@@ -484,10 +484,10 @@ SchemaDocumentArray.prototype.cast = function(value, doc, init, prev, options) {
|
|
|
484
484
|
}
|
|
485
485
|
|
|
486
486
|
subdoc = new Constructor(null, value, initDocumentOptions, selected, i);
|
|
487
|
-
// Don't pass `path` to $init -
|
|
488
|
-
// Element subdocuments use relative paths internally for change tracking.
|
|
489
|
-
if (options.path != null) {
|
|
490
|
-
const { path, ...initOptions } = options;
|
|
487
|
+
// Don't pass `path` or `arrayPathIndex` to $init - they're only for this DocumentArray itself,
|
|
488
|
+
// not its element fields. Element subdocuments use relative paths internally for change tracking.
|
|
489
|
+
if (options.path != null || options.arrayPathIndex != null) {
|
|
490
|
+
const { path, arrayPathIndex, ...initOptions } = options;
|
|
491
491
|
options = initOptions;
|
|
492
492
|
}
|
|
493
493
|
rawArray[i] = subdoc.$init(rawArray[i], options);
|
package/package.json
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -738,7 +738,7 @@ declare module 'mongoose' {
|
|
|
738
738
|
static ObjectId: typeof Schema.Types.ObjectId;
|
|
739
739
|
}
|
|
740
740
|
|
|
741
|
-
export type NumberSchemaDefinition = typeof Number | 'number' | 'Number' | typeof Schema.Types.Number | Schema.Types.Number;
|
|
741
|
+
export type NumberSchemaDefinition = typeof Number | 'number' | 'Number' | typeof Schema.Types.Number | Schema.Types.Number | 'int32' | 'Int32' | typeof Schema.Types.Int32 | Schema.Types.Int32;
|
|
742
742
|
export type StringSchemaDefinition = typeof String | 'string' | 'String' | typeof Schema.Types.String | Schema.Types.String;
|
|
743
743
|
export type BooleanSchemaDefinition = typeof Boolean | 'boolean' | 'Boolean' | typeof Schema.Types.Boolean | Schema.Types.Boolean;
|
|
744
744
|
export type DateSchemaDefinition = DateConstructor | 'date' | 'Date' | typeof Schema.Types.Date | Schema.Types.Date;
|
package/types/models.d.ts
CHANGED
|
@@ -158,13 +158,19 @@ declare module 'mongoose' {
|
|
|
158
158
|
MongooseBulkUpdatePerOperationOptions;
|
|
159
159
|
|
|
160
160
|
export type UpdateOneModel<TSchema extends mongodb.Document = mongodb.Document> =
|
|
161
|
-
Omit<mongodb.UpdateOneModel<TSchema>, 'filter'> &
|
|
162
|
-
{
|
|
161
|
+
Omit<mongodb.UpdateOneModel<TSchema>, 'filter' | 'update'> &
|
|
162
|
+
{
|
|
163
|
+
filter: QueryFilter<TSchema>;
|
|
164
|
+
update: UpdateQuery<TSchema> | UpdateWithAggregationPipeline;
|
|
165
|
+
} &
|
|
163
166
|
MongooseBulkUpdatePerOperationOptions;
|
|
164
167
|
|
|
165
168
|
export type UpdateManyModel<TSchema extends mongodb.Document = mongodb.Document> =
|
|
166
|
-
Omit<mongodb.UpdateManyModel<TSchema>, 'filter'> &
|
|
167
|
-
{
|
|
169
|
+
Omit<mongodb.UpdateManyModel<TSchema>, 'filter' | 'update'> &
|
|
170
|
+
{
|
|
171
|
+
filter: QueryFilter<TSchema>;
|
|
172
|
+
update: UpdateQuery<TSchema> | UpdateWithAggregationPipeline;
|
|
173
|
+
} &
|
|
168
174
|
MongooseBulkUpdatePerOperationOptions;
|
|
169
175
|
|
|
170
176
|
export type DeleteOneModel<TSchema extends mongodb.Document = mongodb.Document> =
|