diff --git a/lib/error/validator.js b/lib/error/validator.js index 6d54fe7f4f7..4ca7316d7bf 100644 --- a/lib/error/validator.js +++ b/lib/error/validator.js @@ -12,15 +12,16 @@ class ValidatorError extends MongooseError { * Schema validator error * * @param {Object} properties + * @param {Document} doc * @api private */ - constructor(properties) { + constructor(properties, doc) { let msg = properties.message; if (!msg) { msg = MongooseError.messages.general.default; } - const message = formatMessage(msg, properties); + const message = formatMessage(msg, properties, doc); super(message); properties = Object.assign({}, properties, { message: message }); @@ -75,9 +76,9 @@ ValidatorError.prototype.formatMessage = formatMessage; * @api private */ -function formatMessage(msg, properties) { +function formatMessage(msg, properties, doc) { if (typeof msg === 'function') { - return msg(properties); + return msg(properties, doc); } const propertyNames = Object.keys(properties); diff --git a/lib/schematype.js b/lib/schematype.js index 21d2f034755..6c1863febe5 100644 --- a/lib/schematype.js +++ b/lib/schematype.js @@ -1290,7 +1290,7 @@ SchemaType.prototype.doValidate = function(value, fn, scope, options) { validatorProperties.value = value; if (validator instanceof RegExp) { - validate(validator.test(value), validatorProperties); + validate(validator.test(value), validatorProperties, scope); continue; } @@ -1299,7 +1299,7 @@ SchemaType.prototype.doValidate = function(value, fn, scope, options) { } if (value === undefined && validator !== this.requiredValidator) { - validate(true, validatorProperties); + validate(true, validatorProperties, scope); continue; } @@ -1319,19 +1319,19 @@ SchemaType.prototype.doValidate = function(value, fn, scope, options) { if (ok != null && typeof ok.then === 'function') { ok.then( - function(ok) { validate(ok, validatorProperties); }, + function(ok) { validate(ok, validatorProperties, scope); }, function(error) { validatorProperties.reason = error; validatorProperties.message = error.message; ok = false; - validate(ok, validatorProperties); + validate(ok, validatorProperties, scope); }); } else { - validate(ok, validatorProperties); + validate(ok, validatorProperties, scope); } } - function validate(ok, validatorProperties) { + function validate(ok, validatorProperties, scope) { if (err) { return; } @@ -1343,7 +1343,7 @@ SchemaType.prototype.doValidate = function(value, fn, scope, options) { } } else { const ErrorConstructor = validatorProperties.ErrorConstructor || ValidatorError; - err = new ErrorConstructor(validatorProperties); + err = new ErrorConstructor(validatorProperties, scope); err[validatorErrorSymbol] = true; immediate(function() { fn(err); diff --git a/test/schema.validation.test.js b/test/schema.validation.test.js index 0d292339aca..8fc34312119 100644 --- a/test/schema.validation.test.js +++ b/test/schema.validation.test.js @@ -1330,6 +1330,33 @@ describe('schema', function() { }); }); + it('Allows for doc to be passed as another parameter gh-12564', function(done) { + let document = ''; + const s = mongoose.Schema({ + n: { + type: String, + validate: { + validator: function(v) { + return v != null; + }, + message: function(properties, doc) { + document = doc.toString(); + return 'fail ' + properties.path + ' on doc ' + doc; + } + } + }, + field: String + }); + const M = mongoose.model('gh-12564', s); + const m = new M({ n: null, field: 'Yo' }); + + m.validate(function(error) { + assert.equal(error.errors['n'].message.includes(document), true); + assert.equal('fail n on doc ' + document, error.errors['n'].message); + done(); + }); + }); + it('evaluate message function for required field gh6523', function(done) { const s = mongoose.Schema({ n: {