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

Commit 4339799d by Daniel Durante

Initial commit for hooks.. need to stash this for another PR

1 parent 3a46e499
Showing with 311 additions and 24 deletions
......@@ -25,7 +25,11 @@ module.exports = (function() {
schemaDelimiter: '',
language: 'en',
defaultScope: null,
scopes: null
scopes: null,
hooks: {
beforeCreate: [],
afterCreate: []
}
}, options || {})
// error check options
......@@ -632,19 +636,116 @@ module.exports = (function() {
*
* @param {Object} where Options to describe the scope of the search.
* @param {Object} options Possible options are:
- hooks: If set to true, destroy will find all records within the where parameter and will execute before/afterDestroy hooks on each row
- limit: How many rows to delete
- truncate: If set to true, dialects that support it will use TRUNCATE instead of DELETE FROM. If a table is truncated the where and limit options are ignored
* @return {Object} A promise which fires `success`, `error`, `complete` and `sql`.
*/
DAOFactory.prototype.destroy = function(where, options) {
if (this.options.timestamps && this.options.paranoid) {
var attr = Utils._.underscoredIf(this.options.deletedAt, this.options.underscored)
var attrValueHash = {}
attrValueHash[attr] = Utils.now()
return this.QueryInterface.bulkUpdate(this.tableName, attrValueHash, where)
} else {
return this.QueryInterface.bulkDelete(this.tableName, where, options)
}
var self = this
, query = null
, args = []
return new Utils.CustomEventEmitter(function(emitter) {
self.runHooks.call(self, self.options.hooks.beforeBulkDestroy, where, function(err, newValues) {
if (!!err) {
return emitter.emit('error', err)
}
where = newValues
if (self.options.timestamps && self.options.paranoid) {
var attr = Utils._.underscoredIf(self.options.deletedAt, self.options.underscored)
var attrValueHash = {}
attrValueHash[attr] = Utils.now()
query = 'bulkUpdate'
args = [self.tableName, attrValueHash, where]
} else {
query = 'bulkDelete'
args = [self.tableName, where, options]
}
var runQuery = function(err, records) {
if (!!err) {
return emitter.emit('error', err)
}
query = self.QueryInterface[query].apply(self.QueryInterface, args)
query.on('sql', function(sql) {
emitter.emit('sql', sql)
})
.error(function(err) {
emitter.emit('error', err)
})
.success(function(results) {
var finished = function(err) {
if (!!err) {
return emitter.emit('error', err)
}
self.runHooks.call(self, self.options.hooks.afterBulkDestroy, where, function(err) {
if (!!err) {
return emitter.emit('error', err)
}
emitter.emit('success', results)
})
}
if (options && options.hooks === true) {
var tick = 0
var next = function(i) {
self.runHooks.call(self, self.options.hooks.afterDestroy, records[i].dataValues, function(err, newValues) {
if (!!err) {
return finished(err)
}
records[i].dataValues = newValues
tick++
if (tick === records.length) {
return finished()
}
next(tick)
})
}
next(tick)
} else {
finished()
}
})
}
if (options && options.hooks === true) {
var tick = 0
self.all({where: where}).success(function(records) {
var next = function(i) {
self.runHooks.call(self, self.options.hooks.beforeDestroy, records[i].values, function(err, newValues) {
if (!!err) {
return runQuery(err)
}
records[i].dataValues = newValues
tick++
if (tick === records.length) {
return runQuery(null, records)
}
next(tick)
})
}
next(tick)
})
//
} else {
runQuery()
}
})
}).run()
}
/**
......@@ -814,6 +915,7 @@ module.exports = (function() {
}
Utils._.extend(DAOFactory.prototype, require("./associations/mixin"))
Utils._.extend(DAOFactory.prototype, require(__dirname + '/hooks'))
return DAOFactory
})()
......@@ -168,9 +168,15 @@ module.exports = (function() {
this.dataValues[updatedAtAttr] = values[updatedAtAttr] = Utils.now(this.sequelize.options.dialect)
}
var query = null
, args = []
, hook = ''
if (this.isNewRecord) {
this.isDirty = false
return this.QueryInterface.insert(this, this.QueryInterface.QueryGenerator.addSchema(this.__factory), values)
this.isDirty = false
query = 'insert'
args = [this, this.QueryInterface.QueryGenerator.addSchema(this.__factory), values]
hook = 'Create'
} else {
var identifier = this.__options.hasPrimaryKeys ? this.primaryKeyValues : { id: this.id };
......@@ -178,12 +184,40 @@ module.exports = (function() {
identifier = this.__options.whereCollection;
}
this.isDirty = false
var tableName = this.QueryInterface.QueryGenerator.addSchema(this.__factory)
, query = this.QueryInterface.update(this, tableName, values, identifier, options)
return query
this.isDirty = false
query = 'update'
args = [this, this.QueryInterface.QueryGenerator.addSchema(this.__factory), values, identifier, options]
hook = 'Update'
}
return new Utils.CustomEventEmitter(function(saveEmitter) {
self.__factory.runHooks.call(self, self.__factory.options.hooks['before' + hook], values, function(err, newValues) {
if (!!err) {
return saveEmitter.emit('error', err)
}
// redeclare our new values
args[2] = newValues
self.QueryInterface[query].apply(self.QueryInterface, args)
.on('sql', function(sql) {
saveEmitter.emit('sql', sql)
})
.error(function(err) {
saveEmitter.emit('err', err)
})
.success(function(result) {
self.__factory.runHooks.call(self, self.__factory.options.hooks['after' + hook], result.values, function(err, newValues) {
if (!!err) {
return saveEmitter.emit('error', err)
}
result.dataValues = newValues
saveEmitter.emit('success', result)
})
})
})
}).run()
}
/*
......@@ -225,6 +259,8 @@ module.exports = (function() {
* @return null if and only if validation successful; otherwise an object containing { field name : [error msgs] } entries.
*/
DAO.prototype.validate = function(object) {
var self = this
var validator = new DaoValidator(this, object)
, errors = validator.validate()
......@@ -277,14 +313,44 @@ module.exports = (function() {
}
DAO.prototype.destroy = function() {
if (this.__options.timestamps && this.__options.paranoid) {
var attr = Utils._.underscoredIf(this.__options.deletedAt, this.__options.underscored)
this.dataValues[attr] = new Date()
return this.save()
} else {
var identifier = this.__options.hasPrimaryKeys ? this.primaryKeyValues : { id: this.id };
return this.QueryInterface.delete(this, this.QueryInterface.QueryGenerator.addSchema(this.__factory.tableName, this.__factory.options.schema), identifier)
}
var self = this
, query = null
return new Utils.CustomEventEmitter(function(emitter) {
self.daoFactory.runHooks.call(self, self.daoFactory.options.hooks.beforeDestroy, self.dataValues, function(err, newValues) {
if (!!err) {
return emitter.emit('error', err)
}
self.dataValues = newValues
if (self.__options.timestamps && self.__options.paranoid) {
var attr = Utils._.underscoredIf(self.__options.deletedAt, self.__options.underscored)
self.dataValues[attr] = new Date()
query = self.save()
} else {
var identifier = self.__options.hasPrimaryKeys ? self.primaryKeyValues : { id: self.id };
query = self.QueryInterface.delete(self, self.QueryInterface.QueryGenerator.addSchema(self.__factory.tableName, self.__factory.options.schema), identifier)
}
query.on('sql', function(sql) {
emitter.emit('sql', sql)
})
.error(function(err) {
emitter.emit('error', err)
})
.success(function(results) {
self.daoFactory.runHooks.call(self, self.daoFactory.options.hooks.afterDestroy, self.dataValues, function(err, newValues) {
if (!!err) {
return emitter.emit('error', err)
}
self.dataValues = newValues
emitter.emit('success', results)
})
})
})
}).run()
}
DAO.prototype.increment = function(fields, count) {
......
var Utils = require("./utils")
var Hooks = module.exports = function(){}
Hooks.runHooks = function(hooks, daoValues, fn) {
var self = this
, tick = 0
var run = function(hook) {
if (!hook) {
return fn(null, daoValues);
}
if (typeof hook === "object") {
hook = hook.fn
}
hook.call(self, daoValues, function(err, newValues) {
tick++
if (!!err) {
return fn(err)
}
daoValues = newValues
return run(hooks[tick])
})
}
run(hooks[tick])
}
Hooks.hook = function(hookType, name, fn) {
Hooks.addHook.call(this, hookType, name, fn)
}
Hooks.addHook = function(hookType, name, fn) {
if (typeof name === "function") {
fn = name
name = null
}
var method = function(daoValues, callback) {
fn.call(this, daoValues, callback)
}
// Just in case if we override the default DAOFactory.options
this.options.hooks[hookType] = this.options.hooks[hookType] || []
this.options.hooks[hookType][this.options.hooks[hookType].length] = !!name ? {name: name, fn: method} : method
}
Hooks.beforeValidate = function(name, fn) {
Hooks.addHook.call(this, 'beforeValidate', name, fn)
}
Hooks.afterValidate = function(name, fn) {
Hooks.addHook.call(this, 'afterValidate', name, fn)
}
Hooks.beforeCreate = function(name, fn) {
Hooks.addHook.call(this, 'beforeCreate', name, fn)
}
Hooks.afterCreate = function(name, fn) {
Hooks.addHook.call(this, 'afterCreate', name, fn)
}
Hooks.beforeDestroy = function(name, fn) {
Hooks.addHook.call(this, 'beforeDestroy', name, fn)
}
Hooks.afterDestroy = function(name, fn) {
Hooks.addHook.call(this, 'afterDestroy', name, fn)
}
Hooks.beforeBulkDestroy = function(name, fn) {
Hooks.addHook.call(this, 'beforeBulkDestroy', name, fn)
}
Hooks.afterBulkDestroy = function(name, fn) {
Hooks.addHook.call(this, 'afterBulkDestroy', name, fn)
}
// - beforeSave
// - afterSave
// - beforeUpdate
// - afterUpdate
// - beforeDestroy
// - afterDestroy
// - beforeValidate
// - afterValidate
// user.save(callback); // If Model.id isn't set, save will invoke Model.create() instead
// // beforeValidate
// // afterValidate
// // beforeSave
// // beforeUpdate
// // afterUpdate
// // afterSave
// // callback
// user.updateAttribute('email', 'email@example.com', callback);
// // beforeValidate
// // afterValidate
// // beforeSave
// // beforeUpdate
// // afterUpdate
// // afterSave
// // callback
// user.destroy(callback);
// // beforeDestroy
// // afterDestroy
// // callback
// User.create(data, callback);
// // beforeValidate
// // afterValidate
// // beforeCreate
// // beforeSave
// // afterSave
// // afterCreate
// // callback
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!