Skip to content

Commit 159d705

Browse files
committed
fix: apply embedded discriminators recursively so fix for #14109 works on discriminators underneath subdocs
1 parent 4437d8e commit 159d705

File tree

3 files changed

+77
-9
lines changed

3 files changed

+77
-9
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
'use strict';
2+
3+
module.exports = applyEmbeddedDiscriminators;
4+
5+
function applyEmbeddedDiscriminators(schema, seen = new WeakSet()) {
6+
if (seen.has(schema)) {
7+
return;
8+
}
9+
seen.add(schema);
10+
for (const path of Object.keys(schema.paths)) {
11+
const schemaType = schema.paths[path];
12+
if (!schemaType.schema) {
13+
continue;
14+
}
15+
applyEmbeddedDiscriminators(schemaType.schema, seen);
16+
if (!schemaType.schema._applyDiscriminators) {
17+
continue;
18+
}
19+
for (const disc of schemaType.schema._applyDiscriminators.keys()) {
20+
schemaType.discriminator(disc, schemaType.schema._applyDiscriminators.get(disc));
21+
}
22+
}
23+
}

lib/index.js

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const sanitizeFilter = require('./helpers/query/sanitizeFilter');
3232
const isBsonType = require('./helpers/isBsonType');
3333
const MongooseError = require('./error/mongooseError');
3434
const SetOptionError = require('./error/setOptionError');
35+
const applyEmbeddedDiscriminators = require('./helpers/discriminator/applyEmbeddedDiscriminators');
3536

3637
const defaultMongooseSymbol = Symbol.for('mongoose:default');
3738

@@ -629,15 +630,7 @@ Mongoose.prototype._model = function(name, schema, collection, options) {
629630
}
630631
}
631632

632-
for (const path of Object.keys(schema.paths)) {
633-
const schemaType = schema.paths[path];
634-
if (!schemaType.schema || !schemaType.schema._applyDiscriminators) {
635-
continue;
636-
}
637-
for (const disc of schemaType.schema._applyDiscriminators.keys()) {
638-
schemaType.discriminator(disc, schemaType.schema._applyDiscriminators.get(disc));
639-
}
640-
}
633+
applyEmbeddedDiscriminators(schema);
641634

642635
return model;
643636
};

test/document.test.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12708,6 +12708,58 @@ describe('document', function() {
1270812708
);
1270912709
});
1271012710

12711+
it('handles embedded discriminators on nested path defined using Schema.prototype.discriminator (gh-14109) (gh-13898)', async function() {
12712+
const baseNestedDiscriminated = new Schema({
12713+
type: { type: Number, required: true }
12714+
}, { discriminatorKey: 'type' });
12715+
12716+
class BaseClass {
12717+
whoAmI() {
12718+
return 'I am baseNestedDiscriminated';
12719+
}
12720+
}
12721+
BaseClass.type = 1;
12722+
12723+
baseNestedDiscriminated.loadClass(BaseClass);
12724+
12725+
class NumberTyped extends BaseClass {
12726+
whoAmI() {
12727+
return 'I am NumberTyped';
12728+
}
12729+
}
12730+
NumberTyped.type = 3;
12731+
12732+
class StringTyped extends BaseClass {
12733+
whoAmI() {
12734+
return 'I am StringTyped';
12735+
}
12736+
}
12737+
StringTyped.type = 4;
12738+
12739+
const containsNestedSchema = new Schema({
12740+
nestedDiscriminatedTypes: { type: [baseNestedDiscriminated], required: true }
12741+
});
12742+
12743+
baseNestedDiscriminated.discriminator(1, new Schema({}).loadClass(NumberTyped));
12744+
baseNestedDiscriminated.discriminator('3', new Schema({}).loadClass(StringTyped));
12745+
12746+
const l2Schema = new Schema({ l3: containsNestedSchema });
12747+
const l1Schema = new Schema({ l2: l2Schema });
12748+
12749+
const Test = db.model('Test', l1Schema);
12750+
const instance = await Test.create({
12751+
l2: {
12752+
l3: {
12753+
nestedDiscriminatedTypes: [{ type: 1 }, { type: '3' }]
12754+
}
12755+
}
12756+
});
12757+
assert.deepStrictEqual(
12758+
instance.l2.l3.nestedDiscriminatedTypes.map(i => i.whoAmI()),
12759+
['I am NumberTyped', 'I am StringTyped']
12760+
);
12761+
});
12762+
1271112763
it('can use `collection` as schema name (gh-13956)', async function() {
1271212764
const schema = new mongoose.Schema({ name: String, collection: String });
1271312765
const Test = db.model('Test', schema);

0 commit comments

Comments
 (0)