Skip to content

Commit 6dd7f6e

Browse files
committed
Merge branch 'master' into 9.0
2 parents c28738e + 4d93843 commit 6dd7f6e

File tree

7 files changed

+73
-12
lines changed

7 files changed

+73
-12
lines changed

docs/layout.pug

+2
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ html(lang='en')
111111
a.pure-menu-link(href=`${versions.versionedPath}/docs/typescript/query-helpers.html`, class=outputUrl === `${versions.versionedPath}/docs/typescript/query-helpers.html` ? 'selected' : '') Query Helpers
112112
li.pure-menu-item.sub-item
113113
a.pure-menu-link(href=`${versions.versionedPath}/docs/typescript/populate.html`, class=outputUrl === `${versions.versionedPath}/docs/typescript/populate.html` ? 'selected' : '') Populate
114+
li.pure-menu-item.sub-item
115+
a.pure-menu-link(href=`${versions.versionedPath}/docs/typescript/virtuals.html`, class=outputUrl === `${versions.versionedPath}/docs/typescript/virtuals.html` ? 'selected' : '') Virtuals
114116
li.pure-menu-item.sub-item
115117
a.pure-menu-link(href=`${versions.versionedPath}/docs/typescript/subdocuments.html`, class=outputUrl === `${versions.versionedPath}/docs/typescript/subdocuments.html` ? 'selected' : '') Subdocuments
116118
li.pure-menu-item

docs/typescript/virtuals.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ interface UserVirtuals {
7272
fullName: string;
7373
}
7474

75-
type UserModel = Model<UserDoc, {}, UserVirtuals>; // <-- add virtuals here...
75+
type UserModel = Model<UserDoc, {}, {}, UserVirtuals>; // <-- add virtuals here...
7676

77-
const schema = new Schema<UserDoc, UserModel, UserVirtuals>({ // <-- and here
77+
const schema = new Schema<UserDoc, UserModel, {}, {}, UserVirtuals>({ // <-- and here
7878
firstName: String,
7979
lastName: String
8080
});

lib/helpers/query/getEmbeddedDiscriminatorPath.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const updatedPathsByArrayFilter = require('../update/updatedPathsByArrayFilter')
1717
*/
1818

1919
module.exports = function getEmbeddedDiscriminatorPath(schema, update, filter, path, options) {
20-
const parts = path.split('.');
20+
const parts = path.indexOf('.') === -1 ? [path] : path.split('.');
2121
let schematype = null;
2222
let type = 'adhocOrUndefined';
2323

@@ -26,9 +26,10 @@ module.exports = function getEmbeddedDiscriminatorPath(schema, update, filter, p
2626
const arrayFilters = options != null && Array.isArray(options.arrayFilters) ?
2727
options.arrayFilters : [];
2828
const updatedPathsByFilter = updatedPathsByArrayFilter(update);
29+
let startIndex = 0;
2930

3031
for (let i = 0; i < parts.length; ++i) {
31-
const originalSubpath = parts.slice(0, i + 1).join('.');
32+
const originalSubpath = parts.slice(startIndex, i + 1).join('.');
3233
const subpath = cleanPositionalOperators(originalSubpath);
3334
schematype = schema.path(subpath);
3435
if (schematype == null) {
@@ -89,6 +90,8 @@ module.exports = function getEmbeddedDiscriminatorPath(schema, update, filter, p
8990

9091
const rest = parts.slice(i + 1).join('.');
9192
schematype = discriminatorSchema.path(rest);
93+
schema = discriminatorSchema;
94+
startIndex = i + 1;
9295
if (schematype != null) {
9396
type = discriminatorSchema._getPathType(rest);
9497
break;

lib/helpers/schema/getPath.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const numberRE = /^\d+$/;
88
* @api private
99
*/
1010

11-
module.exports = function getPath(schema, path) {
11+
module.exports = function getPath(schema, path, discriminatorValueMap) {
1212
let schematype = schema.path(path);
1313
if (schematype != null) {
1414
return schematype;
@@ -26,10 +26,13 @@ module.exports = function getPath(schema, path) {
2626
schematype = schema.path(cur);
2727
if (schematype != null && schematype.schema) {
2828
schema = schematype.schema;
29-
cur = '';
3029
if (!isArray && schematype.$isMongooseDocumentArray) {
3130
isArray = true;
3231
}
32+
if (discriminatorValueMap && discriminatorValueMap[cur]) {
33+
schema = schema.discriminators[discriminatorValueMap[cur]] ?? schema;
34+
}
35+
cur = '';
3336
}
3437
}
3538

lib/helpers/update/castArrayFilters.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ function _castArrayFilters(arrayFilters, schema, strictQuery, updatedPathsByFilt
3333
return;
3434
}
3535

36+
// Map to store discriminator values for embedded documents in the array filters.
37+
// This is used to handle cases where array filters target specific embedded document types.
38+
const discriminatorValueMap = {};
39+
3640
for (const filter of arrayFilters) {
3741
if (filter == null) {
3842
throw new Error(`Got null array filter in ${arrayFilters}`);
@@ -58,12 +62,13 @@ function _castArrayFilters(arrayFilters, schema, strictQuery, updatedPathsByFilt
5862
updatedPathsByFilter[filterWildcardPath]
5963
);
6064

61-
const baseSchematype = getPath(schema, baseFilterPath);
65+
const baseSchematype = getPath(schema, baseFilterPath, discriminatorValueMap);
6266
let filterBaseSchema = baseSchematype != null ? baseSchematype.schema : null;
6367
if (filterBaseSchema != null &&
6468
filterBaseSchema.discriminators != null &&
6569
filter[filterWildcardPath + '.' + filterBaseSchema.options.discriminatorKey]) {
6670
filterBaseSchema = filterBaseSchema.discriminators[filter[filterWildcardPath + '.' + filterBaseSchema.options.discriminatorKey]] || filterBaseSchema;
71+
discriminatorValueMap[baseFilterPath] = filter[filterWildcardPath + '.' + filterBaseSchema.options.discriminatorKey];
6772
}
6873

6974
for (const key of keys) {
@@ -83,7 +88,7 @@ function _castArrayFilters(arrayFilters, schema, strictQuery, updatedPathsByFilt
8388
// If there are multiple array filters in the path being updated, make sure
8489
// to replace them so we can get the schema path.
8590
filterPathRelativeToBase = cleanPositionalOperators(filterPathRelativeToBase);
86-
schematype = getPath(filterBaseSchema, filterPathRelativeToBase);
91+
schematype = getPath(filterBaseSchema, filterPathRelativeToBase, discriminatorValueMap);
8792
}
8893

8994
if (schematype == null) {

package.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,17 @@
4747
"lodash.isequal": "4.5.0",
4848
"lodash.isequalwith": "4.4.0",
4949
"markdownlint-cli2": "^0.17.1",
50-
"marked": "15.0.7",
50+
"marked": "15.0.11",
5151
"mkdirp": "^3.0.1",
52-
"mocha": "11.1.0",
52+
"mocha": "11.2.2",
5353
"moment": "2.30.1",
5454
"mongodb-memory-server": "10.1.4",
5555
"ncp": "^2.0.0",
5656
"nyc": "15.1.0",
5757
"pug": "3.0.3",
5858
"sinon": "20.0.0",
59-
"tsd": "0.31.2",
60-
"typescript": "5.7.3",
59+
"tsd": "0.32.0",
60+
"typescript": "5.8.3",
6161
"uuid": "11.1.0"
6262
},
6363
"directories": {

test/helpers/update.castArrayFilters.test.js

+48
Original file line numberDiff line numberDiff line change
@@ -349,4 +349,52 @@ describe('castArrayFilters', function() {
349349

350350
assert.strictEqual(q.getUpdate().$set['groups.$[group].tags.$[tag]'], '42');
351351
});
352+
353+
it('casts paths underneath embedded discriminators (gh-15386)', async function() {
354+
const eventSchema = new Schema({ message: String }, { discriminatorKey: 'kind', _id: false });
355+
const batchSchema = new Schema({ events: [eventSchema] });
356+
357+
const docArray = batchSchema.path('events');
358+
docArray.discriminator('Clicked', new Schema({ element: { type: String, required: true } }, { _id: false }));
359+
360+
const productSchema = new Schema({
361+
name: String,
362+
price: Number
363+
});
364+
365+
docArray.discriminator(
366+
'Purchased',
367+
new Schema({
368+
products: {
369+
type: [productSchema],
370+
required: true
371+
}
372+
})
373+
);
374+
375+
const q = new Query();
376+
q.schema = batchSchema;
377+
378+
const filter = {};
379+
const update = {
380+
$set: {
381+
'events.$[event].products.$[product].price': '20'
382+
}
383+
};
384+
const purchasedId = new Types.ObjectId();
385+
const productId = new Types.ObjectId();
386+
const opts = {
387+
arrayFilters: [
388+
{ 'event._id': purchasedId, 'event.kind': 'Purchased' },
389+
{ 'product._id': productId.toString() }
390+
]
391+
};
392+
393+
q.updateOne(filter, update, opts);
394+
castArrayFilters(q);
395+
q._update = q._castUpdate(q._update, false);
396+
397+
assert.strictEqual(q.getOptions().arrayFilters[1]['product._id'].toHexString(), productId.toHexString());
398+
assert.strictEqual(q.getUpdate().$set['events.$[event].products.$[product].price'], 20);
399+
});
352400
});

0 commit comments

Comments
 (0)