From f845fb22eccbeb033bf99c6b412928cbfd40a764 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Tue, 2 Apr 2024 16:23:02 -0400 Subject: [PATCH] fix(schema): support setting discriminator options in Schema.prototype.discriminator() Fix #14448 --- .../applyEmbeddedDiscriminators.js | 7 +++++-- lib/index.js | 6 +++++- lib/schema.js | 10 ++++++++-- test/schema.test.js | 19 +++++++++++++++++++ 4 files changed, 37 insertions(+), 5 deletions(-) diff --git a/lib/helpers/discriminator/applyEmbeddedDiscriminators.js b/lib/helpers/discriminator/applyEmbeddedDiscriminators.js index 9a04ecb072f..b7832234cbb 100644 --- a/lib/helpers/discriminator/applyEmbeddedDiscriminators.js +++ b/lib/helpers/discriminator/applyEmbeddedDiscriminators.js @@ -20,9 +20,12 @@ function applyEmbeddedDiscriminators(schema, seen = new WeakSet()) { continue; } for (const discriminatorKey of schemaType.schema._applyDiscriminators.keys()) { - const discriminatorSchema = schemaType.schema._applyDiscriminators.get(discriminatorKey); + const { + schema: discriminatorSchema, + options + } = schemaType.schema._applyDiscriminators.get(discriminatorKey); applyEmbeddedDiscriminators(discriminatorSchema, seen); - schemaType.discriminator(discriminatorKey, discriminatorSchema); + schemaType.discriminator(discriminatorKey, discriminatorSchema, options); } schemaType._appliedDiscriminators = true; } diff --git a/lib/index.js b/lib/index.js index 641e19fe876..38197ec50ae 100644 --- a/lib/index.js +++ b/lib/index.js @@ -628,7 +628,11 @@ Mongoose.prototype._model = function(name, schema, collection, options) { if (schema._applyDiscriminators != null) { for (const disc of schema._applyDiscriminators.keys()) { - model.discriminator(disc, schema._applyDiscriminators.get(disc)); + const { + schema: discriminatorSchema, + options + } = schema._applyDiscriminators.get(disc); + model.discriminator(disc, discriminatorSchema, options); } } diff --git a/lib/schema.js b/lib/schema.js index 600e27208ee..ff6d505f7b0 100644 --- a/lib/schema.js +++ b/lib/schema.js @@ -624,12 +624,18 @@ Schema.prototype.defaultOptions = function(options) { * * @param {String} name the name of the discriminator * @param {Schema} schema the discriminated Schema + * @param {Object} [options] discriminator options + * @param {String} [options.value] the string stored in the `discriminatorKey` property. If not specified, Mongoose uses the `name` parameter. + * @param {Boolean} [options.clone=true] By default, `discriminator()` clones the given `schema`. Set to `false` to skip cloning. + * @param {Boolean} [options.overwriteModels=false] by default, Mongoose does not allow you to define a discriminator with the same name as another discriminator. Set this to allow overwriting discriminators with the same name. + * @param {Boolean} [options.mergeHooks=true] By default, Mongoose merges the base schema's hooks with the discriminator schema's hooks. Set this option to `false` to make Mongoose use the discriminator schema's hooks instead. + * @param {Boolean} [options.mergePlugins=true] By default, Mongoose merges the base schema's plugins with the discriminator schema's plugins. Set this option to `false` to make Mongoose use the discriminator schema's plugins instead. * @return {Schema} the Schema instance * @api public */ -Schema.prototype.discriminator = function(name, schema) { +Schema.prototype.discriminator = function(name, schema, options) { this._applyDiscriminators = this._applyDiscriminators || new Map(); - this._applyDiscriminators.set(name, schema); + this._applyDiscriminators.set(name, { schema, options }); return this; }; diff --git a/test/schema.test.js b/test/schema.test.js index 0df19a65790..074c6ddc760 100644 --- a/test/schema.test.js +++ b/test/schema.test.js @@ -72,6 +72,7 @@ describe('schema', function() { }, b: { $type: String } }, { typeKey: '$type' }); + db.deleteModel(/Test/); NestedModel = db.model('Test', NestedSchema); }); @@ -3202,4 +3203,22 @@ describe('schema', function() { const doc = new baseModel({ type: 1, self: [{ type: 1 }] }); assert.equal(doc.self[0].type, 1); }); + + it('handles discriminator options with Schema.prototype.discriminator (gh-14448)', async function() { + const eventSchema = new mongoose.Schema({ + name: String + }, { discriminatorKey: 'kind' }); + const clickedEventSchema = new mongoose.Schema({ element: String }); + eventSchema.discriminator( + 'Test2', + clickedEventSchema, + { value: 'click' } + ); + const Event = db.model('Test', eventSchema); + const ClickedModel = db.model('Test2'); + + const doc = await Event.create({ kind: 'click', element: '#hero' }); + assert.equal(doc.element, '#hero'); + assert.ok(doc instanceof ClickedModel); + }); });