diff --git a/lib/schemaType.js b/lib/schemaType.js index e3caa4ff03..74d713795d 100644 --- a/lib/schemaType.js +++ b/lib/schemaType.js @@ -803,6 +803,21 @@ SchemaType.prototype.get = function(fn) { return this; }; +/** + * Adds multiple validators for this document path. + * Calls `validate()` for every element in validators. + * + * @param {Array} validators + * @returns this + */ + +SchemaType.prototype.validateAll = function(validators) { + for (let i = 0; i < validators.length; i++) { + this.validate(validators[i]); + } + return this; +}; + /** * Adds validator(s) for this document path. * @@ -1285,6 +1300,9 @@ SchemaType.prototype.select = function select(val) { SchemaType.prototype.doValidate = function(value, fn, scope, options) { let err = false; const path = this.path; + if (typeof fn !== 'function') { + throw new TypeError(`Must pass callback function to doValidate(), got ${typeof fn}`); + } // Avoid non-object `validators` const validators = this.validators. @@ -1419,7 +1437,6 @@ SchemaType.prototype.doValidateSync = function(value, scope, options) { let i = 0; const len = validators.length; for (i = 0; i < len; ++i) { - const v = validators[i]; if (v === null || typeof v !== 'object') { diff --git a/test/schematype.test.js b/test/schematype.test.js index 582a135c09..ad8367d0f6 100644 --- a/test/schematype.test.js +++ b/test/schematype.test.js @@ -281,4 +281,38 @@ describe('schematype', function() { }); }); }); + it('demonstrates the `validateAll()` function (gh-6910)', function() { + const validateSchema = new Schema({ name: String, password: String }); + validateSchema.path('name').validate({ + validator: function(v) { + return v.length > 5; + }, + message: 'name must be longer than 5 characters' + }); + validateSchema.path('password').validateAll([ + { + validator: function(v) { + return this.name !== v; + }, + message: 'password must not equal name' + }, + { + validator: function(v) { + return v.length > 5; + }, + message: 'password must be at least six characters' + } + ]); + assert.equal(validateSchema.path('password').validators.length, 2); + + const passwordPath = validateSchema.path('password'); + assert.throws( + () => { throw passwordPath.doValidateSync('john', { name: 'john' }); }, + /password must not equal name/ + ); + assert.throws( + () => { throw passwordPath.doValidateSync('short', { name: 'john' }); }, + /password must be at least six characters/ + ); + }); }); diff --git a/types/schematypes.d.ts b/types/schematypes.d.ts index 088bc27c59..9cb4834300 100644 --- a/types/schematypes.d.ts +++ b/types/schematypes.d.ts @@ -192,10 +192,14 @@ declare module 'mongoose' { [other: string]: any; } - interface Validator { - message?: string; type?: string; validator?: Function + interface Validator { + message?: string; + type?: string; + validator?: ValidatorFunction; } + type ValidatorFunction = (this: DocType, value: any, validatorProperties?: Validator) => any; + class SchemaType { /** SchemaType constructor */ constructor(path: string, options?: AnyObject, instance?: string); @@ -281,7 +285,10 @@ declare module 'mongoose' { validators: Validator[]; /** Adds validator(s) for this document path. */ - validate(obj: RegExp | ((this: DocType, value: any, validatorProperties?: Validator) => any), errorMsg?: string, type?: string): this; + validate(obj: RegExp | ValidatorFunction | Validator, errorMsg?: string, type?: string): this; + + /** Adds multiple validators for this document path. */ + validateAll(validators: Array | Validator>): this; /** Default options for this SchemaType */ defaultOptions?: Record;