Async validations hooks
This commit is contained in:
parent
fbf118695e
commit
3b2b57eb7b
|
@ -107,15 +107,21 @@ AbstractClass.create = function (data) {
|
||||||
if (data instanceof AbstractClass && !data.id) {
|
if (data instanceof AbstractClass && !data.id) {
|
||||||
obj = data;
|
obj = data;
|
||||||
data = obj.toObject(true);
|
data = obj.toObject(true);
|
||||||
|
create();
|
||||||
} else {
|
} else {
|
||||||
obj = new this(data);
|
obj = new this(data);
|
||||||
|
|
||||||
// validation required
|
// validation required
|
||||||
if (!obj.isValid()) {
|
obj.isValid(function (valid) {
|
||||||
return callback(new Error('Validation error'), obj);
|
if (!valid) {
|
||||||
|
callback(new Error('Validation error'), obj);
|
||||||
|
} else {
|
||||||
|
create();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function create() {
|
||||||
obj.trigger("create", function () {
|
obj.trigger("create", function () {
|
||||||
this._adapter().create(modelName, data, function (err, id) {
|
this._adapter().create(modelName, data, function (err, id) {
|
||||||
if (id) {
|
if (id) {
|
||||||
|
@ -127,6 +133,7 @@ AbstractClass.create = function (data) {
|
||||||
}
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
});
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
AbstractClass.exists = function exists(id, cb) {
|
AbstractClass.exists = function exists(id, cb) {
|
||||||
|
@ -221,14 +228,26 @@ AbstractClass.prototype.save = function (options, callback) {
|
||||||
options.throws = false;
|
options.throws = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.validate && !this.isValid()) {
|
if (options.validate) {
|
||||||
|
this.isValid(function (valid) {
|
||||||
|
if (valid) {
|
||||||
|
save.call(this);
|
||||||
|
} else {
|
||||||
var err = new Error('Validation error');
|
var err = new Error('Validation error');
|
||||||
|
// throws option is dangerous for async usage
|
||||||
if (options.throws) {
|
if (options.throws) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
return callback && callback(err, this);
|
if (callback) {
|
||||||
|
callback(err, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
} else {
|
||||||
|
save.call(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function save() {
|
||||||
this.trigger("save", function(){
|
this.trigger("save", function(){
|
||||||
var modelName = this.constructor.modelName;
|
var modelName = this.constructor.modelName;
|
||||||
var data = this.toObject(true);
|
var data = this.toObject(true);
|
||||||
|
@ -249,6 +268,7 @@ AbstractClass.prototype.save = function (options, callback) {
|
||||||
this.constructor.create(this, callback);
|
this.constructor.create(this, callback);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
AbstractClass.prototype.isNewRecord = function () {
|
AbstractClass.prototype.isNewRecord = function () {
|
||||||
|
@ -295,11 +315,17 @@ AbstractClass.prototype.updateAttributes = function updateAttributes(data, cb) {
|
||||||
this[key] = data[key];
|
this[key] = data[key];
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
if (!this.isValid()) {
|
this.isValid(function (valid) {
|
||||||
var err = new Error('Validation error');
|
if (!valid) {
|
||||||
return cb && cb(err);
|
if (cb) {
|
||||||
|
cb(new Error('Validation error'));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
update.call(this);
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
function update() {
|
||||||
this.trigger("update", function(){
|
this.trigger("update", function(){
|
||||||
this._adapter().updateAttributes(model, this.id, data, function (err) {
|
this._adapter().updateAttributes(model, this.id, data, function (err) {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
|
@ -316,6 +342,7 @@ AbstractClass.prototype.updateAttributes = function updateAttributes(data, cb) {
|
||||||
cb(err);
|
cb(err);
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
});
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -12,7 +12,7 @@ Validatable.validatesExclusionOf = getConfigurator('exclusion');
|
||||||
Validatable.validatesFormatOf = getConfigurator('format');
|
Validatable.validatesFormatOf = getConfigurator('format');
|
||||||
Validatable.validate = getConfigurator('custom');
|
Validatable.validate = getConfigurator('custom');
|
||||||
Validatable.validateAsync = getConfigurator('custom', {async: true});
|
Validatable.validateAsync = getConfigurator('custom', {async: true});
|
||||||
Validatable.validateUniquenessOf = getConfigurator('uniqueness');
|
Validatable.validatesUniquenessOf = getConfigurator('uniqueness', {async: true});
|
||||||
|
|
||||||
// implementation of validators
|
// implementation of validators
|
||||||
var validators = {
|
var validators = {
|
||||||
|
@ -70,8 +70,20 @@ var validators = {
|
||||||
err();
|
err();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
custom: function (attr, conf, err, cb) {
|
custom: function (attr, conf, err, done) {
|
||||||
conf.customValidator.call(this, err, cb);
|
conf.customValidator.call(this, err, done);
|
||||||
|
},
|
||||||
|
uniqueness: function (attr, conf, err, done) {
|
||||||
|
var cond = {where: {}};
|
||||||
|
cond.where[attr] = this[attr];
|
||||||
|
this.constructor.all(cond, function (error, found) {
|
||||||
|
if (found.length > 1) {
|
||||||
|
err();
|
||||||
|
} else if (found.length === 1 && found[0].id !== this.id) {
|
||||||
|
err();
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
}.bind(this));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -88,6 +100,9 @@ Validatable.prototype.isValid = function (callback) {
|
||||||
// exit with success when no errors
|
// exit with success when no errors
|
||||||
if (!this.constructor._validations) {
|
if (!this.constructor._validations) {
|
||||||
cleanErrors(this);
|
cleanErrors(this);
|
||||||
|
if (callback) {
|
||||||
|
callback(valid);
|
||||||
|
}
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,6 +136,7 @@ Validatable.prototype.isValid = function (callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (valid) cleanErrors(this);
|
if (valid) cleanErrors(this);
|
||||||
|
if (!async && callback) callback(valid);
|
||||||
|
|
||||||
return valid;
|
return valid;
|
||||||
};
|
};
|
||||||
|
@ -216,7 +232,8 @@ var defaultMessages = {
|
||||||
'number': 'is not a number'
|
'number': 'is not a number'
|
||||||
},
|
},
|
||||||
inclusion: 'is not included in the list',
|
inclusion: 'is not included in the list',
|
||||||
exclusion: 'is reserved'
|
exclusion: 'is reserved',
|
||||||
|
uniqueness: 'is not unique'
|
||||||
};
|
};
|
||||||
|
|
||||||
function nullCheck(attr, conf, err) {
|
function nullCheck(attr, conf, err) {
|
||||||
|
|
|
@ -57,6 +57,10 @@ function testOrm(schema) {
|
||||||
published: { type: Boolean, default: false }
|
published: { type: Boolean, default: false }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Post.validateAsync('title', function (err, done) {
|
||||||
|
process.nextTick(done);
|
||||||
|
});
|
||||||
|
|
||||||
User.hasMany(Post, {as: 'posts', foreignKey: 'userId'});
|
User.hasMany(Post, {as: 'posts', foreignKey: 'userId'});
|
||||||
// creates instance methods:
|
// creates instance methods:
|
||||||
// user.posts(conds)
|
// user.posts(conds)
|
||||||
|
|
|
@ -27,6 +27,16 @@ validAttributes =
|
||||||
createdByAdmin: false
|
createdByAdmin: false
|
||||||
createdByScript: true
|
createdByScript: true
|
||||||
|
|
||||||
|
getValidAttributes = ->
|
||||||
|
name: 'Anatoliy'
|
||||||
|
email: 'email@example.com'
|
||||||
|
state: ''
|
||||||
|
age: 26
|
||||||
|
gender: 'male'
|
||||||
|
domain: '1602'
|
||||||
|
createdByAdmin: false
|
||||||
|
createdByScript: true
|
||||||
|
|
||||||
it 'should validate presence', (test) ->
|
it 'should validate presence', (test) ->
|
||||||
User.validatesPresenceOf 'email', 'name'
|
User.validatesPresenceOf 'email', 'name'
|
||||||
|
|
||||||
|
@ -251,3 +261,16 @@ it 'should validate asynchronously', (test) ->
|
||||||
test.ok not valid, 'not valid name'
|
test.ok not valid, 'not valid name'
|
||||||
test.done()
|
test.done()
|
||||||
|
|
||||||
|
it 'should validate uniqueness', (test) ->
|
||||||
|
User.validatesUniquenessOf 'email'
|
||||||
|
User.create getValidAttributes(), ->
|
||||||
|
user = new User getValidAttributes()
|
||||||
|
|
||||||
|
# test.ok not user.isValid(), 'not valid because async validation'
|
||||||
|
user.isValid (valid) ->
|
||||||
|
test.ok not valid, 'email is not unique'
|
||||||
|
user.email = 'unique@email.tld'
|
||||||
|
user.isValid (valid) ->
|
||||||
|
test.ok valid, 'valid with unique email'
|
||||||
|
test.done()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue