不要怂,就是干,撸起袖子干!

Commit 80e1774d by Rui Marinho Committed by Jan Aagaard Meier

Improve validation when dealing with non-strings (#5861)

* Improve validation when dealing with non-strings

validator@5.0.0+ has stopped coercing input values as strings and since
version 4, the library has been printing deprecation notices everytime a
non-string is passed to it.

All `validate` functions now correctly handle theses cases by delegating
this work to lodash functions.

* Coerce number values when validating
1 parent 45b9990e
# Future # Future
- [FIXED] Type validation now works with non-strings due to updated validator@5.0.0 [#5861](https://github.com/sequelize/sequelize/pull/5861)
- [FIXED] Improved offset and limit support for SQL server 2008 [#5616](https://github.com/sequelize/sequelize/pull/5616) - [FIXED] Improved offset and limit support for SQL server 2008 [#5616](https://github.com/sequelize/sequelize/pull/5616)
# 3.23.1 # 3.23.1
......
...@@ -191,7 +191,7 @@ TEXT.prototype.toSql = function() { ...@@ -191,7 +191,7 @@ TEXT.prototype.toSql = function() {
} }
}; };
TEXT.prototype.validate = function(value) { TEXT.prototype.validate = function(value) {
if (typeof value !== 'string') { if (!_.isString(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid string', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid string', value));
} }
...@@ -228,7 +228,7 @@ NUMBER.prototype.toSql = function() { ...@@ -228,7 +228,7 @@ NUMBER.prototype.toSql = function() {
}; };
NUMBER.prototype.validate = function(value) { NUMBER.prototype.validate = function(value) {
if (!_.isNumber(value)) { if (!Validator.isFloat(String(value))) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid number', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid number', value));
} }
...@@ -267,7 +267,7 @@ var INTEGER = NUMBER.inherits(function(length) { ...@@ -267,7 +267,7 @@ var INTEGER = NUMBER.inherits(function(length) {
INTEGER.prototype.key = INTEGER.key = 'INTEGER'; INTEGER.prototype.key = INTEGER.key = 'INTEGER';
INTEGER.prototype.validate = function(value) { INTEGER.prototype.validate = function(value) {
if (!Validator.isInt(value)) { if (!Validator.isInt(String(value))) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid integer', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid integer', value));
} }
...@@ -294,7 +294,7 @@ var BIGINT = NUMBER.inherits(function(length) { ...@@ -294,7 +294,7 @@ var BIGINT = NUMBER.inherits(function(length) {
BIGINT.prototype.key = BIGINT.key = 'BIGINT'; BIGINT.prototype.key = BIGINT.key = 'BIGINT';
BIGINT.prototype.validate = function(value) { BIGINT.prototype.validate = function(value) {
if (!Validator.isInt(value)) { if (!Validator.isInt(String(value))) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid bigint', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid bigint', value));
} }
...@@ -319,7 +319,7 @@ var FLOAT = NUMBER.inherits(function(length, decimals) { ...@@ -319,7 +319,7 @@ var FLOAT = NUMBER.inherits(function(length, decimals) {
FLOAT.prototype.key = FLOAT.key = 'FLOAT'; FLOAT.prototype.key = FLOAT.key = 'FLOAT';
FLOAT.prototype.validate = function(value) { FLOAT.prototype.validate = function(value) {
if (!Validator.isFloat(value)) { if (!Validator.isFloat(String(value))) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid float', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid float', value));
} }
...@@ -387,7 +387,7 @@ DECIMAL.prototype.toSql = function() { ...@@ -387,7 +387,7 @@ DECIMAL.prototype.toSql = function() {
return 'DECIMAL'; return 'DECIMAL';
}; };
DECIMAL.prototype.validate = function(value) { DECIMAL.prototype.validate = function(value) {
if (!Validator.isDecimal(value)) { if (!Validator.isDecimal(String(value))) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid decimal', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid decimal', value));
} }
...@@ -419,7 +419,7 @@ BOOLEAN.prototype.toSql = function() { ...@@ -419,7 +419,7 @@ BOOLEAN.prototype.toSql = function() {
return 'TINYINT(1)'; return 'TINYINT(1)';
}; };
BOOLEAN.prototype.validate = function(value) { BOOLEAN.prototype.validate = function(value) {
if (!Validator.isBoolean(value)) { if (!Validator.isBoolean(String(value))) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid boolean', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid boolean', value));
} }
...@@ -458,7 +458,7 @@ DATE.prototype.toSql = function() { ...@@ -458,7 +458,7 @@ DATE.prototype.toSql = function() {
return 'DATETIME'; return 'DATETIME';
}; };
DATE.prototype.validate = function(value) { DATE.prototype.validate = function(value) {
if (!Validator.isDate(value)) { if (!_.isDate(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid date', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid date', value));
} }
...@@ -672,7 +672,7 @@ var UUID = ABSTRACT.inherits(); ...@@ -672,7 +672,7 @@ var UUID = ABSTRACT.inherits();
UUID.prototype.key = UUID.key = 'UUID'; UUID.prototype.key = UUID.key = 'UUID';
UUID.prototype.validate = function(value, options) { UUID.prototype.validate = function(value, options) {
if (!Validator.isUUID(value) && (!options || !options.acceptStrings || typeof value !== 'string')) { if (!_.isString(value) || !Validator.isUUID(value) && (!options || !options.acceptStrings)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid uuid', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid uuid', value));
} }
...@@ -692,7 +692,7 @@ util.inherits(UUIDV1, ABSTRACT); ...@@ -692,7 +692,7 @@ util.inherits(UUIDV1, ABSTRACT);
UUIDV1.prototype.key = UUIDV1.key = 'UUIDV1'; UUIDV1.prototype.key = UUIDV1.key = 'UUIDV1';
UUIDV1.prototype.validate = function(value, options) { UUIDV1.prototype.validate = function(value, options) {
if (!Validator.isUUID(value) && (!options || !options.acceptStrings || typeof value !== 'string')) { if (!_.isString(value) || !Validator.isUUID(value) && (!options || !options.acceptStrings)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid uuid', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid uuid', value));
} }
...@@ -712,7 +712,7 @@ util.inherits(UUIDV4, ABSTRACT); ...@@ -712,7 +712,7 @@ util.inherits(UUIDV4, ABSTRACT);
UUIDV4.prototype.key = UUIDV4.key = 'UUIDV4'; UUIDV4.prototype.key = UUIDV4.key = 'UUIDV4';
UUIDV4.prototype.validate = function(value, options) { UUIDV4.prototype.validate = function(value, options) {
if (!Validator.isUUID(value, 4) && (!options || !options.acceptStrings || typeof value !== 'string')) { if (!_.isString(value) || !Validator.isUUID(value, 4) && (!options || !options.acceptStrings)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid uuidv4', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid uuidv4', value));
} }
...@@ -815,7 +815,7 @@ ARRAY.prototype.toSql = function() { ...@@ -815,7 +815,7 @@ ARRAY.prototype.toSql = function() {
return this.type.toSql() + '[]'; return this.type.toSql() + '[]';
}; };
ARRAY.prototype.validate = function(value) { ARRAY.prototype.validate = function(value) {
if (!Array.isArray(value)) { if (!_.isArray(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid array', value)); throw new sequelizeErrors.ValidationError(util.format('%j is not a valid array', value));
} }
......
...@@ -4,6 +4,11 @@ var validator = require('validator') ...@@ -4,6 +4,11 @@ var validator = require('validator')
, _ = require('lodash'); , _ = require('lodash');
var extensions = { var extensions = {
extend: function(name, fn) {
this[name] = fn;
return this;
},
notEmpty: function(str) { notEmpty: function(str) {
return !str.match(/^[\s\t\r\n]*$/); return !str.match(/^[\s\t\r\n]*$/);
}, },
...@@ -64,7 +69,7 @@ var extendModelValidations = function(modelInstance) { ...@@ -64,7 +69,7 @@ var extendModelValidations = function(modelInstance) {
}; };
_.forEach(extensions, function(extend, key) { _.forEach(extensions, function(extend, key) {
validator.extend(key, extend); validator[key] = extend;
}); });
}; };
...@@ -75,7 +80,7 @@ validator.notNull = function() { ...@@ -75,7 +80,7 @@ validator.notNull = function() {
// https://github.com/chriso/validator.js/blob/1.5.0/lib/validators.js // https://github.com/chriso/validator.js/blob/1.5.0/lib/validators.js
_.forEach(extensions, function(extend, key) { _.forEach(extensions, function(extend, key) {
validator.extend(key, extend); validator[key] = extend;
}); });
module.exports = { module.exports = {
......
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
"shimmer": "1.1.0", "shimmer": "1.1.0",
"terraformer-wkt-parser": "^1.1.0", "terraformer-wkt-parser": "^1.1.0",
"toposort-class": "^1.0.1", "toposort-class": "^1.0.1",
"validator": "^4.6.1", "validator": "^5.2.0",
"wkx": "0.2.0" "wkx": "0.2.0"
}, },
"devDependencies": { "devDependencies": {
......
...@@ -162,6 +162,10 @@ suite(Support.getTestDialectTeaser('SQL'), function() { ...@@ -162,6 +162,10 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
expect(type.validate(true)).to.equal(true); expect(type.validate(true)).to.equal(true);
expect(type.validate(false)).to.equal(true); expect(type.validate(false)).to.equal(true);
expect(type.validate('1')).to.equal(true);
expect(type.validate('0')).to.equal(true);
expect(type.validate('true')).to.equal(true);
expect(type.validate('false')).to.equal(true);
}); });
}); });
}); });
...@@ -233,6 +237,10 @@ suite(Support.getTestDialectTeaser('SQL'), function() { ...@@ -233,6 +237,10 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
expect(function () { expect(function () {
type.validate('foobar'); type.validate('foobar');
}).to.throw(Sequelize.ValidationError, '"foobar" is not a valid uuid'); }).to.throw(Sequelize.ValidationError, '"foobar" is not a valid uuid');
expect(function () {
type.validate(['foobar']);
}).to.throw(Sequelize.ValidationError, '["foobar"] is not a valid uuid');
}); });
test('should return `true` if `value` is an uuid', function() { test('should return `true` if `value` is an uuid', function() {
...@@ -261,6 +269,10 @@ suite(Support.getTestDialectTeaser('SQL'), function() { ...@@ -261,6 +269,10 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
expect(function () { expect(function () {
type.validate('foobar'); type.validate('foobar');
}).to.throw(Sequelize.ValidationError, '"foobar" is not a valid uuid'); }).to.throw(Sequelize.ValidationError, '"foobar" is not a valid uuid');
expect(function () {
type.validate(['foobar']);
}).to.throw(Sequelize.ValidationError, '["foobar"] is not a valid uuid');
}); });
test('should return `true` if `value` is an uuid', function() { test('should return `true` if `value` is an uuid', function() {
...@@ -290,6 +302,10 @@ suite(Support.getTestDialectTeaser('SQL'), function() { ...@@ -290,6 +302,10 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
expect(function () { expect(function () {
type.validate(value); type.validate(value);
}).to.throw(Sequelize.ValidationError, util.format('%j is not a valid uuidv4', value)); }).to.throw(Sequelize.ValidationError, util.format('%j is not a valid uuidv4', value));
expect(function () {
type.validate(['foobar']);
}).to.throw(Sequelize.ValidationError, '["foobar"] is not a valid uuidv4');
}); });
test('should return `true` if `value` is an uuid', function() { test('should return `true` if `value` is an uuid', function() {
...@@ -377,11 +393,20 @@ suite(Support.getTestDialectTeaser('SQL'), function() { ...@@ -377,11 +393,20 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
expect(function () { expect(function () {
type.validate('foobar'); type.validate('foobar');
}).to.throw(Sequelize.ValidationError, '"foobar" is not a valid integer'); }).to.throw(Sequelize.ValidationError, '"foobar" is not a valid integer');
expect(function () {
type.validate('123.45');
}).to.throw(Sequelize.ValidationError, '"123.45" is not a valid integer');
expect(function () {
type.validate(123.45);
}).to.throw(Sequelize.ValidationError, '123.45 is not a valid integer');
}); });
test('should return `true` if `value` is a valid integer', function() { test('should return `true` if `value` is a valid integer', function() {
var type = DataTypes.INTEGER(); var type = DataTypes.INTEGER();
expect(type.validate('12345')).to.equal(true);
expect(type.validate(12345)).to.equal(true); expect(type.validate(12345)).to.equal(true);
}); });
}); });
...@@ -451,12 +476,16 @@ suite(Support.getTestDialectTeaser('SQL'), function() { ...@@ -451,12 +476,16 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
expect(function () { expect(function () {
type.validate('foobar'); type.validate('foobar');
}).to.throw(Sequelize.ValidationError, '"foobar" is not a valid bigint'); }).to.throw(Sequelize.ValidationError, '"foobar" is not a valid bigint');
expect(function () {
type.validate(123.45);
}).to.throw(Sequelize.ValidationError, '123.45 is not a valid bigint');
}); });
test('should return `true` if `value` is an integer', function() { test('should return `true` if `value` is an integer', function() {
var type = DataTypes.BIGINT(); var type = DataTypes.BIGINT();
expect(type.validate(12345)).to.equal(true); expect(type.validate('9223372036854775807')).to.equal(true);
}); });
}); });
}); });
...@@ -730,12 +759,20 @@ suite(Support.getTestDialectTeaser('SQL'), function() { ...@@ -730,12 +759,20 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
expect(function () { expect(function () {
type.validate('foobar'); type.validate('foobar');
}).to.throw(Sequelize.ValidationError, '"foobar" is not a valid float'); }).to.throw(Sequelize.ValidationError, '"foobar" is not a valid float');
expect(function () {
type.validate('-.123');
}).to.throw(Sequelize.ValidationError, '"-.123" is not a valid float');
}); });
test('should return `true` if `value` is a float', function() { test('should return `true` if `value` is a float', function() {
var type = DataTypes.FLOAT(); var type = DataTypes.FLOAT();
expect(type.validate(1.2)).to.equal(true); expect(type.validate(1.2)).to.equal(true);
expect(type.validate('1')).to.equal(true);
expect(type.validate('1.2')).to.equal(true);
expect(type.validate('-0.123')).to.equal(true);
expect(type.validate('-0.22250738585072011e-307')).to.equal(true);
}); });
}); });
}); });
...@@ -770,6 +807,37 @@ suite(Support.getTestDialectTeaser('SQL'), function() { ...@@ -770,6 +807,37 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
testsql('DECIMAL({ precision: 10 })', DataTypes.DECIMAL({ precision: 10 }), { testsql('DECIMAL({ precision: 10 })', DataTypes.DECIMAL({ precision: 10 }), {
default: 'DECIMAL(10)' default: 'DECIMAL(10)'
}); });
suite('validate', function () {
test('should throw an error if `value` is invalid', function() {
var type = DataTypes.DECIMAL(10);
expect(function () {
type.validate('foobar');
}).to.throw(Sequelize.ValidationError, '"foobar" is not a valid decimal');
expect(function () {
type.validate('0.1a');
}).to.throw(Sequelize.ValidationError, '"0.1a" is not a valid decimal');
expect(function () {
type.validate(NaN);
}).to.throw(Sequelize.ValidationError, 'null is not a valid decimal');
});
test('should return `true` if `value` is a decimal', function() {
var type = DataTypes.DECIMAL(10);
expect(type.validate(123)).to.equal(true);
expect(type.validate(1.2)).to.equal(true);
expect(type.validate(-0.25)).to.equal(true);
expect(type.validate(0.0000000000001)).to.equal(true);
expect(type.validate('123')).to.equal(true);
expect(type.validate('1.2')).to.equal(true);
expect(type.validate('-0.25')).to.equal(true);
expect(type.validate('0.0000000000001')).to.equal(true);
});
});
}); });
suite('ENUM', function () { suite('ENUM', function () {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!