diff --git a/index.js b/index.js index 029571e..82cab92 100644 --- a/index.js +++ b/index.js @@ -12,9 +12,7 @@ var indexesCache = {}; * @return {bool} True if and only if it is an unique error. */ function isUniqueError(err) { - return err - && (err.name === 'BulkWriteError' || err.name === 'MongoError') - && (err.code === 11000 || err.code === 11001); + return err && ['BulkWriteError', 'MongoError', 'MongoServerError'].includes(err.name) && (err.code === 11000 || err.code === 11001); } /** @@ -29,20 +27,14 @@ function isUniqueError(err) { * @return {*} Matching value, or undefined if none. */ function getValueByPath(obj, path) { - var segments = path.split('.'); - var result = obj; - - for ( - var i = 0; - i < segments.length - && result !== null - && result !== undefined; - ++i - ) { - result = result[segments[i]]; - } + var segments = path.split('.'); + var result = obj; + + for (var i = 0; i < segments.length && result !== null && result !== undefined; ++i) { + result = result[segments[i]]; + } - return result; + return result; } /** @@ -53,34 +45,31 @@ function getValueByPath(obj, path) { * @return {Object} Map of collected messages. */ function collectMessages(tree) { - var result = {}; - - for (var key in tree) { - if (tree.hasOwnProperty(key)) { - if ( - typeof tree[key] === 'object' - && tree[key] !== null - ) { - if (typeof tree[key].unique === 'string') { - // Schema property that has a custom - // unique message - result[key] = tree[key].unique; - tree[key].unique = true; - } else { - // Nested schema - var subtree = collectMessages(tree[key]); - - for (var subkey in subtree) { - if (subtree.hasOwnProperty(subkey)) { - result[key + '.' + subkey] = subtree[subkey]; - } - } - } + var result = {}; + + for (var key in tree) { + if (tree.hasOwnProperty(key)) { + if (typeof tree[key] === 'object' && tree[key] !== null) { + if (typeof tree[key].unique === 'string') { + // Schema property that has a custom + // unique message + result[key] = tree[key].unique; + tree[key].unique = true; + } else { + // Nested schema + var subtree = collectMessages(tree[key]); + + for (var subkey in subtree) { + if (subtree.hasOwnProperty(subkey)) { + result[key + '.' + subkey] = subtree[subkey]; } + } } + } } + } - return result; + return result; } /** @@ -91,22 +80,22 @@ function collectMessages(tree) { * @return {Promise} Resolved with index information data. */ function getIndexes(collection) { - return new global.Promise(function (resolve, reject) { - if (indexesCache[collection.name]) { - resolve(indexesCache[collection.name]); - return; - } + return new global.Promise(function (resolve, reject) { + if (indexesCache[collection.name]) { + resolve(indexesCache[collection.name]); + return; + } - collection.indexInformation(function (dbErr, indexes) { - if (dbErr) { - reject(dbErr); - return; - } + collection.indexInformation(function (dbErr, indexes) { + if (dbErr) { + reject(dbErr); + return; + } - indexesCache[collection.name] = indexes; - resolve(indexes); - }); + indexesCache[collection.name] = indexes; + resolve(indexes); }); + }); } /** @@ -121,126 +110,119 @@ function getIndexes(collection) { * @return {Promise.} Beautified error message */ function beautify(error, collection, values, messages, defaultMessage) { - // Try to recover the list of duplicated fields - var onSuberrors = global.Promise.resolve({}); - - // Extract the failed duplicate index's name from the - // from the error message (with a hacky regex) - var matches = errorRegex.exec(error.message); - - if (matches) { - var indexName = matches[1]; - - // Retrieve that index's list of fields - onSuberrors = getIndexes(collection).then(function (indexes) { - var suberrors = {}; - - // Create a suberror per duplicated field - if (indexName in indexes) { - indexes[indexName].forEach(function (field) { - var path = field[0]; - var props = { - type: 'unique', - path: path, - value: getValueByPath(values, path), - message: typeof messages[path] === 'string' - ? messages[path] : defaultMessage - }; - - suberrors[path] = new mongoose.Error.ValidatorError(props); - }); - } - - return suberrors; + // Try to recover the list of duplicated fields + var onSuberrors = global.Promise.resolve({}); + + // Extract the failed duplicate index's name from the + // from the error message (with a hacky regex) + var matches = errorRegex.exec(error.message); + + if (matches) { + var indexName = matches[1]; + + // Retrieve that index's list of fields + onSuberrors = getIndexes(collection).then(function (indexes) { + var suberrors = {}; + + // Create a suberror per duplicated field + if (indexName in indexes) { + indexes[indexName].forEach(function (field) { + var path = field[0]; + var props = { + type: 'unique', + path: path, + value: getValueByPath(values, path), + message: typeof messages[path] === 'string' ? messages[path] : defaultMessage, + }; + + suberrors[path] = new mongoose.Error.ValidatorError(props); }); - } - - return onSuberrors.then(function (suberrors) { - var beautifiedError = new mongoose.Error.ValidationError(); + } - beautifiedError.errors = suberrors; - return beautifiedError; + return suberrors; }); + } + + return onSuberrors.then(function (suberrors) { + var beautifiedError = new mongoose.Error.ValidationError(); + + beautifiedError.errors = suberrors; + return beautifiedError; + }); } module.exports = function (schema, options) { - options = options || {}; + options = options || {}; - if (!options.defaultMessage) { - options.defaultMessage = 'Path `{PATH}` ({VALUE}) is not unique.'; - } + if (!options.defaultMessage) { + options.defaultMessage = 'Path `{PATH}` ({VALUE}) is not unique.'; + } - // Fetch error messages defined in the "unique" field, - // store them for later use and replace them with true - var tree = schema.tree; - var messages = collectMessages(tree); + // Fetch error messages defined in the "unique" field, + // store them for later use and replace them with true + var tree = schema.tree; + var messages = collectMessages(tree); - schema._indexes.forEach(function (index) { - if (index[0] && index[1] && index[1].unique) { - Object.keys(index[0]).forEach(function (indexKey) { - messages[indexKey] = index[1].unique; - }); + schema._indexes.forEach(function (index) { + if (index[0] && index[1] && index[1].unique) { + Object.keys(index[0]).forEach(function (indexKey) { + messages[indexKey] = index[1].unique; + }); - index[1].unique = true; - } - }); + index[1].unique = true; + } + }); + + // Post hook that gets called after any save or update + // operation and that filters unique errors + var postHook = function (error, _, next) { + // Mongoose ≥5 does no longer pass the document as the + // second argument of 'update' hooks, so we use this instead + var doc = this; + + // If the next() function is missing, this might be + // a sign that we are using an outdated Mongoose + if (typeof next !== 'function') { + throw new Error( + 'mongoose-beautiful-unique-validation error: ' + + 'The hook was called incorrectly. Double check that ' + + 'you are using mongoose@>=4.5.0; if you need to use ' + + 'an outdated Mongoose version, please install this module ' + + 'in version 4.0.0' + ); + } - // Post hook that gets called after any save or update - // operation and that filters unique errors - var postHook = function (error, _, next) { - // Mongoose ≥5 does no longer pass the document as the - // second argument of 'update' hooks, so we use this instead - var doc = this; - - // If the next() function is missing, this might be - // a sign that we are using an outdated Mongoose - if (typeof next !== 'function') { - throw new Error( - 'mongoose-beautiful-unique-validation error: ' - + 'The hook was called incorrectly. Double check that ' - + 'you are using mongoose@>=4.5.0; if you need to use ' - + 'an outdated Mongoose version, please install this module ' - + 'in version 4.0.0' - ); - } + if (isUniqueError(error)) { + // Beautify unicity constraint failure errors + var collection, values; - if (isUniqueError(error)) { - // Beautify unicity constraint failure errors - var collection, values; - - if (this.constructor.name == 'Query') { - collection = this.model.collection; - values = this._update; - - if ('$set' in values) { - values = Object.assign({}, values, values.$set); - delete values.$set; - } - } else { - collection = doc.collection; - values = doc; - } + if (this.constructor.name == 'Query') { + collection = this.model.collection; + values = this._update; - beautify( - error, collection, values, - messages, options.defaultMessage - ) - .then(next) - .catch(function (beautifyError) { - setTimeout(function () { - throw new Error( - 'mongoose-beautiful-unique-validation error: ' - + beautifyError.stack - ); - }); - }); - } else { - // Pass over other errors - next(error); + if ('$set' in values) { + values = Object.assign({}, values, values.$set); + delete values.$set; } - }; + } else { + collection = doc.collection; + values = doc; + } + + beautify(error, collection, values, messages, options.defaultMessage) + .then(next) + .catch(function (beautifyError) { + setTimeout(function () { + throw new Error('mongoose-beautiful-unique-validation error: ' + beautifyError.stack); + }); + }); + } else { + // Pass over other errors + next(error); + } + }; - schema.post('save', postHook); - schema.post('update', postHook); - schema.post('findOneAndUpdate', postHook); + schema.post('save', postHook); + schema.post('update', postHook); + schema.post('findOneAndUpdate', postHook); }; diff --git a/package.json b/package.json index 75708c7..84cc54c 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "mongoose-beautiful-unique-validation", "description": "Plugin for Mongoose that turns duplicate errors into regular Mongoose validation errors", - "version": "7.1.1", + "version": "7.1.2", "license": "MIT", "main": "index.js", "repository": { "type": "git", - "url": "https://github.com/matteodelabre/mongoose-beautiful-unique-validation.git" + "url": "https://github.com/OguzBey/mongoose-beautiful-unique-validation.git" }, "scripts": { "test": "tape tests | tap-spec", @@ -23,9 +23,9 @@ "unique" ], "author": { - "name": "Mattéo Delabre ✏️", - "email": "contact@matteodelabre.me", - "url": "https://github.com/matteodelabre" + "name": "Oğuzhan", + "email": "cfmelun@gmail.com", + "url": "https://github.com/OguzBey" }, "peerDependencies": { "mongoose": ">=4.11.4"