From f9daeb40796d374bb3999a8254f27a27b810493e Mon Sep 17 00:00:00 2001 From: Nick Baugh Date: Tue, 8 Aug 2017 02:24:37 -0400 Subject: [PATCH 1/4] Fixed default message formatter (closes #41) --- README.md | 26 ++++++++++++++++++++++---- index.js | 20 ++++++++++---------- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 758c729..c2aa4fb 100644 --- a/README.md +++ b/README.md @@ -180,17 +180,35 @@ The `errors` attribute contains a list of all original values that failed the un ### Error messages -By default, the `ValidatorError` message will be the formatted value of `mongoose.Error.messages.general.unique` (which is set automatically by this package if not already defined). +By default, the `ValidatorError` message will be the formatted value of a String `options.message` (which is set automatically by this package if not already defined). -The default value of `mongoose.Error.messages.general.unique` is ``"Path `{PATH}` ({VALUE}) is not unique."`` which adheres to [the Mongoose error message defaults](https://github.com/Automattic/mongoose/blob/master/lib/error/messages.js). +The default value of `options.message` is ``"Path `{PATH}` ({VALUE}) is not unique."`` which adheres to [the Mongoose error message defaults](https://github.com/Automattic/mongoose/blob/master/lib/error/messages.js). -If you want to override it, add your custom message in the `unique` field (instead of `true`), during the schema's creation (or) override the default global Mongoose error: +If you want to override it, you have two choices: + +1. Add your custom message in the `unique` field (instead of `true`), during the schema's creation: + +```diff +const userSchema = mongoose.Schema({ + name: { + type: String, ++ unique: 'Two users cannot share the same username ({VALUE})' +- unique: true + } +}); +``` + +2. Override the global default through `options.message` while initializing the schema plugin: ```js // change this however you'd like -mongoose.Error.messages.general.unique = 'Path `{PATH}` ({VALUE}) is not unique.'; +userSchema.plugin(beautifyUnique, { + message: "Path `{PATH}` ({VALUE}) is not unique." +}); ``` +> **Note**: Custom messages defined in the schema will always take precedence over the global default message. + ## Contributions This is free and open source software. All contributions (even small ones) are welcome. [Check out the contribution guide to get started!](CONTRIBUTING.md) diff --git a/index.js b/index.js index 290d8fb..468d5a3 100644 --- a/index.js +++ b/index.js @@ -2,12 +2,6 @@ var mongoose = require('mongoose'); -// Bind custom message for mongoose if it doesn't already exist -if (mongoose.Error.messages.general.unique === undefined) { - mongoose.Error.messages.general.unique = - 'Path `{PATH}` ({VALUE}) is not unique.'; -} - var errorRegex = /index:\s*(?:.+?\.\$)?(.*?)\s*dup/; var indexesCache = {}; @@ -56,9 +50,10 @@ function getIndexes(collection) { * @param {Collection} collection Mongoose collection. * @param {Object} values Hashmap containing data about duplicated values * @param {Object} messages Map fields to unique error messages + * @param {String} message Default message formatter string * @return {Promise.} Beautified error message */ -function beautify(error, collection, values, messages) { +function beautify(error, collection, values, messages, message) { // Try to recover the list of duplicated fields var onSuberrors = global.Promise.resolve({}); @@ -86,7 +81,7 @@ function beautify(error, collection, values, messages) { if (typeof messages[path] === 'string') { props.message = messages[path]; } else { - props.message = mongoose.Error.messages.general.unique; + props.message = message; } suberrors[path] = new mongoose.Error.ValidatorError(props); @@ -105,9 +100,14 @@ function beautify(error, collection, values, messages) { }); } -module.exports = function (schema) { +module.exports = function (schema, options) { var tree = schema.tree, key, messages = {}; + options = options || {}; + if (!options.message) { + options.message = 'Path `{PATH}` ({VALUE}) is not unique.'; + } + // Fetch error messages defined in the "unique" field, // store them for later use and replace them with true for (key in tree) { @@ -161,7 +161,7 @@ module.exports = function (schema) { values = doc; } - beautify(error, collection, values, messages) + beautify(error, collection, values, messages, options.message) .then(next) .catch(function (beautifyError) { setTimeout(function () { From 68194f0edec9aee49069ace3bf9b9e92a7814eab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matt=C3=A9o=20Delabre?= Date: Thu, 10 Aug 2017 12:07:58 +0200 Subject: [PATCH 2/4] Rename .message to .defaultMessage --- index.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/index.js b/index.js index 468d5a3..2d746e3 100644 --- a/index.js +++ b/index.js @@ -50,10 +50,10 @@ function getIndexes(collection) { * @param {Collection} collection Mongoose collection. * @param {Object} values Hashmap containing data about duplicated values * @param {Object} messages Map fields to unique error messages - * @param {String} message Default message formatter string + * @param {String} defaultMessage Default message formatter string * @return {Promise.} Beautified error message */ -function beautify(error, collection, values, messages, message) { +function beautify(error, collection, values, messages, defaultMessage) { // Try to recover the list of duplicated fields var onSuberrors = global.Promise.resolve({}); @@ -81,7 +81,7 @@ function beautify(error, collection, values, messages, message) { if (typeof messages[path] === 'string') { props.message = messages[path]; } else { - props.message = message; + props.message = defaultMessage; } suberrors[path] = new mongoose.Error.ValidatorError(props); @@ -104,8 +104,9 @@ module.exports = function (schema, options) { var tree = schema.tree, key, messages = {}; options = options || {}; - if (!options.message) { - options.message = '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, @@ -161,7 +162,10 @@ module.exports = function (schema, options) { values = doc; } - beautify(error, collection, values, messages, options.message) + beautify( + error, collection, values, + messages, options.defaultMessage + ) .then(next) .catch(function (beautifyError) { setTimeout(function () { From ff70f79a3262e67adf613e828d3e69e5071f80a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matt=C3=A9o=20Delabre?= Date: Thu, 10 Aug 2017 12:14:50 +0200 Subject: [PATCH 3/4] Add tests for default message override --- tests/save.js | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tests/save.js b/tests/save.js index 52977b0..ab9ce19 100644 --- a/tests/save.js +++ b/tests/save.js @@ -376,6 +376,47 @@ test('should use custom validation messages', function (t) { }); }); +test('should allow overriding the default validation message', function (t) { + var DefaultMessageSchema = new Schema({ + address: { + type: String, + unique: true + } + }); + + DefaultMessageSchema.plugin(beautifulValidation, { + defaultMessage: 'Default message override test, {PATH}' + }); + + var DefaultMessage = mongoose.model('DefaultMessage', DefaultMessageSchema); + + DefaultMessage.on('index', function (indexErr) { + t.error(indexErr, 'indexes should be built correctly'); + + new DefaultMessage({ + address: '123 Fake St.' + }).save().then(function () { + return new DefaultMessage({ + address: '123 Fake St.' + }).save(); + }, function (err) { + t.error(err, 'should save the first document successfully'); + t.end(); + }).then(function () { + t.fail('should not save the duplicate document successfully'); + t.end(); + }, function (err) { + assertUniqueError( + t, err, + {address: '123 Fake St.'}, + {address: 'Default message override test, address'} + ); + + t.end(); + }); + }); +}); + test('should use custom validation messages w/ compound', function (t) { var CompoundMessageSchema = new Schema({ name: String, From fb235f6a10774892d5b2b17aab3698fde1932275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matt=C3=A9o=20Delabre?= Date: Thu, 10 Aug 2017 12:25:21 +0200 Subject: [PATCH 4/4] Make the two ways of setting a custom message more explicit --- README.md | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index c2aa4fb..a1627bd 100644 --- a/README.md +++ b/README.md @@ -176,17 +176,13 @@ Schemata in which this module is plugged in will produce beautified duplication **You need to plug in this module after declaring all indexes on the schema, otherwise they will not be beautified.** -The `errors` attribute contains a list of all original values that failed the unique contraint. +The reported error has the same shape as normal validation errors. For each field that has a duplicate value, an item is added to the `errors` attribute. See examples above. ### Error messages -By default, the `ValidatorError` message will be the formatted value of a String `options.message` (which is set automatically by this package if not already defined). +By default, the validation error message will be ``Path `{PATH}` ({VALUE}) is not unique.``, with `{PATH}` replaced by the name of the duplicated field and `{VALUE}` by the value that already existed. -The default value of `options.message` is ``"Path `{PATH}` ({VALUE}) is not unique."`` which adheres to [the Mongoose error message defaults](https://github.com/Automattic/mongoose/blob/master/lib/error/messages.js). - -If you want to override it, you have two choices: - -1. Add your custom message in the `unique` field (instead of `true`), during the schema's creation: +To set a custom validation message on a particular path, add your message in the `unique` field (instead of `true`), during the schema's creation. ```diff const userSchema = mongoose.Schema({ @@ -198,12 +194,11 @@ const userSchema = mongoose.Schema({ }); ``` -2. Override the global default through `options.message` while initializing the schema plugin: +When using the plugin globally or with a schema that has several paths with unique values, you might want to override the default message value. You can do that through the `defaultMessage` option while adding the plugin. ```js -// change this however you'd like userSchema.plugin(beautifyUnique, { - message: "Path `{PATH}` ({VALUE}) is not unique." + defaultMessage: "This custom message will be used as the default" }); ```