diff --git a/index.js b/index.js index 85a5076..03ac666 100644 --- a/index.js +++ b/index.js @@ -2,4 +2,5 @@ module.exports = function(mongoose) { require('./lib/string-ext/max-length.js')(mongoose); require('./lib/string-ext/min-length.js')(mongoose); require('./lib/string-ext/exact-length.js')(mongoose); + require('./lib/number-ext/exclusive-min.js')(mongoose); }; diff --git a/lib/number-ext/exclusive-min.js b/lib/number-ext/exclusive-min.js new file mode 100644 index 0000000..e63b1f4 --- /dev/null +++ b/lib/number-ext/exclusive-min.js @@ -0,0 +1,55 @@ +module.exports = function(mongoose) { + var SchemaNumber = mongoose.SchemaTypes.Number, + errorMessages = mongoose.Error.messages; + + /** + * Sets a minimum number validator not including the configurated value. + * + * ####Example: + * + * var s = new Schema({ n: { type: Number, exclusivemin: 10 }) + * var M = db.model('M', s) + * var m = new M({ n: 9 }) + * m.save(function (err) { + * console.error(err) // validator error + * m.n = 10; + * m.save() // success + * }) + * + * // custom error messages + * // We can also use the special {EXCLUSIVE_MIN} token which will be replaced with the invalid value + * var min = [10, 'The value of path `{PATH}` ({VALUE}) should be greater than ({EXCLUSIVE_MIN}).']; + * var schema = new Schema({ n: { type: Number, min: min }) + * var M = mongoose.model('Measurement', schema); + * var s= new M({ n: 4 }); + * s.validate(function (err) { + * console.log(String(err)) // ValidationError: The value of path `n` (4) should be greater than 10. + * }) + * + * @param {Number} value minimum number + * @param {String} [message] optional custom error message + * @return {SchemaType} this + * @see Customized Error Messages #error_messages_MongooseError-messages + * @api public + */ + + SchemaNumber.prototype.exclusivemin = function (value, message) { + if (this.exclusiveminValidator) { + this.validators = this.validators.filter(function (v) { + return v.validator !== this.exclusiveminValidator; + }, this); + } + + if (null !== value) { + var msg = message || errorMessages.Number.exclusivemin; + msg = msg.replace(/{EXCLUSIVE_MIN}/, value); + this.validators.push([this.exclusiveminValidator = function (v) { + return v === null || v === undefined || v > value; + }, msg, 'exclusivemin']); + } + + return this; + }; + + errorMessages.Number.exclusivemin = 'Path `{PATH}` ({VALUE}) should be greater than {EXCLUSIVE_MIN}.'; +}; diff --git a/lib/string-ext/exact-length.js b/lib/string-ext/exact-length.js index 2484264..1f8512f 100644 --- a/lib/string-ext/exact-length.js +++ b/lib/string-ext/exact-length.js @@ -7,24 +7,25 @@ module.exports = function(mongoose) { * * ####Example: * - * var s = new Schema({ n: { type: String, exactlength: 4 }) - * var M = db.model('M', s) - * var m = new M({ n: 'teste' }) - * m.save(function (err) { - * console.error(err) // validator error - * m.n = 'test; - * m.save() // success - * }) + * var s = new Schema({ n: { type: String, exactlength: 4 }) + * var M = db.model('M', s) + * var m = new M({ n: 'teste' }) + * m.save(function (err) { + * console.error(err) // validator error + * m.n = 'test; + * m.save() // success + * }) * - * // custom error messages - * // We can also use the special {EXACT_LENGTH} token which will be replaced with the invalid value - * var max = [4, 'The length of path `{PATH}` ({VALUE}) is beneath the limit ({EXACT_LENGTH}).']; - * var schema = new Schema({ n: { type: String, exactlength: max }) - * var M = mongoose.model('Measurement', schema); - * var s= new M({ n: 'teste' }); - * s.validate(function (err) { - * console.log(String(err)) // ValidationError: The length of path `n` (5) is beneath the limit (4). - * }) + * // custom error messages + * // We can also use the special {EXACT_LENGTH} token which will be replaced with the invalid value + * var max = [4, 'The length of path `{PATH}` ({VALUE}) has length different of the expected ({EXACT_LENGTH}).']; + * var schema = new Schema({ n: { type: String, exactlength: max }) + * var M = mongoose.model('Measurement', schema); + * var s= new M({ n: 'teste' }); + * s.validate(function (err) { + * // ValidationError: The length of path `n` (5) has length different of the expected (4). + * console.log(String(err)); + * }) * * @param {Number} max length value * @param {String} [message] optional custom error message diff --git a/lib/string-ext/min-length.js b/lib/string-ext/min-length.js index 7e6ad61..b21fb81 100644 --- a/lib/string-ext/min-length.js +++ b/lib/string-ext/min-length.js @@ -18,12 +18,13 @@ module.exports = function(mongoose) { * * // custom error messages * // We can also use the special {MIN_LENGTH} token which will be replaced with the invalid value - * var max = [4, 'The length of path `{PATH}` ({VALUE}) is beneath the limit ({MIN_LENGTH}).']; + * var max = [4, 'The length of path `{PATH}` ({VALUE}) exceeds the minimum allowed length ({MIN_LENGTH}).']; * var schema = new Schema({ n: { type: String, minlength: max }) * var M = mongoose.model('Measurement', schema); * var s= new M({ n: 'teste' }); * s.validate(function (err) { - * console.log(String(err)) // ValidationError: The length of path `n` (5) is beneath the limit (4). + * // ValidationError: The length of path `n` (5) exceeds the minimum allowed length (4). + * console.log(String(err)); * }) * * @param {Number} max length value diff --git a/test/exact-length.string.test.js b/test/exact-length.string.test.js index 8d7a0ed..87f7df7 100644 --- a/test/exact-length.string.test.js +++ b/test/exact-length.string.test.js @@ -2,10 +2,7 @@ var db = require('db'), mongoose = db.mongoose, should = require('should'); -require('../index'); -require('../lib/string-ext/max-length'); - -describe('String.minLength:', function() { +describe('String.exactLength:', function() { var TestDoc; before('init db', db.init); diff --git a/test/exclusive-min.number.test.js b/test/exclusive-min.number.test.js new file mode 100644 index 0000000..2ba7a02 --- /dev/null +++ b/test/exclusive-min.number.test.js @@ -0,0 +1,128 @@ +var db = require('db'), + mongoose = db.mongoose, + should = require('should'); + +describe('Number.exclusiveMin:', function() { + var TestDoc; + + before('init db', db.init); + before('load extensions', db.loadExtensions); + before('load test model', function(done) { + var TestDocSchema = new mongoose.Schema({ + field01: Number, + field02: { + type: Number, + exclusivemin: 5 + }, + field03: { + type: Number, + exclusivemin: [10, 'Invalid number value'] + }, + field04: { + type: Number, + exclusivemin: [20, 'Path {PATH} ({VALUE}) out of minimum limit {EXCLUSIVE_MIN}'] + } + }); + TestDoc = mongoose.model('TestDoc', TestDocSchema); + done(); + }); + + it('should not impact normal Number types', function(done) { + this.timeout(5000); + var tst = new TestDoc({field01: 1}); + tst.save(function(err, tst) { + if(err) { + return done(err); + } + should(tst.field01).be.eql(1); + done(); + }); + }); + it('should not throw exclusiveMin error for bigger number', function(done) { + this.timeout(5000); + var tst = new TestDoc({field02: 5.0009}); + tst.save(function(err, tst) { + if(err) { + return done(err); + } + should(tst.field02).be.eql(5.0009); + done(); + }); + }); + it('should not throw exclusiveMin error for empty values', function(done) { + this.timeout(5000); + var tst = new TestDoc({field01: 1}); + tst.save(function(err, tst) { + if(err) { + return done(err); + } + should(tst.field01).be.eql(1); + should(tst.field02).be.not.ok; + done(); + }); + }); + + it('should throw exclusiveMin default error message', function(done) { + this.timeout(5000); + var tst = new TestDoc({field02: 1}); + tst.save(function(err) { + should(err).be.ok; + should(err.message).be.eql('Validation failed'); + should(err.name).be.eql('ValidationError'); + should(err.errors.field02).be.ok; + should(err.errors.field02.message).be.eql( + 'Path `field02` (1) should be greater than 5.' + ); + done(); + }); + }); + it('should throw exclusiveMin error for exact value', function(done) { + this.timeout(5000); + var tst = new TestDoc({field02: 5}); + tst.save(function(err) { + should(err).be.ok; + should(err.message).be.eql('Validation failed'); + should(err.name).be.eql('ValidationError'); + should(err.errors.field02).be.ok; + should(err.errors.field02.message).be.eql( + 'Path `field02` (5) should be greater than 5.' + ); + done(); + }); + }); + it('should throw exclusiveMin custom error message', function(done) { + this.timeout(5000); + var tst = new TestDoc({ + field02: 1, + field03: 9 + }); + tst.save(function(err) { + should(err).be.ok; + should(err.message).be.eql('Validation failed'); + should(err.name).be.eql('ValidationError'); + should(err.errors.field02).be.ok; + should(err.errors.field02.message).be.eql( + 'Path `field02` (1) should be greater than 5.' + ); + should(err.errors.field03).be.ok; + should(err.errors.field03.message).be.eql('Invalid number value'); + done(); + }); + }); + it('should throw exclusiveMin custom error with special tokens replaced', function(done) { + this.timeout(5000); + var tst = new TestDoc({field04: 15}); + tst.save(function(err) { + should(err).be.ok; + should(err.message).be.eql('Validation failed'); + should(err.name).be.eql('ValidationError'); + should(err.errors.field04).be.ok; + should(err.errors.field04.message).be.eql( + 'Path field04 (15) out of minimum limit 20' + ); + done(); + }); + }); + + after('finish db', db.finish); +}); diff --git a/test/max-length.string.test.js b/test/max-length.string.test.js index 7600e81..12c41ef 100644 --- a/test/max-length.string.test.js +++ b/test/max-length.string.test.js @@ -2,9 +2,6 @@ var db = require('db'), mongoose = db.mongoose, should = require('should'); -require('../index'); -require('../lib/string-ext/max-length'); - describe('String.maxLength:', function() { var TestDoc; diff --git a/test/min-length.string.test.js b/test/min-length.string.test.js index e3866ea..0d2706a 100644 --- a/test/min-length.string.test.js +++ b/test/min-length.string.test.js @@ -2,9 +2,6 @@ var db = require('db'), mongoose = db.mongoose, should = require('should'); -require('../index'); -require('../lib/string-ext/max-length'); - describe('String.minLength:', function() { var TestDoc;