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

Commit a243a82c by Tiago Ribeiro

Add default validation based on attribute type

1 parent a56a1882
...@@ -3,7 +3,9 @@ ...@@ -3,7 +3,9 @@
var util = require('util') var util = require('util')
, _ = require('lodash') , _ = require('lodash')
, Wkt = require('wellknown') , Wkt = require('wellknown')
, warnings = {}; , sequelizeErrors = require('./errors')
, warnings = {}
, Validator = require('validator');
/** /**
* A convenience class holding commonly used data types. The datatypes are used when definining a new model using `Sequelize.define`, like this: * A convenience class holding commonly used data types. The datatypes are used when definining a new model using `Sequelize.define`, like this:
...@@ -80,6 +82,13 @@ STRING.prototype.key = STRING.key = 'STRING'; ...@@ -80,6 +82,13 @@ STRING.prototype.key = STRING.key = 'STRING';
STRING.prototype.toSql = function() { STRING.prototype.toSql = function() {
return 'VARCHAR(' + this._length + ')' + ((this._binary) ? ' BINARY' : ''); return 'VARCHAR(' + this._length + ')' + ((this._binary) ? ' BINARY' : '');
}; };
STRING.prototype.validate = function(value) {
if (typeof value !== 'string') {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid string', value));
}
return true;
};
Object.defineProperty(STRING.prototype, 'BINARY', { Object.defineProperty(STRING.prototype, 'BINARY', {
get: function() { get: function() {
this._binary = true; this._binary = true;
...@@ -137,6 +146,13 @@ TEXT.prototype.toSql = function() { ...@@ -137,6 +146,13 @@ TEXT.prototype.toSql = function() {
return this.key; return this.key;
} }
}; };
TEXT.prototype.validate = function(value) {
if (typeof value !== 'string') {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid string', value));
}
return true;
};
var NUMBER = function(options) { var NUMBER = function(options) {
this.options = options; this.options = options;
...@@ -167,6 +183,13 @@ NUMBER.prototype.toSql = function() { ...@@ -167,6 +183,13 @@ NUMBER.prototype.toSql = function() {
} }
return result; return result;
}; };
NUMBER.prototype.validate = function(value) {
if (!_.isNumber(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid number', value));
}
return true;
};
Object.defineProperty(NUMBER.prototype, 'UNSIGNED', { Object.defineProperty(NUMBER.prototype, 'UNSIGNED', {
get: function() { get: function() {
...@@ -200,6 +223,13 @@ var INTEGER = function(length) { ...@@ -200,6 +223,13 @@ var INTEGER = function(length) {
util.inherits(INTEGER, NUMBER); util.inherits(INTEGER, NUMBER);
INTEGER.prototype.key = INTEGER.key = 'INTEGER'; INTEGER.prototype.key = INTEGER.key = 'INTEGER';
INTEGER.prototype.validate = function(value) {
if (!Validator.isInt(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid integer', value));
}
return true;
};
/** /**
* A 64 bit integer. * A 64 bit integer.
...@@ -219,6 +249,13 @@ var BIGINT = function(length) { ...@@ -219,6 +249,13 @@ var BIGINT = function(length) {
util.inherits(BIGINT, NUMBER); util.inherits(BIGINT, NUMBER);
BIGINT.prototype.key = BIGINT.key = 'BIGINT'; BIGINT.prototype.key = BIGINT.key = 'BIGINT';
BIGINT.prototype.validate = function(value) {
if (!Validator.isInt(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid bigint', value));
}
return true;
};
/** /**
* Floating point number (4-byte precision). Accepts one or two arguments for precision * Floating point number (4-byte precision). Accepts one or two arguments for precision
...@@ -238,6 +275,13 @@ var FLOAT = function(length, decimals) { ...@@ -238,6 +275,13 @@ var FLOAT = function(length, decimals) {
util.inherits(FLOAT, NUMBER); util.inherits(FLOAT, NUMBER);
FLOAT.prototype.key = FLOAT.key = 'FLOAT'; FLOAT.prototype.key = FLOAT.key = 'FLOAT';
FLOAT.prototype.validate = function(value) {
if (!Validator.isFloat(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid float', value));
}
return true;
};
/** /**
* Floating point number (4-byte precision). Accepts one or two arguments for precision * Floating point number (4-byte precision). Accepts one or two arguments for precision
...@@ -302,6 +346,13 @@ DECIMAL.prototype.toSql = function() { ...@@ -302,6 +346,13 @@ DECIMAL.prototype.toSql = function() {
return 'DECIMAL'; return 'DECIMAL';
}; };
DECIMAL.prototype.validate = function(value) {
if (!_.isNumber(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid decimal', value));
}
return true;
};
/** /**
* A boolean / tinyint column, depending on dialect * A boolean / tinyint column, depending on dialect
...@@ -317,6 +368,13 @@ BOOLEAN.prototype.key = BOOLEAN.key = 'BOOLEAN'; ...@@ -317,6 +368,13 @@ BOOLEAN.prototype.key = BOOLEAN.key = 'BOOLEAN';
BOOLEAN.prototype.toSql = function() { BOOLEAN.prototype.toSql = function() {
return 'TINYINT(1)'; return 'TINYINT(1)';
}; };
BOOLEAN.prototype.validate = function(value) {
if (!_.isBoolean(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid boolean', value));
}
return true;
};
/** /**
* A time column * A time column
...@@ -348,7 +406,13 @@ DATE.prototype.key = DATE.key = 'DATE'; ...@@ -348,7 +406,13 @@ DATE.prototype.key = DATE.key = 'DATE';
DATE.prototype.toSql = function() { DATE.prototype.toSql = function() {
return 'DATETIME'; return 'DATETIME';
}; };
DATE.prototype.validate = function(value) {
if (!Validator.isDate(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid date', value));
}
return true;
};
/** /**
* A date only column * A date only column
* @property DATEONLY * @property DATEONLY
...@@ -377,6 +441,13 @@ var HSTORE = function() { ...@@ -377,6 +441,13 @@ var HSTORE = function() {
util.inherits(HSTORE, ABSTRACT); util.inherits(HSTORE, ABSTRACT);
HSTORE.prototype.key = HSTORE.key = 'HSTORE'; HSTORE.prototype.key = HSTORE.key = 'HSTORE';
HSTORE.prototype.validate = function(value) {
if (!_.isPlainObject(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid hstore', value));
}
return true;
};
/** /**
* A JSON string column. Only available in postgres. * A JSON string column. Only available in postgres.
...@@ -389,6 +460,9 @@ var JSONTYPE = function() { ...@@ -389,6 +460,9 @@ var JSONTYPE = function() {
util.inherits(JSONTYPE, ABSTRACT); util.inherits(JSONTYPE, ABSTRACT);
JSONTYPE.prototype.key = JSONTYPE.key = 'JSON'; JSONTYPE.prototype.key = JSONTYPE.key = 'JSON';
JSONTYPE.prototype.validate = function(value) {
return true;
};
/** /**
* A pre-processed JSON data column. Only available in postgres. * A pre-processed JSON data column. Only available in postgres.
...@@ -442,6 +516,13 @@ BLOB.prototype.toSql = function() { ...@@ -442,6 +516,13 @@ BLOB.prototype.toSql = function() {
return this.key; return this.key;
} }
}; };
BLOB.prototype.validate = function(value) {
if (!_.isString(value) && !Buffer.isBuffer(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid blob', value));
}
return true;
};
/** /**
* Range types are data types representing a range of values of some element type (called the range's subtype). * Range types are data types representing a range of values of some element type (called the range's subtype).
...@@ -474,6 +555,21 @@ RANGE.prototype.key = RANGE.key = 'RANGE'; ...@@ -474,6 +555,21 @@ RANGE.prototype.key = RANGE.key = 'RANGE';
RANGE.prototype.toSql = function() { RANGE.prototype.toSql = function() {
return pgRangeSubtypes[this._subtype.toLowerCase()]; return pgRangeSubtypes[this._subtype.toLowerCase()];
}; };
RANGE.prototype.validate = function(value) {
if (_.isPlainObject(value) && value.inclusive) {
value = value.inclusive;
}
if (!_.isArray(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid range', value));
}
if (value.length !== 2) {
throw new sequelizeErrors.ValidationError('A range must be an array with two elements');
}
return true;
};
/** /**
* A column storing a unique univeral identifier. Use with `UUIDV1` or `UUIDV4` for default values. * A column storing a unique univeral identifier. Use with `UUIDV1` or `UUIDV4` for default values.
...@@ -486,6 +582,13 @@ var UUID = function() { ...@@ -486,6 +582,13 @@ var UUID = function() {
util.inherits(UUID, ABSTRACT); util.inherits(UUID, ABSTRACT);
UUID.prototype.key = UUID.key = 'UUID'; UUID.prototype.key = UUID.key = 'UUID';
UUID.prototype.validate = function(value) {
if (!Validator.isUUID(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid uuid', value));
}
return true;
};
/** /**
* A default unique universal identifier generated following the UUID v1 standard * A default unique universal identifier generated following the UUID v1 standard
...@@ -499,6 +602,13 @@ var UUIDV1 = function() { ...@@ -499,6 +602,13 @@ var UUIDV1 = function() {
util.inherits(UUIDV1, ABSTRACT); util.inherits(UUIDV1, ABSTRACT);
UUIDV1.prototype.key = UUIDV1.key = 'UUIDV1'; UUIDV1.prototype.key = UUIDV1.key = 'UUIDV1';
UUIDV1.prototype.validate = function(value) {
if (!Validator.isUUID(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid uuid', value));
}
return true;
};
/** /**
* A default unique universal identifier generated following the UUID v2 standard * A default unique universal identifier generated following the UUID v2 standard
...@@ -512,6 +622,13 @@ var UUIDV4 = function() { ...@@ -512,6 +622,13 @@ var UUIDV4 = function() {
util.inherits(UUIDV4, ABSTRACT); util.inherits(UUIDV4, ABSTRACT);
UUIDV4.prototype.key = UUIDV4.key = 'UUIDV4'; UUIDV4.prototype.key = UUIDV4.key = 'UUIDV4';
UUIDV4.prototype.validate = function(value) {
if (!Validator.isUUID(value, 4)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid uuidv4', value));
}
return true;
};
/** /**
* A virtual value that is not stored in the DB. This could for example be useful if you want to provide a default value in your model that is returned to the user but not stored in the DB. * A virtual value that is not stored in the DB. This could for example be useful if you want to provide a default value in your model that is returned to the user but not stored in the DB.
...@@ -565,6 +682,13 @@ var ENUM = function(value) { ...@@ -565,6 +682,13 @@ var ENUM = function(value) {
util.inherits(ENUM, ABSTRACT); util.inherits(ENUM, ABSTRACT);
ENUM.prototype.key = ENUM.key = 'ENUM'; ENUM.prototype.key = ENUM.key = 'ENUM';
ENUM.prototype.validate = function(value) {
if (!_.contains(this.values, value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid choice in %j', value, this.values));
}
return true;
};
/** /**
* An array of `type`, e.g. `DataTypes.ARRAY(DataTypes.DECIMAL)`. Only available in postgres. * An array of `type`, e.g. `DataTypes.ARRAY(DataTypes.DECIMAL)`. Only available in postgres.
...@@ -583,6 +707,13 @@ ARRAY.prototype.key = ARRAY.key = 'ARRAY'; ...@@ -583,6 +707,13 @@ ARRAY.prototype.key = ARRAY.key = 'ARRAY';
ARRAY.prototype.toSql = function() { ARRAY.prototype.toSql = function() {
return this.type.toSql() + '[]'; return this.type.toSql() + '[]';
}; };
ARRAY.prototype.validate = function(value) {
if (!Array.isArray(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid array', value));
}
return true;
};
ARRAY.is = function(obj, type) { ARRAY.is = function(obj, type) {
return obj instanceof ARRAY && obj.type instanceof type; return obj instanceof ARRAY && obj.type instanceof type;
}; };
......
...@@ -877,6 +877,12 @@ var QueryGenerator = { ...@@ -877,6 +877,12 @@ var QueryGenerator = {
return this.handleSequelizeMethod(value); return this.handleSequelizeMethod(value);
} }
if (field && field.type && value) {
if (field.type.validate) {
field.type.validate(value);
}
}
if (Utils._.isObject(value) && field && (field.type instanceof DataTypes.HSTORE || DataTypes.ARRAY.is(field.type, DataTypes.HSTORE))) { if (Utils._.isObject(value) && field && (field.type instanceof DataTypes.HSTORE || DataTypes.ARRAY.is(field.type, DataTypes.HSTORE))) {
if (field.type instanceof DataTypes.HSTORE){ if (field.type instanceof DataTypes.HSTORE){
return "'" + hstore.stringify(value) + "'"; return "'" + hstore.stringify(value) + "'";
......
...@@ -91,26 +91,8 @@ var Model = function(name, attributes, options) { ...@@ -91,26 +91,8 @@ var Model = function(name, attributes, options) {
throw new Error('Values for ENUM have not been defined.'); throw new Error('Values for ENUM have not been defined.');
} }
attribute.validate = attribute.validate || { // BC compatible.
_checkEnum: function(value, next) { attribute.type.values = attribute.values;
var hasValue = value !== undefined
, isMySQL = ['mysql', 'mariadb'].indexOf(options.sequelize.options.dialect) !== -1
, ciCollation = !!options.collate && options.collate.match(/_ci$/i) !== null
, valueOutOfScope;
if (isMySQL && ciCollation && hasValue) {
var scopeIndex = (attributes[name].values || []).map(function(d) { return d.toLowerCase(); }).indexOf(value.toLowerCase());
valueOutOfScope = scopeIndex === -1;
} else {
valueOutOfScope = ((attributes[name].values || []).indexOf(value) === -1);
}
if (hasValue && valueOutOfScope && attributes[name].allowNull !== true) {
return next('Value "' + value + '" for ENUM ' + name + ' is out of allowed scope. Allowed values: ' + attributes[name].values.join(', '));
}
next();
}
};
} }
return attribute; return attribute;
......
...@@ -406,7 +406,7 @@ QueryInterface.prototype.renameColumn = function(tableName, attrNameBefore, attr ...@@ -406,7 +406,7 @@ QueryInterface.prototype.renameColumn = function(tableName, attrNameBefore, attr
_options[attrNameAfter] = { _options[attrNameAfter] = {
attribute: attrNameAfter, attribute: attrNameAfter,
type: data.type, type: DataTypes[data.type],
allowNull: data.allowNull, allowNull: data.allowNull,
defaultValue: data.defaultValue defaultValue: data.defaultValue
}; };
......
...@@ -16,9 +16,9 @@ if (dialect.match(/^postgres/)) { ...@@ -16,9 +16,9 @@ if (dialect.match(/^postgres/)) {
beforeEach(function() { beforeEach(function() {
this.User = this.sequelize.define('User', { this.User = this.sequelize.define('User', {
username: DataTypes.STRING, username: DataTypes.STRING,
email: {type: DataTypes.ARRAY(DataTypes.TEXT)}, email: { type: DataTypes.ARRAY(DataTypes.TEXT) },
numbers: {type: DataTypes.ARRAY(DataTypes.FLOAT)}, numbers: { type: DataTypes.ARRAY(DataTypes.FLOAT) },
document: {type: DataTypes.HSTORE, defaultValue: '"default"=>"value"'} document: { type: DataTypes.HSTORE, defaultValue: { default: '"value"' } }
}); });
return this.User.sync({ force: true }); return this.User.sync({ force: true });
}); });
......
...@@ -718,4 +718,4 @@ describe(Support.getTestDialectTeaser('InstanceValidator'), function() { ...@@ -718,4 +718,4 @@ describe(Support.getTestDialectTeaser('InstanceValidator'), function() {
expect(errors.get('name')[0].message).to.equal('Validation isExactly7Characters failed'); expect(errors.get('name')[0].message).to.equal('Validation isExactly7Characters failed');
}); });
}); });
}); });
\ No newline at end of file
...@@ -927,7 +927,7 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() { ...@@ -927,7 +927,7 @@ describe(Support.getTestDialectTeaser('Sequelize'), function() {
it("doesn't save an instance if value is not in the range of enums", function() { it("doesn't save an instance if value is not in the range of enums", function() {
return this.Review.create({status: 'fnord'}).catch(function(err) { return this.Review.create({status: 'fnord'}).catch(function(err) {
expect(err).to.be.instanceOf(Error); expect(err).to.be.instanceOf(Error);
expect(err.get('status')[0].message).to.equal('Value "fnord" for ENUM status is out of allowed scope. Allowed values: scheduled, active, finished'); expect(err.message).to.equal('"fnord" is not a valid choice in ["scheduled","active","finished"]');
}); });
}); });
}); });
......
...@@ -2,8 +2,13 @@ ...@@ -2,8 +2,13 @@
var Support = require(__dirname + '/../support') var Support = require(__dirname + '/../support')
, DataTypes = require(__dirname + '/../../../lib/data-types') , DataTypes = require(__dirname + '/../../../lib/data-types')
, Sequelize = Support.Sequelize
, chai = require('chai')
, util = require('util')
, uuid = require('node-uuid')
, expectsql = Support.expectsql , expectsql = Support.expectsql
, current = Support.sequelize; , current = Support.sequelize
, expect = chai.expect;
// Notice: [] will be replaced by dialect specific tick/quote character when there is not dialect specific expectation but only a default expectation // Notice: [] will be replaced by dialect specific tick/quote character when there is not dialect specific expectation but only a default expectation
...@@ -44,6 +49,22 @@ suite(Support.getTestDialectTeaser('SQL'), function() { ...@@ -44,6 +49,22 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
mssql: 'BINARY(255)', mssql: 'BINARY(255)',
postgres: 'BYTEA' postgres: 'BYTEA'
}); });
suite('validate', function () {
test('should throw an error if `value` is invalid', function() {
var type = DataTypes.STRING();
expect(function () {
type.validate(12345);
}).to.throw(Sequelize.ValidationError, '12345 is not a valid string');
});
test('should return `true` if `value` is a string', function() {
var type = DataTypes.STRING();
expect(type.validate('foobar')).to.equal(true);
});
});
}); });
suite('TEXT', function () { suite('TEXT', function () {
...@@ -79,6 +100,22 @@ suite(Support.getTestDialectTeaser('SQL'), function() { ...@@ -79,6 +100,22 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
mysql: 'LONGTEXT', mysql: 'LONGTEXT',
mariadb: 'LONGTEXT' mariadb: 'LONGTEXT'
}); });
suite('validate', function () {
test('should throw an error if `value` is invalid', function() {
var type = DataTypes.TEXT();
expect(function () {
type.validate(12345);
}).to.throw(Sequelize.ValidationError, '12345 is not a valid string');
});
test('should return `true` if `value` is a string', function() {
var type = DataTypes.TEXT();
expect(type.validate('foobar')).to.equal(true);
});
});
}); });
suite('CHAR', function () { suite('CHAR', function () {
...@@ -114,6 +151,23 @@ suite(Support.getTestDialectTeaser('SQL'), function() { ...@@ -114,6 +151,23 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
mysql: 'TINYINT(1)', mysql: 'TINYINT(1)',
sqlite: 'TINYINT(1)' sqlite: 'TINYINT(1)'
}); });
suite('validate', function () {
test('should throw an error if `value` is invalid', function() {
var type = DataTypes.BOOLEAN();
expect(function () {
type.validate(12345);
}).to.throw(Sequelize.ValidationError, '12345 is not a valid boolean');
});
test('should return `true` if `value` is a boolean', function() {
var type = DataTypes.BOOLEAN();
expect(type.validate(true)).to.equal(true);
expect(type.validate(false)).to.equal(true);
});
});
}); });
suite('DATE', function () { suite('DATE', function () {
...@@ -123,8 +177,44 @@ suite(Support.getTestDialectTeaser('SQL'), function() { ...@@ -123,8 +177,44 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
mysql: 'DATETIME', mysql: 'DATETIME',
sqlite: 'DATETIME' sqlite: 'DATETIME'
}); });
suite('validate', function () {
test('should throw an error if `value` is invalid', function() {
var type = DataTypes.DATE();
expect(function () {
type.validate('foobar');
}).to.throw(Sequelize.ValidationError, '"foobar" is not a valid date');
});
test('should return `true` if `value` is a date', function() {
var type = DataTypes.DATE();
expect(type.validate(new Date())).to.equal(true);
});
});
}); });
if (current.dialect.supports.HSTORE) {
suite('HSTORE', function () {
suite('validate', function () {
test('should throw an error if `value` is invalid', function() {
var type = DataTypes.HSTORE();
expect(function () {
type.validate('foobar');
}).to.throw(Sequelize.ValidationError, 'foobar is not a valid hstore');
});
test('should return `true` if `value` is an hstore', function() {
var type = DataTypes.HSTORE();
expect(type.validate({ foo: 'bar' })).to.equal(true);
});
});
});
}
suite('UUID', function () { suite('UUID', function () {
testsql('UUID', DataTypes.UUID, { testsql('UUID', DataTypes.UUID, {
postgres: 'UUID', postgres: 'UUID',
...@@ -133,13 +223,66 @@ suite(Support.getTestDialectTeaser('SQL'), function() { ...@@ -133,13 +223,66 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
sqlite: 'UUID' sqlite: 'UUID'
}); });
suite('validate', function () {
test('should throw an error if `value` is invalid', function() {
var type = DataTypes.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() {
var type = DataTypes.UUID();
expect(type.validate(uuid.v4())).to.equal(true);
});
});
});
suite('UUIDV1', function () {
testsql('UUIDV1', DataTypes.UUIDV1, { testsql('UUIDV1', DataTypes.UUIDV1, {
default: 'UUIDV1' default: 'UUIDV1'
}); });
suite('validate', function () {
test('should throw an error if `value` is invalid', function() {
var type = DataTypes.UUIDV1();
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() {
var type = DataTypes.UUIDV1();
expect(type.validate(uuid.v1())).to.equal(true);
});
});
});
suite('UUIDV4', function () {
testsql('UUIDV4', DataTypes.UUIDV4, { testsql('UUIDV4', DataTypes.UUIDV4, {
default: 'UUIDV4' default: 'UUIDV4'
}); });
suite('validate', function () {
test('should throw an error if `value` is invalid', function() {
var type = DataTypes.UUIDV4();
var value = uuid.v1();
expect(function () {
type.validate(value);
}).to.throw(Sequelize.ValidationError, util.format('%j is not a valid uuidv4', value));
});
test('should return `true` if `value` is an uuid', function() {
var type = DataTypes.UUIDV4();
expect(type.validate(uuid.v4())).to.equal(true);
});
});
}); });
suite('NOW', function () { suite('NOW', function () {
...@@ -205,6 +348,22 @@ suite(Support.getTestDialectTeaser('SQL'), function() { ...@@ -205,6 +348,22 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
postgres: 'INTEGER', postgres: 'INTEGER',
mssql: 'INTEGER' mssql: 'INTEGER'
}); });
suite('validate', function () {
test('should throw an error if `value` is invalid', function() {
var type = DataTypes.INTEGER();
expect(function () {
type.validate('foobar');
}).to.throw(Sequelize.ValidationError, '"foobar" is not a valid integer');
});
test('should return `true` if `value` is a valid integer', function() {
var type = DataTypes.INTEGER();
expect(type.validate(12345)).to.equal(true);
});
});
}); });
suite('BIGINT', function () { suite('BIGINT', function () {
...@@ -263,6 +422,22 @@ suite(Support.getTestDialectTeaser('SQL'), function() { ...@@ -263,6 +422,22 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
postgres: 'BIGINT', postgres: 'BIGINT',
mssql: 'BIGINT' mssql: 'BIGINT'
}); });
suite('validate', function () {
test('should throw an error if `value` is invalid', function() {
var type = DataTypes.BIGINT();
expect(function () {
type.validate('foobar');
}).to.throw(Sequelize.ValidationError, '"foobar" is not a valid bigint');
});
test('should return `true` if `value` is an integer', function() {
var type = DataTypes.BIGINT();
expect(type.validate(12345)).to.equal(true);
});
});
}); });
suite('REAL', function () { suite('REAL', function () {
...@@ -526,6 +701,22 @@ suite(Support.getTestDialectTeaser('SQL'), function() { ...@@ -526,6 +701,22 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
postgres: 'FLOAT', postgres: 'FLOAT',
mssql: 'FLOAT' mssql: 'FLOAT'
}); });
suite('validate', function () {
test('should throw an error if `value` is invalid', function() {
var type = DataTypes.FLOAT();
expect(function () {
type.validate('foobar');
}).to.throw(Sequelize.ValidationError, '"foobar" is not a valid float');
});
test('should return `true` if `value` is a float', function() {
var type = DataTypes.FLOAT();
expect(type.validate(1.2)).to.equal(true);
});
});
}); });
if (current.dialect.supports.NUMERIC) { if (current.dialect.supports.NUMERIC) {
...@@ -560,12 +751,29 @@ suite(Support.getTestDialectTeaser('SQL'), function() { ...@@ -560,12 +751,29 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
}); });
}); });
// TODO: Fix Enums and add more tests suite('ENUM', function () {
// suite('ENUM', function () { // TODO: Fix Enums and add more tests
// testsql('ENUM("value 1", "value 2")', DataTypes.ENUM('value 1', 'value 2'), { // testsql('ENUM("value 1", "value 2")', DataTypes.ENUM('value 1', 'value 2'), {
// default: 'ENUM' // default: 'ENUM'
// }); // });
// });
suite('validate', function () {
test('should throw an error if `value` is invalid', function() {
var type = DataTypes.ENUM('foo');
expect(function () {
type.validate('foobar');
}).to.throw(Sequelize.ValidationError, '"foobar" is not a valid choice in ["foo"]');
});
test('should return `true` if `value` is a valid choice', function() {
var type = DataTypes.ENUM('foobar', 'foobiz');
expect(type.validate('foobar')).to.equal(true);
expect(type.validate('foobiz')).to.equal(true);
});
});
});
suite('BLOB', function () { suite('BLOB', function () {
testsql('BLOB', DataTypes.BLOB, { testsql('BLOB', DataTypes.BLOB, {
...@@ -597,6 +805,71 @@ suite(Support.getTestDialectTeaser('SQL'), function() { ...@@ -597,6 +805,71 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
mssql: 'VARBINARY(MAX)', mssql: 'VARBINARY(MAX)',
postgres: 'BYTEA' postgres: 'BYTEA'
}); });
suite('validate', function () {
test('should throw an error if `value` is invalid', function() {
var type = DataTypes.BLOB();
expect(function () {
type.validate(12345);
}).to.throw(Sequelize.ValidationError, '12345 is not a valid blob');
});
test('should return `true` if `value` is a blob', function() {
var type = DataTypes.BLOB();
expect(type.validate('foobar')).to.equal(true);
expect(type.validate(new Buffer('foobar'))).to.equal(true);
});
});
});
suite('RANGE', function () {
suite('validate', function () {
test('should throw an error if `value` is invalid', function() {
var type = DataTypes.RANGE();
expect(function () {
type.validate('foobar');
}).to.throw(Sequelize.ValidationError, '"foobar" is not a valid range');
});
test('should throw an error if `value` is not an array with two elements', function() {
var type = DataTypes.RANGE();
expect(function () {
type.validate([1]);
}).to.throw(Sequelize.ValidationError, 'A range must be an array with two elements');
});
test('should throw an error if `value.inclusive` is invalid', function() {
var type = DataTypes.RANGE();
expect(function () {
type.validate({ inclusive: 'foobar' });
}).to.throw(Sequelize.ValidationError, '"foobar" is not a valid range');
});
test('should throw an error if `value.inclusive` is not an array with two elements', function() {
var type = DataTypes.RANGE();
expect(function () {
type.validate({ inclusive: [1] });
}).to.throw(Sequelize.ValidationError, 'A range must be an array with two elements');
});
test('should return `true` if `value` is a range', function() {
var type = DataTypes.RANGE();
expect(type.validate([1, 2])).to.equal(true);
});
test('should return `true` if `value.inclusive` is a range', function() {
var type = DataTypes.RANGE();
expect(type.validate({ inclusive: [1, 2] })).to.equal(true);
});
});
}); });
if (current.dialect.supports.ARRAY) { if (current.dialect.supports.ARRAY) {
...@@ -664,6 +937,22 @@ suite(Support.getTestDialectTeaser('SQL'), function() { ...@@ -664,6 +937,22 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
postgres: 'JSONB[]' postgres: 'JSONB[]'
}); });
} }
suite('validate', function () {
test('should throw an error if `value` is invalid', function() {
var type = DataTypes.ARRAY();
expect(function () {
type.validate('foobar');
}).to.throw(Sequelize.ValidationError, '"foobar" is not a valid array');
});
test('should return `true` if `value` is an array', function() {
var type = DataTypes.ARRAY();
expect(type.validate(['foo', 'bar'])).to.equal(true);
});
});
}); });
} }
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!