summaryrefslogtreecommitdiffstats
path: root/node_modules/mongoose/lib/helpers/model
diff options
context:
space:
mode:
authorGravatar Piotr Russ <mail@pruss.it> 2020-11-16 00:10:28 +0100
committerGravatar Piotr Russ <mail@pruss.it> 2020-11-16 00:10:28 +0100
commite06ec920f7a5d784e674c4c4b4e6d1da3dc7391d (patch)
tree55713f725f77b44ebfec86e4eec3ce33e71458ca /node_modules/mongoose/lib/helpers/model
downloadwebsite_creator-e06ec920f7a5d784e674c4c4b4e6d1da3dc7391d.tar.gz
website_creator-e06ec920f7a5d784e674c4c4b4e6d1da3dc7391d.tar.bz2
website_creator-e06ec920f7a5d784e674c4c4b4e6d1da3dc7391d.zip
api, login, auth
Diffstat (limited to 'node_modules/mongoose/lib/helpers/model')
-rw-r--r--node_modules/mongoose/lib/helpers/model/applyHooks.js135
-rw-r--r--node_modules/mongoose/lib/helpers/model/applyMethods.js56
-rw-r--r--node_modules/mongoose/lib/helpers/model/applyStaticHooks.js71
-rw-r--r--node_modules/mongoose/lib/helpers/model/applyStatics.js12
-rw-r--r--node_modules/mongoose/lib/helpers/model/castBulkWrite.js224
-rw-r--r--node_modules/mongoose/lib/helpers/model/discriminator.js205
6 files changed, 703 insertions, 0 deletions
diff --git a/node_modules/mongoose/lib/helpers/model/applyHooks.js b/node_modules/mongoose/lib/helpers/model/applyHooks.js
new file mode 100644
index 0000000..9570a36
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/model/applyHooks.js
@@ -0,0 +1,135 @@
+'use strict';
+
+const symbols = require('../../schema/symbols');
+const promiseOrCallback = require('../promiseOrCallback');
+
+/*!
+ * ignore
+ */
+
+module.exports = applyHooks;
+
+/*!
+ * ignore
+ */
+
+applyHooks.middlewareFunctions = [
+ 'deleteOne',
+ 'save',
+ 'validate',
+ 'remove',
+ 'updateOne',
+ 'init'
+];
+
+/*!
+ * Register hooks for this model
+ *
+ * @param {Model} model
+ * @param {Schema} schema
+ */
+
+function applyHooks(model, schema, options) {
+ options = options || {};
+
+ const kareemOptions = {
+ useErrorHandlers: true,
+ numCallbackParams: 1,
+ nullResultByDefault: true,
+ contextParameter: true
+ };
+ const objToDecorate = options.decorateDoc ? model : model.prototype;
+
+ model.$appliedHooks = true;
+ for (const key of Object.keys(schema.paths)) {
+ const type = schema.paths[key];
+ let childModel = null;
+ if (type.$isSingleNested) {
+ childModel = type.caster;
+ } else if (type.$isMongooseDocumentArray) {
+ childModel = type.Constructor;
+ } else {
+ continue;
+ }
+
+ if (childModel.$appliedHooks) {
+ continue;
+ }
+
+ applyHooks(childModel, type.schema, options);
+ if (childModel.discriminators != null) {
+ const keys = Object.keys(childModel.discriminators);
+ for (const key of keys) {
+ applyHooks(childModel.discriminators[key],
+ childModel.discriminators[key].schema, options);
+ }
+ }
+ }
+
+ // Built-in hooks rely on hooking internal functions in order to support
+ // promises and make it so that `doc.save.toString()` provides meaningful
+ // information.
+
+ const middleware = schema.s.hooks.
+ filter(hook => {
+ if (hook.name === 'updateOne' || hook.name === 'deleteOne') {
+ return !!hook['document'];
+ }
+ if (hook.name === 'remove' || hook.name === 'init') {
+ return hook['document'] == null || !!hook['document'];
+ }
+ return true;
+ }).
+ filter(hook => {
+ // If user has overwritten the method, don't apply built-in middleware
+ if (schema.methods[hook.name]) {
+ return !hook.fn[symbols.builtInMiddleware];
+ }
+
+ return true;
+ });
+
+ model._middleware = middleware;
+
+ objToDecorate.$__originalValidate = objToDecorate.$__originalValidate || objToDecorate.$__validate;
+
+ for (const method of ['save', 'validate', 'remove', 'deleteOne']) {
+ const toWrap = method === 'validate' ? '$__originalValidate' : `$__${method}`;
+ const wrapped = middleware.
+ createWrapper(method, objToDecorate[toWrap], null, kareemOptions);
+ objToDecorate[`$__${method}`] = wrapped;
+ }
+ objToDecorate.$__init = middleware.
+ createWrapperSync('init', objToDecorate.$__init, null, kareemOptions);
+
+ // Support hooks for custom methods
+ const customMethods = Object.keys(schema.methods);
+ const customMethodOptions = Object.assign({}, kareemOptions, {
+ // Only use `checkForPromise` for custom methods, because mongoose
+ // query thunks are not as consistent as I would like about returning
+ // a nullish value rather than the query. If a query thunk returns
+ // a query, `checkForPromise` causes infinite recursion
+ checkForPromise: true
+ });
+ for (const method of customMethods) {
+ if (!middleware.hasHooks(method)) {
+ // Don't wrap if there are no hooks for the custom method to avoid
+ // surprises. Also, `createWrapper()` enforces consistent async,
+ // so wrapping a sync method would break it.
+ continue;
+ }
+ const originalMethod = objToDecorate[method];
+ objToDecorate[method] = function() {
+ const args = Array.prototype.slice.call(arguments);
+ const cb = args.slice(-1).pop();
+ const argsWithoutCallback = typeof cb === 'function' ?
+ args.slice(0, args.length - 1) : args;
+ return promiseOrCallback(cb, callback => {
+ return this[`$__${method}`].apply(this,
+ argsWithoutCallback.concat([callback]));
+ }, model.events);
+ };
+ objToDecorate[`$__${method}`] = middleware.
+ createWrapper(method, originalMethod, null, customMethodOptions);
+ }
+} \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/model/applyMethods.js b/node_modules/mongoose/lib/helpers/model/applyMethods.js
new file mode 100644
index 0000000..912f3aa
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/model/applyMethods.js
@@ -0,0 +1,56 @@
+'use strict';
+
+const get = require('../get');
+
+/*!
+ * Register methods for this model
+ *
+ * @param {Model} model
+ * @param {Schema} schema
+ */
+
+module.exports = function applyMethods(model, schema) {
+ function apply(method, schema) {
+ Object.defineProperty(model.prototype, method, {
+ get: function() {
+ const h = {};
+ for (const k in schema.methods[method]) {
+ h[k] = schema.methods[method][k].bind(this);
+ }
+ return h;
+ },
+ configurable: true
+ });
+ }
+ for (const method of Object.keys(schema.methods)) {
+ const fn = schema.methods[method];
+ if (schema.tree.hasOwnProperty(method)) {
+ throw new Error('You have a method and a property in your schema both ' +
+ 'named "' + method + '"');
+ }
+ if (schema.reserved[method] &&
+ !get(schema, `methodOptions.${method}.suppressWarning`, false)) {
+ console.warn(`mongoose: the method name "${method}" is used by mongoose ` +
+ 'internally, overwriting it may cause bugs. If you\'re sure you know ' +
+ 'what you\'re doing, you can suppress this error by using ' +
+ `\`schema.method('${method}', fn, { suppressWarning: true })\`.`);
+ }
+ if (typeof fn === 'function') {
+ model.prototype[method] = fn;
+ } else {
+ apply(method, schema);
+ }
+ }
+
+ // Recursively call `applyMethods()` on child schemas
+ model.$appliedMethods = true;
+ for (const key of Object.keys(schema.paths)) {
+ const type = schema.paths[key];
+ if (type.$isSingleNested && !type.caster.$appliedMethods) {
+ applyMethods(type.caster, type.schema);
+ }
+ if (type.$isMongooseDocumentArray && !type.Constructor.$appliedMethods) {
+ applyMethods(type.Constructor, type.schema);
+ }
+ }
+};
diff --git a/node_modules/mongoose/lib/helpers/model/applyStaticHooks.js b/node_modules/mongoose/lib/helpers/model/applyStaticHooks.js
new file mode 100644
index 0000000..219e289
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/model/applyStaticHooks.js
@@ -0,0 +1,71 @@
+'use strict';
+
+const middlewareFunctions = require('../query/applyQueryMiddleware').middlewareFunctions;
+const promiseOrCallback = require('../promiseOrCallback');
+
+module.exports = function applyStaticHooks(model, hooks, statics) {
+ const kareemOptions = {
+ useErrorHandlers: true,
+ numCallbackParams: 1
+ };
+
+ hooks = hooks.filter(hook => {
+ // If the custom static overwrites an existing query middleware, don't apply
+ // middleware to it by default. This avoids a potential backwards breaking
+ // change with plugins like `mongoose-delete` that use statics to overwrite
+ // built-in Mongoose functions.
+ if (middlewareFunctions.indexOf(hook.name) !== -1) {
+ return !!hook.model;
+ }
+ return hook.model !== false;
+ });
+
+ model.$__insertMany = hooks.createWrapper('insertMany',
+ model.$__insertMany, model, kareemOptions);
+
+ for (const key of Object.keys(statics)) {
+ if (hooks.hasHooks(key)) {
+ const original = model[key];
+
+ model[key] = function() {
+ const numArgs = arguments.length;
+ const lastArg = numArgs > 0 ? arguments[numArgs - 1] : null;
+ const cb = typeof lastArg === 'function' ? lastArg : null;
+ const args = Array.prototype.slice.
+ call(arguments, 0, cb == null ? numArgs : numArgs - 1);
+ // Special case: can't use `Kareem#wrap()` because it doesn't currently
+ // support wrapped functions that return a promise.
+ return promiseOrCallback(cb, callback => {
+ hooks.execPre(key, model, args, function(err) {
+ if (err != null) {
+ return callback(err);
+ }
+
+ let postCalled = 0;
+ const ret = original.apply(model, args.concat(post));
+ if (ret != null && typeof ret.then === 'function') {
+ ret.then(res => post(null, res), err => post(err));
+ }
+
+ function post(error, res) {
+ if (postCalled++ > 0) {
+ return;
+ }
+
+ if (error != null) {
+ return callback(error);
+ }
+
+ hooks.execPost(key, model, [res], function(error) {
+ if (error != null) {
+ return callback(error);
+ }
+ callback(null, res);
+ });
+ }
+ });
+ }, model.events);
+ };
+ }
+ }
+}; \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/model/applyStatics.js b/node_modules/mongoose/lib/helpers/model/applyStatics.js
new file mode 100644
index 0000000..3b9501e
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/model/applyStatics.js
@@ -0,0 +1,12 @@
+'use strict';
+
+/*!
+ * Register statics for this model
+ * @param {Model} model
+ * @param {Schema} schema
+ */
+module.exports = function applyStatics(model, schema) {
+ for (const i in schema.statics) {
+ model[i] = schema.statics[i];
+ }
+};
diff --git a/node_modules/mongoose/lib/helpers/model/castBulkWrite.js b/node_modules/mongoose/lib/helpers/model/castBulkWrite.js
new file mode 100644
index 0000000..6e7a830
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/model/castBulkWrite.js
@@ -0,0 +1,224 @@
+'use strict';
+
+const getDiscriminatorByValue = require('../../helpers/discriminator/getDiscriminatorByValue');
+const applyTimestampsToChildren = require('../update/applyTimestampsToChildren');
+const applyTimestampsToUpdate = require('../update/applyTimestampsToUpdate');
+const cast = require('../../cast');
+const castUpdate = require('../query/castUpdate');
+const setDefaultsOnInsert = require('../setDefaultsOnInsert');
+
+/*!
+ * Given a model and a bulkWrite op, return a thunk that handles casting and
+ * validating the individual op.
+ */
+
+module.exports = function castBulkWrite(originalModel, op, options) {
+ const now = originalModel.base.now();
+
+ if (op['insertOne']) {
+ return (callback) => {
+ const model = decideModelByObject(originalModel, op['insertOne']['document']);
+
+ const doc = new model(op['insertOne']['document']);
+ if (model.schema.options.timestamps != null) {
+ doc.initializeTimestamps();
+ }
+ if (options.session != null) {
+ doc.$session(options.session);
+ }
+ op['insertOne']['document'] = doc;
+ op['insertOne']['document'].validate({ __noPromise: true }, function(error) {
+ if (error) {
+ return callback(error, null);
+ }
+ callback(null);
+ });
+ };
+ } else if (op['updateOne']) {
+ return (callback) => {
+ try {
+ if (!op['updateOne']['filter']) {
+ throw new Error('Must provide a filter object.');
+ }
+ if (!op['updateOne']['update']) {
+ throw new Error('Must provide an update object.');
+ }
+
+ const model = decideModelByObject(originalModel, op['updateOne']['filter']);
+ const schema = model.schema;
+ const strict = options.strict != null ? options.strict : model.schema.options.strict;
+
+ _addDiscriminatorToObject(schema, op['updateOne']['filter']);
+
+ if (model.schema.$timestamps != null && op['updateOne'].timestamps !== false) {
+ const createdAt = model.schema.$timestamps.createdAt;
+ const updatedAt = model.schema.$timestamps.updatedAt;
+ applyTimestampsToUpdate(now, createdAt, updatedAt, op['updateOne']['update'], {});
+ }
+
+ applyTimestampsToChildren(now, op['updateOne']['update'], model.schema);
+
+ if (op['updateOne'].setDefaultsOnInsert) {
+ setDefaultsOnInsert(op['updateOne']['filter'], model.schema, op['updateOne']['update'], {
+ setDefaultsOnInsert: true,
+ upsert: op['updateOne'].upsert
+ });
+ }
+
+ op['updateOne']['filter'] = cast(model.schema, op['updateOne']['filter'], {
+ strict: strict,
+ upsert: op['updateOne'].upsert
+ });
+
+ op['updateOne']['update'] = castUpdate(model.schema, op['updateOne']['update'], {
+ strict: strict,
+ overwrite: false,
+ upsert: op['updateOne'].upsert
+ }, model, op['updateOne']['filter']);
+ } catch (error) {
+ return callback(error, null);
+ }
+
+ callback(null);
+ };
+ } else if (op['updateMany']) {
+ return (callback) => {
+ try {
+ if (!op['updateMany']['filter']) {
+ throw new Error('Must provide a filter object.');
+ }
+ if (!op['updateMany']['update']) {
+ throw new Error('Must provide an update object.');
+ }
+
+ const model = decideModelByObject(originalModel, op['updateMany']['filter']);
+ const schema = model.schema;
+ const strict = options.strict != null ? options.strict : model.schema.options.strict;
+
+ if (op['updateMany'].setDefaultsOnInsert) {
+ setDefaultsOnInsert(op['updateMany']['filter'], model.schema, op['updateMany']['update'], {
+ setDefaultsOnInsert: true,
+ upsert: op['updateMany'].upsert
+ });
+ }
+
+ if (model.schema.$timestamps != null && op['updateMany'].timestamps !== false) {
+ const createdAt = model.schema.$timestamps.createdAt;
+ const updatedAt = model.schema.$timestamps.updatedAt;
+ applyTimestampsToUpdate(now, createdAt, updatedAt, op['updateMany']['update'], {});
+ }
+
+ applyTimestampsToChildren(now, op['updateMany']['update'], model.schema);
+
+ _addDiscriminatorToObject(schema, op['updateMany']['filter']);
+
+ op['updateMany']['filter'] = cast(model.schema, op['updateMany']['filter'], {
+ strict: strict,
+ upsert: op['updateMany'].upsert
+ });
+
+ op['updateMany']['update'] = castUpdate(model.schema, op['updateMany']['update'], {
+ strict: strict,
+ overwrite: false,
+ upsert: op['updateMany'].upsert
+ }, model, op['updateMany']['filter']);
+
+ } catch (error) {
+ return callback(error, null);
+ }
+
+ callback(null);
+ };
+ } else if (op['replaceOne']) {
+ return (callback) => {
+ const model = decideModelByObject(originalModel, op['replaceOne']['filter']);
+ const schema = model.schema;
+ const strict = options.strict != null ? options.strict : model.schema.options.strict;
+
+ _addDiscriminatorToObject(schema, op['replaceOne']['filter']);
+ try {
+ op['replaceOne']['filter'] = cast(model.schema, op['replaceOne']['filter'], {
+ strict: strict,
+ upsert: op['replaceOne'].upsert
+ });
+ } catch (error) {
+ return callback(error, null);
+ }
+
+ // set `skipId`, otherwise we get "_id field cannot be changed"
+ const doc = new model(op['replaceOne']['replacement'], strict, true);
+ if (model.schema.options.timestamps != null) {
+ doc.initializeTimestamps();
+ }
+ if (options.session != null) {
+ doc.$session(options.session);
+ }
+ op['replaceOne']['replacement'] = doc;
+
+ op['replaceOne']['replacement'].validate({ __noPromise: true }, function(error) {
+ if (error) {
+ return callback(error, null);
+ }
+ op['replaceOne']['replacement'] = op['replaceOne']['replacement'].toBSON();
+ callback(null);
+ });
+ };
+ } else if (op['deleteOne']) {
+ return (callback) => {
+ const model = decideModelByObject(originalModel, op['deleteOne']['filter']);
+ const schema = model.schema;
+
+ _addDiscriminatorToObject(schema, op['deleteOne']['filter']);
+
+ try {
+ op['deleteOne']['filter'] = cast(model.schema,
+ op['deleteOne']['filter']);
+ } catch (error) {
+ return callback(error, null);
+ }
+
+ callback(null);
+ };
+ } else if (op['deleteMany']) {
+ return (callback) => {
+ const model = decideModelByObject(originalModel, op['deleteMany']['filter']);
+ const schema = model.schema;
+
+ _addDiscriminatorToObject(schema, op['deleteMany']['filter']);
+
+ try {
+ op['deleteMany']['filter'] = cast(model.schema,
+ op['deleteMany']['filter']);
+ } catch (error) {
+ return callback(error, null);
+ }
+
+ callback(null);
+ };
+ } else {
+ return (callback) => {
+ callback(new Error('Invalid op passed to `bulkWrite()`'), null);
+ };
+ }
+};
+
+function _addDiscriminatorToObject(schema, obj) {
+ if (schema == null) {
+ return;
+ }
+ if (schema.discriminatorMapping && !schema.discriminatorMapping.isRoot) {
+ obj[schema.discriminatorMapping.key] = schema.discriminatorMapping.value;
+ }
+}
+
+/*!
+ * gets discriminator model if discriminator key is present in object
+ */
+
+function decideModelByObject(model, object) {
+ const discriminatorKey = model.schema.options.discriminatorKey;
+ if (object != null && object.hasOwnProperty(discriminatorKey)) {
+ model = getDiscriminatorByValue(model, object[discriminatorKey]) || model;
+ }
+ return model;
+} \ No newline at end of file
diff --git a/node_modules/mongoose/lib/helpers/model/discriminator.js b/node_modules/mongoose/lib/helpers/model/discriminator.js
new file mode 100644
index 0000000..2ad4c5e
--- /dev/null
+++ b/node_modules/mongoose/lib/helpers/model/discriminator.js
@@ -0,0 +1,205 @@
+'use strict';
+
+const Mixed = require('../../schema/mixed');
+const defineKey = require('../document/compile').defineKey;
+const get = require('../get');
+const utils = require('../../utils');
+
+const CUSTOMIZABLE_DISCRIMINATOR_OPTIONS = {
+ toJSON: true,
+ toObject: true,
+ _id: true,
+ id: true
+};
+
+/*!
+ * ignore
+ */
+
+module.exports = function discriminator(model, name, schema, tiedValue, applyPlugins) {
+ if (!(schema && schema.instanceOfSchema)) {
+ throw new Error('You must pass a valid discriminator Schema');
+ }
+
+ if (model.schema.discriminatorMapping &&
+ !model.schema.discriminatorMapping.isRoot) {
+ throw new Error('Discriminator "' + name +
+ '" can only be a discriminator of the root model');
+ }
+
+ if (applyPlugins) {
+ const applyPluginsToDiscriminators = get(model.base,
+ 'options.applyPluginsToDiscriminators', false);
+ // Even if `applyPluginsToDiscriminators` isn't set, we should still apply
+ // global plugins to schemas embedded in the discriminator schema (gh-7370)
+ model.base._applyPlugins(schema, {
+ skipTopLevel: !applyPluginsToDiscriminators
+ });
+ }
+
+ const key = model.schema.options.discriminatorKey;
+
+ const existingPath = model.schema.path(key);
+ if (existingPath != null) {
+ if (!utils.hasUserDefinedProperty(existingPath.options, 'select')) {
+ existingPath.options.select = true;
+ }
+ existingPath.options.$skipDiscriminatorCheck = true;
+ } else {
+ const baseSchemaAddition = {};
+ baseSchemaAddition[key] = {
+ default: void 0,
+ select: true,
+ $skipDiscriminatorCheck: true
+ };
+ baseSchemaAddition[key][model.schema.options.typeKey] = String;
+ model.schema.add(baseSchemaAddition);
+ defineKey(key, null, model.prototype, null, [key], model.schema.options);
+ }
+
+ if (schema.path(key) && schema.path(key).options.$skipDiscriminatorCheck !== true) {
+ throw new Error('Discriminator "' + name +
+ '" cannot have field with name "' + key + '"');
+ }
+
+ let value = name;
+ if (typeof tiedValue == 'string' && tiedValue.length) {
+ value = tiedValue;
+ }
+
+ function merge(schema, baseSchema) {
+ // Retain original schema before merging base schema
+ schema._baseSchema = baseSchema;
+ if (baseSchema.paths._id &&
+ baseSchema.paths._id.options &&
+ !baseSchema.paths._id.options.auto) {
+ schema.remove('_id');
+ }
+
+ // Find conflicting paths: if something is a path in the base schema
+ // and a nested path in the child schema, overwrite the base schema path.
+ // See gh-6076
+ const baseSchemaPaths = Object.keys(baseSchema.paths);
+ const conflictingPaths = [];
+
+ for (const path of baseSchemaPaths) {
+ if (schema.nested[path]) {
+ conflictingPaths.push(path);
+ continue;
+ }
+
+ if (path.indexOf('.') === -1) {
+ continue;
+ }
+ const sp = path.split('.').slice(0, -1);
+ let cur = '';
+ for (const piece of sp) {
+ cur += (cur.length ? '.' : '') + piece;
+ if (schema.paths[cur] instanceof Mixed ||
+ schema.singleNestedPaths[cur] instanceof Mixed) {
+ conflictingPaths.push(path);
+ }
+ }
+ }
+
+ utils.merge(schema, baseSchema, {
+ isDiscriminatorSchemaMerge: true,
+ omit: { discriminators: true, base: true },
+ omitNested: conflictingPaths.reduce((cur, path) => {
+ cur['tree.' + path] = true;
+ return cur;
+ }, {})
+ });
+
+ // Clean up conflicting paths _after_ merging re: gh-6076
+ for (const conflictingPath of conflictingPaths) {
+ delete schema.paths[conflictingPath];
+ }
+
+ // Rebuild schema models because schemas may have been merged re: #7884
+ schema.childSchemas.forEach(obj => {
+ obj.model.prototype.$__setSchema(obj.schema);
+ });
+
+ const obj = {};
+ obj[key] = {
+ default: value,
+ select: true,
+ set: function(newName) {
+ if (newName === value) {
+ return value;
+ }
+ throw new Error('Can\'t set discriminator key "' + key + '"');
+ },
+ $skipDiscriminatorCheck: true
+ };
+ obj[key][schema.options.typeKey] = existingPath ?
+ existingPath.instance :
+ String;
+ schema.add(obj);
+ schema.discriminatorMapping = { key: key, value: value, isRoot: false };
+
+ if (baseSchema.options.collection) {
+ schema.options.collection = baseSchema.options.collection;
+ }
+
+ const toJSON = schema.options.toJSON;
+ const toObject = schema.options.toObject;
+ const _id = schema.options._id;
+ const id = schema.options.id;
+
+ const keys = Object.keys(schema.options);
+ schema.options.discriminatorKey = baseSchema.options.discriminatorKey;
+
+ for (const _key of keys) {
+ if (!CUSTOMIZABLE_DISCRIMINATOR_OPTIONS[_key]) {
+ // Special case: compiling a model sets `pluralization = true` by default. Avoid throwing an error
+ // for that case. See gh-9238
+ if (_key === 'pluralization' && schema.options[_key] == true && baseSchema.options[_key] == null) {
+ continue;
+ }
+
+ if (!utils.deepEqual(schema.options[_key], baseSchema.options[_key])) {
+ throw new Error('Can\'t customize discriminator option ' + _key +
+ ' (can only modify ' +
+ Object.keys(CUSTOMIZABLE_DISCRIMINATOR_OPTIONS).join(', ') +
+ ')');
+ }
+ }
+ }
+ schema.options = utils.clone(baseSchema.options);
+ if (toJSON) schema.options.toJSON = toJSON;
+ if (toObject) schema.options.toObject = toObject;
+ if (typeof _id !== 'undefined') {
+ schema.options._id = _id;
+ }
+ schema.options.id = id;
+ schema.s.hooks = model.schema.s.hooks.merge(schema.s.hooks);
+
+ schema.plugins = Array.prototype.slice.call(baseSchema.plugins);
+ schema.callQueue = baseSchema.callQueue.concat(schema.callQueue);
+ delete schema._requiredpaths; // reset just in case Schema#requiredPaths() was called on either schema
+ }
+
+ // merges base schema into new discriminator schema and sets new type field.
+ merge(schema, model.schema);
+
+ if (!model.discriminators) {
+ model.discriminators = {};
+ }
+
+ if (!model.schema.discriminatorMapping) {
+ model.schema.discriminatorMapping = { key: key, value: null, isRoot: true };
+ }
+ if (!model.schema.discriminators) {
+ model.schema.discriminators = {};
+ }
+
+ model.schema.discriminators[name] = schema;
+
+ if (model.discriminators[name]) {
+ throw new Error('Discriminator with name "' + name + '" already exists');
+ }
+
+ return schema;
+};