Merge pull request #1445 from strongloop/fix/validate-update
Add validation on update
This commit is contained in:
commit
2f7dd90f1f
16
lib/dao.js
16
lib/dao.js
|
@ -2689,7 +2689,21 @@ DataAccessObject.updateAll = function(where, data, options, cb) {
|
|||
Model.notifyObserversOf('before save', context,
|
||||
function(err, ctx) {
|
||||
if (err) return cb(err);
|
||||
doUpdate(ctx.where, ctx.data);
|
||||
|
||||
data = ctx.data;
|
||||
var inst = data;
|
||||
if (!(data instanceof Model)) {
|
||||
inst = new Model(data, {applyDefaultValues: false});
|
||||
}
|
||||
|
||||
// validation required
|
||||
inst.isValid(function(valid) {
|
||||
if (valid) {
|
||||
doUpdate(ctx.where, ctx.data);
|
||||
} else {
|
||||
cb(new ValidationError(inst), inst);
|
||||
}
|
||||
}, options);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -2259,6 +2259,8 @@ describe('manipulation', function() {
|
|||
});
|
||||
|
||||
it('should not coerce invalid values provided in where conditions', function(done) {
|
||||
// remove the validations since update/updateAll validates the model
|
||||
delete Person.validations;
|
||||
Person.update({name: 'Brett Boe'}, {dob: 'notadate'}, function(err) {
|
||||
should.exist(err);
|
||||
err.message.should.equal('Invalid date: notadate');
|
||||
|
|
|
@ -26,7 +26,7 @@ function getValidAttributes() {
|
|||
}
|
||||
|
||||
describe('validations', function() {
|
||||
var User, Entry;
|
||||
var User, Entry, Employee;
|
||||
|
||||
before(function(done) {
|
||||
db = getSchema();
|
||||
|
@ -47,8 +47,16 @@ describe('validations', function() {
|
|||
id: {type: 'string', id: true, generated: false},
|
||||
name: {type: 'string'},
|
||||
});
|
||||
Employee = db.define('Employee', {
|
||||
id: {type: Number, id: true, generated: false},
|
||||
name: {type: String},
|
||||
age: {type: Number},
|
||||
});
|
||||
Entry.validatesUniquenessOf('id');
|
||||
db.automigrate(done);
|
||||
db.automigrate(function(err) {
|
||||
should.not.exist(err);
|
||||
Employee.create(empData, done);
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(function(done) {
|
||||
|
@ -58,8 +66,8 @@ describe('validations', function() {
|
|||
});
|
||||
});
|
||||
|
||||
after(function() {
|
||||
// db.disconnect();
|
||||
after(function(done) {
|
||||
Employee.destroyAll(done);
|
||||
});
|
||||
|
||||
describe('commons', function() {
|
||||
|
@ -390,6 +398,51 @@ describe('validations', function() {
|
|||
user.domain = 'domain';
|
||||
user.isValid().should.be.true;
|
||||
});
|
||||
|
||||
describe('validate presence on update', function() {
|
||||
before(function(done) {
|
||||
Employee.destroyAll(function(err) {
|
||||
should.not.exist(err);
|
||||
delete Employee.validations;
|
||||
db.automigrate('Employee', function(err) {
|
||||
should.not.exist(err);
|
||||
Employee.create(empData, function(err, inst) {
|
||||
should.not.exist(err);
|
||||
should.exist(inst);
|
||||
Employee.validatesPresenceOf('name', 'age');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('succeeds when validate condition is met', function(done) {
|
||||
var data = {name: 'Foo-new', age: 5};
|
||||
Employee.updateAll({id: 1}, data,
|
||||
function(err, emp) {
|
||||
should.not.exist(err);
|
||||
should.exist(emp);
|
||||
should.equal(emp.count, 1);
|
||||
Employee.find({where: {id: 1}}, function(err, emp) {
|
||||
should.not.exist(err);
|
||||
should.exist(emp);
|
||||
data.id = 1;
|
||||
should.deepEqual(data, emp[0].toObject());
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('throws err when validate condition is not met', function(done) {
|
||||
Employee.updateAll({where: {id: 1}}, {name: 'Foo-new'},
|
||||
function(err, emp) {
|
||||
should.exist(err);
|
||||
should.equal(err.statusCode, 422);
|
||||
should.equal(err.details.messages.age[0], 'can\'t be blank');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('absence', function() {
|
||||
|
@ -402,6 +455,52 @@ describe('validations', function() {
|
|||
u = new User({reserved: 'foo', locked: false});
|
||||
u.isValid().should.be.true;
|
||||
});
|
||||
|
||||
describe('validate absence on update', function() {
|
||||
before(function(done) {
|
||||
Employee.destroyAll(function(err) {
|
||||
should.not.exist(err);
|
||||
delete Employee.validations;
|
||||
db.automigrate('Employee', function(err) {
|
||||
should.not.exist(err);
|
||||
Employee.create(empData, function(err, inst) {
|
||||
should.not.exist(err);
|
||||
should.exist(inst);
|
||||
Employee.validatesAbsenceOf('name');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('succeeds when validate condition is met', function(done) {
|
||||
var data = {age: 5};
|
||||
Employee.updateAll({id: 1}, data,
|
||||
function(err, emp) {
|
||||
should.not.exist(err);
|
||||
should.exist(emp);
|
||||
should.equal(emp.count, 1);
|
||||
Employee.find({where: {id: 1}}, function(err, emp) {
|
||||
should.not.exist(err);
|
||||
should.exist(emp);
|
||||
data.id = 1;
|
||||
data.name = 'Foo';
|
||||
should.deepEqual(data, emp[0].toObject());
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('throws err when validate condition is not met', function(done) {
|
||||
Employee.updateAll({where: {id: 1}}, {name: 'Foo-new', age: 5},
|
||||
function(err, emp) {
|
||||
should.exist(err);
|
||||
should.equal(err.statusCode, 422);
|
||||
should.equal(err.details.messages.name[0], 'can\'t be set');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('uniqueness', function() {
|
||||
|
@ -613,6 +712,51 @@ describe('validations', function() {
|
|||
});
|
||||
})).should.be.false();
|
||||
});
|
||||
|
||||
describe('validate uniqueness on update', function() {
|
||||
before(function(done) {
|
||||
Employee.destroyAll(function(err) {
|
||||
should.not.exist(err);
|
||||
delete Employee.validations;
|
||||
db.automigrate('Employee', function(err) {
|
||||
should.not.exist(err);
|
||||
Employee.create(empData, function(err, inst) {
|
||||
should.not.exist(err);
|
||||
should.exist(inst);
|
||||
Employee.validatesUniquenessOf('name');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('succeeds when validate condition is met', function(done) {
|
||||
var data = {name: 'Foo-new', age: 5};
|
||||
Employee.updateAll({id: 1}, data,
|
||||
function(err, emp) {
|
||||
should.not.exist(err);
|
||||
should.exist(emp);
|
||||
should.equal(emp.count, 1);
|
||||
Employee.find({where: {id: 1}}, function(err, emp) {
|
||||
should.not.exist(err);
|
||||
should.exist(emp);
|
||||
data.id = 1;
|
||||
should.deepEqual(data, emp[0].toObject());
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('throws err when validate condition is not met', function(done) {
|
||||
Employee.updateAll({where: {id: 1}}, {name: 'Bar', age: 5},
|
||||
function(err, emp) {
|
||||
should.exist(err);
|
||||
should.equal(err.statusCode, 422);
|
||||
should.equal(err.details.messages.name[0], 'is not unique');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('format', function() {
|
||||
|
@ -642,6 +786,51 @@ describe('validations', function() {
|
|||
var u = new User({email: null});
|
||||
u.isValid().should.be.false;
|
||||
});
|
||||
|
||||
describe('validate format on update', function() {
|
||||
before(function(done) {
|
||||
Employee.destroyAll(function(err) {
|
||||
should.not.exist(err);
|
||||
delete Employee.validations;
|
||||
db.automigrate('Employee', function(err) {
|
||||
should.not.exist(err);
|
||||
Employee.create(empData, function(err, inst) {
|
||||
should.not.exist(err);
|
||||
should.exist(inst);
|
||||
Employee.validatesFormatOf('name', {with: /^\w+\s\w+$/, allowNull: false});
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('succeeds when validate condition is met', function(done) {
|
||||
var data = {name: 'Foo Mo', age: 5};
|
||||
Employee.updateAll({id: 1}, data,
|
||||
function(err, emp) {
|
||||
should.not.exist(err);
|
||||
should.exist(emp);
|
||||
should.equal(emp.count, 1);
|
||||
Employee.find({where: {id: 1}}, function(err, emp) {
|
||||
should.not.exist(err);
|
||||
should.exist(emp);
|
||||
data.id = 1;
|
||||
should.deepEqual(data, emp[0].toObject());
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('throws err when validate condition is not met', function(done) {
|
||||
Employee.updateAll({where: {id: 1}}, {name: '45foo', age: 5},
|
||||
function(err, emp) {
|
||||
should.exist(err);
|
||||
should.equal(err.statusCode, 422);
|
||||
should.equal(err.details.messages.name[0], 'is invalid');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('numericality', function() {
|
||||
|
@ -703,6 +892,51 @@ describe('validations', function() {
|
|||
user.isValid().should.be.false();
|
||||
user.errors.should.match({age: /is not an integer/});
|
||||
});
|
||||
|
||||
describe('validate numericality on update', function() {
|
||||
before(function(done) {
|
||||
Employee.destroyAll(function(err) {
|
||||
should.not.exist(err);
|
||||
delete Employee.validations;
|
||||
db.automigrate('Employee', function(err) {
|
||||
should.not.exist(err);
|
||||
Employee.create(empData, function(err, inst) {
|
||||
should.not.exist(err);
|
||||
should.exist(inst);
|
||||
Employee.validatesNumericalityOf('age');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('succeeds when validate condition is met', function(done) {
|
||||
var data = {name: 'Foo-new', age: 5};
|
||||
Employee.updateAll({id: 1}, data,
|
||||
function(err, emp) {
|
||||
should.not.exist(err);
|
||||
should.exist(emp);
|
||||
should.equal(emp.count, 1);
|
||||
Employee.find({where: {id: 1}}, function(err, emp) {
|
||||
should.not.exist(err);
|
||||
should.exist(emp);
|
||||
data.id = 1;
|
||||
should.deepEqual(data, emp[0].toObject());
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('throws err when validate condition is not met', function(done) {
|
||||
Employee.updateAll({where: {id: 1}}, {age: {someAge: 5}},
|
||||
function(err, emp) {
|
||||
should.exist(err);
|
||||
should.equal(err.statusCode, 422);
|
||||
should.equal(err.details.messages.age[0], 'is not a number');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('inclusion', function() {
|
||||
|
@ -774,6 +1008,52 @@ describe('validations', function() {
|
|||
function getErrorDetails(err) {
|
||||
return err.message.replace(/^.*Details: /, '');
|
||||
}
|
||||
|
||||
describe('validate inclusion on update', function() {
|
||||
before(function(done) {
|
||||
Employee.destroyAll(function(err) {
|
||||
should.not.exist(err);
|
||||
delete Employee.validations;
|
||||
db.automigrate('Employee', function(err) {
|
||||
should.not.exist(err);
|
||||
Employee.create(empData, function(err, inst) {
|
||||
should.not.exist(err);
|
||||
should.exist(inst);
|
||||
Employee.validatesInclusionOf('name', {in: ['Foo-new']});
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('succeeds when validate condition is met', function(done) {
|
||||
var data = {name: 'Foo-new', age: 5};
|
||||
Employee.updateAll({id: 1}, data,
|
||||
function(err, emp) {
|
||||
should.not.exist(err);
|
||||
should.exist(emp);
|
||||
should.equal(emp.count, 1);
|
||||
Employee.find({where: {id: 1}}, function(err, emp) {
|
||||
should.not.exist(err);
|
||||
should.exist(emp);
|
||||
data.id = 1;
|
||||
should.deepEqual(data, emp[0].toObject());
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('throws err when validate condition is not met', function(done) {
|
||||
Employee.updateAll({where: {id: 1}}, {name: 'Foo-new2', age: 5},
|
||||
function(err, emp) {
|
||||
should.exist(err);
|
||||
should.equal(err.statusCode, 422);
|
||||
should.equal(err.details.messages.name[0], 'is not included in ' +
|
||||
'the list');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('exclusion', function() {
|
||||
|
@ -826,10 +1106,100 @@ describe('validations', function() {
|
|||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('validate exclusion on update', function() {
|
||||
before(function(done) {
|
||||
Employee.destroyAll(function(err) {
|
||||
should.not.exist(err);
|
||||
delete Employee.validations;
|
||||
db.automigrate('Employee', function(err) {
|
||||
should.not.exist(err);
|
||||
Employee.create(empData, function(err, inst) {
|
||||
should.not.exist(err);
|
||||
should.exist(inst);
|
||||
Employee.validatesExclusionOf('name', {in: ['Bob']});
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('succeeds when validate condition is met', function(done) {
|
||||
var data = {name: 'Foo-new', age: 5};
|
||||
Employee.updateAll({id: 1}, data,
|
||||
function(err, emp) {
|
||||
should.not.exist(err);
|
||||
should.exist(emp);
|
||||
should.equal(emp.count, 1);
|
||||
Employee.find({where: {id: 1}}, function(err, emp) {
|
||||
should.not.exist(err);
|
||||
should.exist(emp);
|
||||
data.id = 1;
|
||||
should.deepEqual(data, emp[0].toObject());
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('throws err when validate condition is not met', function(done) {
|
||||
Employee.updateAll({where: {id: 1}}, {name: 'Bob', age: 5},
|
||||
function(err, emp) {
|
||||
should.exist(err);
|
||||
should.equal(err.statusCode, 422);
|
||||
should.equal(err.details.messages.name[0], 'is reserved');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('length', function() {
|
||||
it('should validate length');
|
||||
|
||||
describe('validate length on update', function() {
|
||||
before(function(done) {
|
||||
Employee.destroyAll(function(err) {
|
||||
should.not.exist(err);
|
||||
delete Employee.validations;
|
||||
db.automigrate('Employee', function(err) {
|
||||
should.not.exist(err);
|
||||
Employee.create(empData, function(err, inst) {
|
||||
should.not.exist(err);
|
||||
should.exist(inst);
|
||||
Employee.validatesLengthOf('name', {min: 5});
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('succeeds when validate condition is met', function(done) {
|
||||
var data = {name: 'Foo-new', age: 5};
|
||||
Employee.updateAll({id: 1}, data,
|
||||
function(err, emp) {
|
||||
should.not.exist(err);
|
||||
should.exist(emp);
|
||||
should.equal(emp.count, 1);
|
||||
Employee.find({where: {id: 1}}, function(err, emp) {
|
||||
should.not.exist(err);
|
||||
should.exist(emp);
|
||||
data.id = 1;
|
||||
should.deepEqual(data, emp[0].toObject());
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('throws err when validate condition is not met', function(done) {
|
||||
Employee.updateAll({where: {id: 1}}, {name: 'Bob', age: 5},
|
||||
function(err, emp) {
|
||||
should.exist(err);
|
||||
should.equal(err.statusCode, 422);
|
||||
should.equal(err.details.messages.name[0], 'too short');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('custom', function() {
|
||||
|
@ -938,6 +1308,7 @@ describe('validations', function() {
|
|||
return err.message.replace(/^.*Details: /, '');
|
||||
}
|
||||
});
|
||||
|
||||
describe('date', function() {
|
||||
it('should validate a date object', function() {
|
||||
User.validatesDateOf('updatedAt');
|
||||
|
@ -1013,3 +1384,17 @@ describe('validations', function() {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
var empData = [{
|
||||
id: 1,
|
||||
name: 'Foo',
|
||||
age: 1,
|
||||
}, {
|
||||
id: 2,
|
||||
name: 'Bar',
|
||||
age: 2,
|
||||
}, {
|
||||
id: 3,
|
||||
name: 'Baz',
|
||||
age: 3,
|
||||
}];
|
||||
|
|
Loading…
Reference in New Issue