Skip to content

Commit

Permalink
feat: String maxLength validator
Browse files Browse the repository at this point in the history
  • Loading branch information
the-darc committed Mar 19, 2015
1 parent e55c337 commit 84ad05a
Show file tree
Hide file tree
Showing 8 changed files with 360 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
coverage
node_modules
42 changes: 42 additions & 0 deletions .jshintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"node": true,
"browser": true,
"esnext": true,
"bitwise": false,
"camelcase": false,
"curly": false,
"eqeqeq": true,
"immed": true,
"latedef": true,
"newcap": true,
"noarg": true,
"quotmark": "single",
"regexp": true,
"undef": true,
"unused": true,
"strict": false,
"trailing": true,
"smarttabs": false,
"expr": true,
"globals": {
"angular": true
},
"predef": [
"define",
"require",
"exports",
"module",
"describe",
"before",
"beforeEach",
"after",
"afterEach",
"it",
"StringMask",
"BrV"
],
"indent": 4,
"maxlen": 120,
"devel": false,
"noempty": true
}
4 changes: 4 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
language: node_js
node_js:
- "0.11"
- "0.10"
89 changes: 89 additions & 0 deletions gulpfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
var gulp = require('gulp'),
path = require('path'),
jshintReporter = require('jshint-stylish'),
plugins = require('gulp-load-plugins')({
config: path.join(__dirname, 'package.json')
}),
istanbul = require('gulp-istanbul');

var filePatterns = {
src: ['./lib/**/*.js', './index.js'],
test: ['./test/**/*.test.js']
};

var config = {
files: filePatterns.test,
reporter: 'progress',

target: 'node',
framework: 'mocha',
coverage: filePatterns.src
};

function handleError(err) {
console.log(err.toString());
this.emit('end');
}

function mochaRunnerFactory() {
var mocha = require('gulp-mocha');

return mocha({
reporter: config.reporter || 'progress'
});
}

function unitTestFactory(watch) {
function mochaRunner() {
return gulp.src(config.files, {
cwd: process.env.PWD,
read: false
})
.pipe(mochaRunnerFactory(config.reporter))
.on('error', handleError);
}

if (!watch) {
return mochaRunner;
}

var filesToWatch = config.coverage.concat(config.files);

return function() {
gulp.watch(filesToWatch, mochaRunner);
};
}

gulp.task('jshint', function() {
gulp.src(config.coverage.concat(config.files))
.pipe(plugins.jshint('.jshintrc'))
.pipe(plugins.jshint.reporter(jshintReporter));
});

gulp.task('default', ['jshint'], function() {
gulp.watch(config.files.concat(config.coverage), ['jshint']);
});

gulp.task('test', ['jshint'], function(done) {
unitTestFactory(false)();
});

gulp.task('test-watch', function(done) {
config.reporter = 'spec';
unitTestFactory(true)();
});

gulp.task('test-coverage', function(done) {
gulp.src(config.coverage)
.pipe(istanbul())
.pipe(istanbul.hookRequire())
.on('finish', function() {
gulp.src(config.files, {
cwd: process.env.PWD,
read: false
})
.pipe(mochaRunnerFactory('progress'))
.pipe(istanbul.writeReports())
.on('end', done);
});
});
4 changes: 4 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module.exports = function(mongoose) {
require('./lib/string-ext/max-length.js')(mongoose);
require('./lib/string-ext/min-length.js')(mongoose);
};
55 changes: 55 additions & 0 deletions lib/string-ext/max-length.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
module.exports = function(mongoose) {
var SchemaString = mongoose.SchemaTypes.String,
errorMessages = mongoose.Error.messages;

/**
* Sets a maxlength string validator.
*
* ####Example:
*
* var s = new Schema({ n: { type: String, maxlength: 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 {MAX_LENGTH} token which will be replaced with the invalid value
* var max = [4, 'The length of path `{PATH}` ({VALUE}) is beneath the limit ({MAX_LENGTH}).'];
* var schema = new Schema({ n: { type: String, maxlength: 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).
* })
*
* @param {Number} max length value
* @param {String} [message] optional custom error message
* @return {SchemaType} this
* @see Customized Error Messages #error_messages_MongooseError-messages
* @api public
*/

SchemaString.prototype.maxlength = function(value, message) {
if (this.maxlengthValidator) {
this.validators = this.validators.filter(function (v) {
return v[0] !== this.maxlengthValidator;
}, this);
}

if (null !== value) {
var msg = message || errorMessages.String.maxlength;
msg = msg.replace(/{MAX_LENGTH}/, value);
this.validators.push([this.maxlengthValidator = function (v) {
return !v || v.length <= value;
}, msg, 'maxlength']);
}

return this;
};

errorMessages.String.maxlength = 'Path `{PATH}` ({VALUE}) exceeds the maximum allowed length ({MAX_LENGTH}).';
};
40 changes: 40 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"name": "mongoose-types-ext",
"version": "0.1.0",
"description": "A package of mongoose types extensions",
"main": "index.js",
"directories": {
"test": "test"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/the-darc/mongoose-types-ext"
},
"keywords": [
"mongoose",
"mongodb",
"minLength",
"maxLength"
],
"author": "darc.tec@gmail.com",
"license": "MIT",
"bugs": {
"url": "https://github.com/the-darc/mongoose-types-ext/issues"
},
"homepage": "https://github.com/the-darc/mongoose-types-ext",
"devDependencies": {
"gulp": "^3.8.11",
"gulp-istanbul": "^0.6.0",
"gulp-jshint": "^1.9.4",
"gulp-load-plugins": "^0.8.1",
"gulp-mocha": "^2.0.0",
"jasmine-core": "^2.2.0",
"jshint-stylish": "^1.0.1",
"mocha": "^2.2.1",
"mongoose": "^3.8.25",
"should": "^5.2.0"
}
}
124 changes: 124 additions & 0 deletions test/max-length.string.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
describe('String.maxLength:', function() {
var db = require('db'),
mongoose = db.mongoose,
should = require('should');

require('../index');
require('../lib/string-ext/max-length');

var TestDoc;

before('init db', db.init);
before('load extensions', db.loadExtensions);
before('load test model', function(done) {
var TestDocSchema = new mongoose.Schema({
field01: String,
field02: {
type: String,
maxlength: 5
},
field03: {
type: String,
maxlength: [10, 'Invalid text length']
},
field04: {
type: String,
maxlength: 10
}
});
TestDocSchema.path('field04', {
type: String,
maxlength: [1, 'Path {PATH} ({VALUE}) has length greater than {MAX_LENGTH}']
});
TestDoc = mongoose.model('TestDoc', TestDocSchema);
done();
});

it('should not impact normal string types', function(done) {
var tst = new TestDoc({field01: '12345678'});
tst.save(function(err, tst) {
if(err) {
return done(err);
}
should(tst.field01).be.eql('12345678');
done();
});
});
it('should not throw maxLength error for shorter strings', function(done) {
var tst = new TestDoc({field02: '1234'});
tst.save(function(err, tst) {
if(err) {
return done(err);
}
should(tst.field02).be.eql('1234');
done();
});
});
it('should not throw maxLength error for exact length strings', function(done) {
var tst = new TestDoc({field02: '12345'});
tst.save(function(err, tst) {
if(err) {
return done(err);
}
should(tst.field02).be.eql('12345');
done();
});
});
it('should not throw maxLength error for empty values', function(done) {
var tst = new TestDoc({field01: 'some value'});
tst.save(function(err, tst) {
if(err) {
return done(err);
}
should(tst.field01).be.eql('some value');
should(tst.field02).be.not.ok;
done();
});
});
it('should throw maxLength default error message', function(done) {
var tst = new TestDoc({field02: '123456'});
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` (123456) exceeds the maximum allowed length (5).'
);
done();
});
});
it('should throw maxLength custom error message', function(done) {
var tst = new TestDoc({
field02: '123456',
field03: '123456789112345'
});
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` (123456) exceeds the maximum allowed length (5).'
);
should(err.errors.field03).be.ok;
should(err.errors.field03.message).be.eql('Invalid text length');
done();
});
});
it('should throw maxLength custom error with special tokens replaced', function(done) {
var tst = new TestDoc({field04: 'test'});
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 (test) has length greater than 1'
);
done();
});
});

after('finish db', db.finish);
});

0 comments on commit 84ad05a

Please sign in to comment.