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

Commit 939203b4 by Jan Aagaard Meier

feat(validations) Partial rollback of datatype validation by hiding behind a fla…

…g. Soften up some validation and restrict them to insert and create
1 parent a15d4233
# Next
- [FIXED] Partial rollback of datatype validations by hiding it behind the `validation` flag.
# 3.11.0
- [INTERNALS] Updated dependencies [#4594](https://github.com/sequelize/sequelize/pull/4594)
+ bluebird@2.10.1
......
......@@ -84,10 +84,8 @@ STRING.prototype.toSql = function() {
};
STRING.prototype.validate = function(value) {
if (Object.prototype.toString.call(value) !== '[object String]') {
if (this.options.binary) {
if (Buffer.isBuffer(value)) {
return true;
}
if ((this.options.binary && Buffer.isBuffer(value)) || _.isNumber(value)) {
return true;
}
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid string', value));
}
......@@ -352,7 +350,7 @@ DECIMAL.prototype.toSql = function() {
return 'DECIMAL';
};
DECIMAL.prototype.validate = function(value) {
if (!_.isNumber(value)) {
if (!Validator.isDecimal(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid decimal', value));
}
......@@ -374,7 +372,7 @@ BOOLEAN.prototype.toSql = function() {
return 'TINYINT(1)';
};
BOOLEAN.prototype.validate = function(value) {
if (!_.isBoolean(value)) {
if (!Validator.isBoolean(value)) {
throw new sequelizeErrors.ValidationError(util.format('%j is not a valid boolean', value));
}
......
......@@ -289,7 +289,7 @@ var QueryGenerator = {
identityWrapperRequired = true;
}
values.push(this.escape(value, (modelAttributeMap && modelAttributeMap[key]) || undefined));
values.push(this.escape(value, (modelAttributeMap && modelAttributeMap[key]) || undefined, { context: 'INSERT' }));
}
}
}
......@@ -413,7 +413,7 @@ var QueryGenerator = {
}
var value = attrValueHash[key];
values.push(this.quoteIdentifier(key) + '=' + this.escape(value, (modelAttributeMap && modelAttributeMap[key] || undefined)));
values.push(this.quoteIdentifier(key) + '=' + this.escape(value, (modelAttributeMap && modelAttributeMap[key] || undefined), { context: 'UPDATE' }));
}
var replacements = {
......@@ -894,11 +894,12 @@ var QueryGenerator = {
/*
Escape a value (e.g. a string, number or date)
*/
escape: function(value, field) {
escape: function(value, field, options) {
options = options || {};
if (value && value._isSequelizeMethod) {
return this.handleSequelizeMethod(value);
} else {
if (field && field.type && value) {
if (['INSERT', 'UPDATE'].indexOf(options.context) !== -1 &&this.validation && field && field.type && value) {
if (field.type.validate) {
field.type.validate(value);
}
......
......@@ -353,13 +353,15 @@ var QueryGenerator = {
return Utils.addTicks(identifier, '`');
},
escape: function(value, field) {
escape: function(value, field, options) {
options = options || {};
if (value && value._isSequelizeMethod) {
return this.handleSequelizeMethod(value);
} else if (value && field && field.type instanceof DataTypes.GEOMETRY) {
return 'GeomFromText(\'' + Wkt.stringify(value) + '\')';
} else {
if (field && field.type && value) {
if (['INSERT', 'UPDATE'].indexOf(options.context) !== -1 && this.validation && field && field.type && value) {
if (field.type.validate) {
field.type.validate(value);
}
......
......@@ -895,12 +895,14 @@ var QueryGenerator = {
/*
Escape a value (e.g. a string, number or date)
*/
escape: function(value, field) {
escape: function(value, field, options) {
options = options || {};
if (value && value._isSequelizeMethod) {
return this.handleSequelizeMethod(value);
}
if (field && field.type && value) {
if (['INSERT', 'UPDATE'].indexOf(options.context) !== -1 && this.validation && field && field.type && value) {
if (field.type.validate) {
field.type.validate(value);
}
......
......@@ -189,7 +189,7 @@ var QueryGenerator = {
for (var key in attrValueHash) {
var value = attrValueHash[key];
values.push(this.quoteIdentifier(key) + '=' + this.escape(value, (modelAttributeMap && modelAttributeMap[key] || undefined)));
values.push(this.quoteIdentifier(key) + '=' + this.escape(value, (modelAttributeMap && modelAttributeMap[key] || undefined), { context: 'UPDATE' }));
}
var replacements = {
......
......@@ -80,6 +80,7 @@ var url = require('url')
* @param {Function} [options.pool.validateConnection] A function that validates a connection. Called with client. The default function checks that client is an object, and that its state is not disconnected
* @param {Boolean} [options.quoteIdentifiers=true] Set to `false` to make table names and attributes case-insensitive on Postgres and skip double quoting of them.
* @param {String} [options.isolationLevel='REPEATABLE_READ'] Set the default transaction isolation level. See `Sequelize.Transaction.ISOLATION_LEVELS` for possible options.
* @param {Boolean [options.validation=false] Run built in type validators on insert and update, e.g. validate that arguments passed to integer fields are integer-like
*/
/**
......@@ -143,7 +144,8 @@ var Sequelize = function(database, username, password, options) {
quoteIdentifiers: true,
hooks: {},
isolationLevel: Transaction.ISOLATION_LEVELS.REPEATABLE_READ,
databaseVersion: 0
databaseVersion: 0,
validation: false
}, options || {});
if (this.options.dialect === 'postgresql') {
......@@ -203,6 +205,8 @@ var Sequelize = function(database, username, password, options) {
throw new Error('The dialect ' + this.getDialect() + ' is not supported. ('+err+')');
}
this.dialect.QueryGenerator.validation = options.validation;
/**
* Models are stored here under the name given to `sequelize.define`
* @property models
......
......@@ -12,10 +12,10 @@ var chai = require('chai')
describe(Support.getTestDialectTeaser('Model'), function() {
describe('method findOne', function () {
before(function () {
this.oldfindAll = current.Model.prototype.findAll;
this.oldFindAll = current.Model.prototype.findAll;
});
after(function () {
current.Model.prototype.findAll = this.oldfindall;
current.Model.prototype.findAll = this.oldFindAll;
});
beforeEach(function () {
......
......@@ -3,12 +3,15 @@
/* jshint -W030 */
/* jshint -W110 */
var chai = require('chai')
, sinon = require('sinon')
, expect = chai.expect
, Sequelize = require(__dirname + '/../../../index')
, Support = require(__dirname + '/../support')
, current = Support.sequelize
, Promise = current.Promise
, config = require(__dirname + '/../../config/config');
describe(Support.getTestDialectTeaser('InstanceValidator'), function() {
describe('validations', function() {
var checks = {
......@@ -266,10 +269,95 @@ describe(Support.getTestDialectTeaser('InstanceValidator'), function() {
});
describe('datatype validations', function () {
describe('should throw validationerror', function () {
var User = current.define('user', {
age: Sequelize.INTEGER
current = Support.createSequelizeInstance({
validation: true
});
var User = current.define('user', {
age: Sequelize.INTEGER,
name: Sequelize.STRING,
awesome: Sequelize.BOOLEAN,
number: Sequelize.DECIMAL,
uid: Sequelize.UUID
});
before(function () {
this.stub = sinon.stub(current, 'query', function () {
return new Promise(function (resolve) {
resolve(User.build({}));
});
});
});
after(function () {
this.stub.restore();
});
describe('should not throw', function () {
describe('create', function () {
it('should allow number as a string', function () {
return expect(User.create({
age: '12'
})).not.to.be.rejected;
});
it('should allow decimal as a string', function () {
return expect(User.create({
number: '12.6'
})).not.to.be.rejected;
});
it('should allow string as a number', function () {
return expect(User.create({
name: 12
})).not.to.be.rejected;
});
it('should allow 0/1 as a boolean', function () {
return expect(User.create({
awesome: 1
})).not.to.be.rejected;
});
it('should allow 0/1 string as a boolean', function () {
return expect(User.create({
awesome: '1'
})).not.to.be.rejected;
});
it('should allow true/false string as a boolean', function () {
return expect(User.create({
awesome: 'true'
})).not.to.be.rejected;
});
});
describe('findAll', function () {
it('should allow $in', function () {
return expect(User.all({
where: {
name: {
$like: {
$any: ['foo%', 'bar%']
}
}
}
})).not.to.be.rejected;
});
it('should allow $like for uuid', function () {
return expect(User.all({
where: {
uid: {
$like: '12345678%'
}
}
})).not.to.be.rejected;
});
});
});
describe('should throw validationerror', function () {
describe('create', function () {
it('should throw when passing string', function () {
......
......@@ -51,14 +51,6 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
});
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();
......@@ -66,6 +58,7 @@ suite(Support.getTestDialectTeaser('SQL'), function() {
/*jshint -W053 */
expect(type.validate(new String('foobar'))).to.equal(true);
/*jshint +W053 */
expect(type.validate(12)).to.equal(true);
});
});
});
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!