Added active record style callbacks and hooks. Before and after create, save, update, destroy and after initialization.
This commit is contained in:
parent
13bfb1c972
commit
39bbece115
|
@ -2,12 +2,14 @@
|
||||||
* Module deps
|
* Module deps
|
||||||
*/
|
*/
|
||||||
var Validatable = require('./validatable').Validatable;
|
var Validatable = require('./validatable').Validatable;
|
||||||
|
var Hookable = require('./hookable').Hookable;
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
var jutil = require('./jutil');
|
var jutil = require('./jutil');
|
||||||
|
|
||||||
exports.AbstractClass = AbstractClass;
|
exports.AbstractClass = AbstractClass;
|
||||||
|
|
||||||
jutil.inherits(AbstractClass, Validatable);
|
jutil.inherits(AbstractClass, Validatable);
|
||||||
|
jutil.inherits(AbstractClass, Hookable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class constructor
|
* Abstract class constructor
|
||||||
|
@ -79,6 +81,8 @@ function AbstractClass(data) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.trigger("initialize");
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -107,21 +111,24 @@ AbstractClass.create = function (data) {
|
||||||
obj = new this(data);
|
obj = new this(data);
|
||||||
|
|
||||||
// validation required
|
// validation required
|
||||||
if (!obj.isValid()) {
|
obj.trigger("validation", function(){
|
||||||
return callback(new Error('Validation error'), obj);
|
if (!obj.isValid()) {
|
||||||
}
|
return callback(new Error('Validation error'), obj);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.schema.adapter.create(modelName, data, function (err, id) {
|
obj.trigger("create", function(){
|
||||||
if (id) {
|
this._adapter().create(modelName, data, function (err, id) {
|
||||||
defineReadonlyProp(obj, 'id', id);
|
if (id) {
|
||||||
this.cache[id] = obj;
|
defineReadonlyProp(obj, 'id', id);
|
||||||
}
|
this.constructor.cache[id] = obj;
|
||||||
if (callback) {
|
}
|
||||||
callback(err, obj);
|
if (callback) {
|
||||||
}
|
callback(err, obj);
|
||||||
}.bind(this));
|
}
|
||||||
|
}.bind(this));
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
AbstractClass.exists = function exists(id, cb) {
|
AbstractClass.exists = function exists(id, cb) {
|
||||||
|
@ -213,29 +220,36 @@ AbstractClass.prototype.save = function (options, callback) {
|
||||||
if (!('throws' in options)) {
|
if (!('throws' in options)) {
|
||||||
options.throws = false;
|
options.throws = false;
|
||||||
}
|
}
|
||||||
if (options.validate && !this.isValid()) {
|
this.trigger("validation", function(){
|
||||||
var err = new Error('Validation error');
|
if (options.validate && !this.isValid()) {
|
||||||
if (options.throws) {
|
var err = new Error('Validation error');
|
||||||
throw err;
|
if (options.throws) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
return callback && callback(err);
|
||||||
}
|
}
|
||||||
return callback && callback(err);
|
});
|
||||||
}
|
|
||||||
var modelName = this.constructor.modelName;
|
this.trigger("save", function(){
|
||||||
var data = this.toObject(true);
|
var modelName = this.constructor.modelName;
|
||||||
if (this.id) {
|
var data = this.toObject(true);
|
||||||
this._adapter().save(modelName, data, function (err) {
|
if (this.id) {
|
||||||
if (err) {
|
this.trigger("update", function(){
|
||||||
console.log(err);
|
this._adapter().save(modelName, data, function (err) {
|
||||||
} else {
|
if (err) {
|
||||||
this.constructor.call(this, data);
|
console.log(err);
|
||||||
}
|
} else {
|
||||||
if (callback) {
|
this.constructor.call(this, data);
|
||||||
callback(err, this);
|
}
|
||||||
}
|
if (callback) {
|
||||||
}.bind(this));
|
callback(err, this);
|
||||||
} else {
|
}
|
||||||
this.constructor.create(this, callback);
|
}.bind(this));
|
||||||
}
|
});
|
||||||
|
} else {
|
||||||
|
this.constructor.create(this, callback);
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
AbstractClass.prototype.isNewRecord = function () {
|
AbstractClass.prototype.isNewRecord = function () {
|
||||||
|
@ -262,10 +276,12 @@ AbstractClass.prototype.toObject = function (onlySchema) {
|
||||||
};
|
};
|
||||||
|
|
||||||
AbstractClass.prototype.destroy = function (cb) {
|
AbstractClass.prototype.destroy = function (cb) {
|
||||||
this._adapter().destroy(this.constructor.modelName, this.id, function (err) {
|
this.trigger("destroy", function(){
|
||||||
delete this.constructor.cache[this.id];
|
this._adapter().destroy(this.constructor.modelName, this.id, function (err) {
|
||||||
cb && cb(err);
|
delete this.constructor.cache[this.id];
|
||||||
}.bind(this));
|
cb && cb(err);
|
||||||
|
}.bind(this));
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
AbstractClass.prototype.updateAttribute = function (name, value, cb) {
|
AbstractClass.prototype.updateAttribute = function (name, value, cb) {
|
||||||
|
@ -279,24 +295,29 @@ AbstractClass.prototype.updateAttributes = function updateAttributes(data, cb) {
|
||||||
Object.keys(data).forEach(function (key) {
|
Object.keys(data).forEach(function (key) {
|
||||||
this[key] = data[key];
|
this[key] = data[key];
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
if (!this.isValid()) {
|
this.trigger("validation", function(){
|
||||||
var err = new Error('Validation error');
|
if (!this.isValid()) {
|
||||||
return cb && cb(err);
|
var err = new Error('Validation error');
|
||||||
}
|
return cb && cb(err);
|
||||||
this._adapter().updateAttributes(model, this.id, data, function (err) {
|
|
||||||
if (!err) {
|
|
||||||
Object.keys(data).forEach(function (key) {
|
|
||||||
this[key] = data[key];
|
|
||||||
Object.defineProperty(this, key + '_was', {
|
|
||||||
writable: false,
|
|
||||||
configurable: true,
|
|
||||||
enumerable: false,
|
|
||||||
value: data[key]
|
|
||||||
});
|
|
||||||
}.bind(this));
|
|
||||||
}
|
}
|
||||||
cb(err);
|
});
|
||||||
}.bind(this));
|
|
||||||
|
this.trigger("update", function(){
|
||||||
|
this._adapter().updateAttributes(model, this.id, data, function (err) {
|
||||||
|
if (!err) {
|
||||||
|
Object.keys(data).forEach(function (key) {
|
||||||
|
this[key] = data[key];
|
||||||
|
Object.defineProperty(this, key + '_was', {
|
||||||
|
writable: false,
|
||||||
|
configurable: true,
|
||||||
|
enumerable: false,
|
||||||
|
value: data[key]
|
||||||
|
});
|
||||||
|
}.bind(this));
|
||||||
|
}
|
||||||
|
cb(err);
|
||||||
|
}.bind(this));
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
exports.Hookable = Hookable;
|
||||||
|
|
||||||
|
function Hookable() {
|
||||||
|
// hookable class
|
||||||
|
};
|
||||||
|
|
||||||
|
Hookable.afterInitialize = function(){};
|
||||||
|
Hookable.beforeValidation = function(){};
|
||||||
|
Hookable.afterValidation = function(){};
|
||||||
|
Hookable.beforeSave = function(){};
|
||||||
|
Hookable.afterSave = function(){};
|
||||||
|
Hookable.beforeCreate = function(){};
|
||||||
|
Hookable.afterCreate = function(){};
|
||||||
|
Hookable.beforeUpdate = function(){};
|
||||||
|
Hookable.afterUpdate = function(){};
|
||||||
|
Hookable.beforeDestroy = function(){};
|
||||||
|
Hookable.afterDestroy = function(){};
|
||||||
|
|
||||||
|
Hookable.prototype.trigger = function(action, work){
|
||||||
|
if(work){
|
||||||
|
bHook = this.constructor["before" + capitalize(action)];
|
||||||
|
if(bHook) bHook.call( this );
|
||||||
|
|
||||||
|
work.call(this)
|
||||||
|
}
|
||||||
|
aHook = this.constructor["after" + capitalize(action)];
|
||||||
|
if(aHook) aHook.call( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
function capitalize(string){
|
||||||
|
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
juggling = require('../index')
|
||||||
|
Schema = juggling.Schema
|
||||||
|
AbstractClass = juggling.AbstractClass
|
||||||
|
Hookable = juggling.Hookable
|
||||||
|
|
||||||
|
require('./spec_helper').init module.exports
|
||||||
|
|
||||||
|
schema = new Schema 'memory'
|
||||||
|
User = schema.define 'User',
|
||||||
|
email: String
|
||||||
|
name: String
|
||||||
|
password: String
|
||||||
|
state: String
|
||||||
|
age: Number
|
||||||
|
gender: String
|
||||||
|
domain: String
|
||||||
|
pendingPeriod: Number
|
||||||
|
createdByAdmin: Boolean
|
||||||
|
|
||||||
|
it "should trigger after initialize", (test)->
|
||||||
|
User.afterInitialize = ()->
|
||||||
|
User.afterInitialize = null
|
||||||
|
test.done()
|
||||||
|
user = new User
|
||||||
|
|
||||||
|
|
||||||
|
it "should trigger before create", (test)->
|
||||||
|
User.beforeCreate = ()->
|
||||||
|
User.beforeCreate = null
|
||||||
|
test.done()
|
||||||
|
User.create {}, ()-> test.ok "saved"
|
||||||
|
|
||||||
|
it "should trigger after create", (test)->
|
||||||
|
User.afterCreate = ()->
|
||||||
|
User.afterCreate = null
|
||||||
|
test.done()
|
||||||
|
User.create {}, ()-> test.ok "saved"
|
||||||
|
|
||||||
|
it "should trigger before save", (test)->
|
||||||
|
User.beforeSave = ()->
|
||||||
|
User.beforeSave = null
|
||||||
|
test.done()
|
||||||
|
user = new User
|
||||||
|
user.save ()-> test.ok "saved"
|
||||||
|
|
||||||
|
it "should trigger after save", (test)->
|
||||||
|
User.afterSave = ()->
|
||||||
|
User.afterSave = null
|
||||||
|
test.done()
|
||||||
|
user = new User
|
||||||
|
user.save ()-> test.ok "saved"
|
||||||
|
|
||||||
|
it "should trigger before update", (test)->
|
||||||
|
User.beforeUpdate = ()->
|
||||||
|
User.beforeUpdate = null
|
||||||
|
test.done()
|
||||||
|
User.create {}, (err, user)->
|
||||||
|
user.updateAttributes {email:"1@1.com"}, ()-> test.ok "updated"
|
||||||
|
|
||||||
|
it "should trigger after update", (test)->
|
||||||
|
User.afterUpdate = ()->
|
||||||
|
User.afterUpdate = null
|
||||||
|
test.done()
|
||||||
|
User.create {}, (err, user)->
|
||||||
|
user.updateAttributes {email:"1@1.com"}, ()-> test.ok "updated"
|
||||||
|
|
||||||
|
it "should trigger before destroy", (test)->
|
||||||
|
User.beforeDestroy = ()->
|
||||||
|
User.beforeDestroy = null
|
||||||
|
test.done()
|
||||||
|
User.create {}, (err, user)->
|
||||||
|
user.destroy()
|
||||||
|
|
||||||
|
it "should trigger after destroy", (test)->
|
||||||
|
User.afterDestroy = ()->
|
||||||
|
User.afterDestroy = null
|
||||||
|
test.done()
|
||||||
|
User.create {}, (err, user)->
|
||||||
|
user.destroy()
|
Loading…
Reference in New Issue