Merge pull request #549 from fabien/feature/hookstate-from-options

Allow passing in hookState from options
This commit is contained in:
Raymond Feng 2015-03-30 14:35:34 -07:00
commit 44e5ad1fef
2 changed files with 146 additions and 42 deletions

View File

@ -178,6 +178,8 @@ DataAccessObject.create = function (data, options, cb) {
assert(typeof options === 'object', 'The options argument must be an object'); assert(typeof options === 'object', 'The options argument must be an object');
assert(typeof cb === 'function', 'The cb argument must be a function'); assert(typeof cb === 'function', 'The cb argument must be a function');
var hookState = {};
if (Array.isArray(data)) { if (Array.isArray(data)) {
// Undefined item will be skipped by async.map() which internally uses // Undefined item will be skipped by async.map() which internally uses
// Array.prototype.map(). The following loop makes sure all items are // Array.prototype.map(). The following loop makes sure all items are
@ -216,7 +218,6 @@ DataAccessObject.create = function (data, options, cb) {
var enforced = {}; var enforced = {};
var obj; var obj;
var idValue = getIdValue(this, data); var idValue = getIdValue(this, data);
var hookState = {};
// if we come from save // if we come from save
if (data instanceof Model && !idValue) { if (data instanceof Model && !idValue) {
@ -235,7 +236,8 @@ DataAccessObject.create = function (data, options, cb) {
Model: Model, Model: Model,
instance: obj, instance: obj,
isNewInstance: true, isNewInstance: true,
hookState: hookState hookState: hookState,
options: options
}; };
Model.notifyObserversOf('before save', context, function(err) { Model.notifyObserversOf('before save', context, function(err) {
if (err) return cb(err); if (err) return cb(err);
@ -279,7 +281,8 @@ DataAccessObject.create = function (data, options, cb) {
Model: Model, Model: Model,
instance: obj, instance: obj,
isNewInstance: true, isNewInstance: true,
hookState: hookState hookState: hookState,
options: options
}; };
Model.notifyObserversOf('after save', context, function(err) { Model.notifyObserversOf('after save', context, function(err) {
cb(err, obj); cb(err, obj);
@ -356,16 +359,22 @@ DataAccessObject.updateOrCreate = DataAccessObject.upsert = function upsert(data
assert(typeof options === 'object', 'The options argument must be an object'); assert(typeof options === 'object', 'The options argument must be an object');
assert(typeof cb === 'function', 'The cb argument must be a function'); assert(typeof cb === 'function', 'The cb argument must be a function');
var hookState = {};
var self = this; var self = this;
var Model = this; var Model = this;
var hookState = {};
var id = getIdValue(this, data); var id = getIdValue(this, data);
if (id === undefined || id === null) { if (id === undefined || id === null) {
return this.create(data, options, cb); return this.create(data, options, cb);
} }
var context = { Model: Model, query: byIdQuery(Model, id), hookState: hookState }; var context = {
Model: Model,
query: byIdQuery(Model, id),
hookState: hookState,
options: options
};
Model.notifyObserversOf('access', context, doUpdateOrCreate); Model.notifyObserversOf('access', context, doUpdateOrCreate);
function doUpdateOrCreate(err, ctx) { function doUpdateOrCreate(err, ctx) {
@ -377,7 +386,8 @@ DataAccessObject.updateOrCreate = DataAccessObject.upsert = function upsert(data
Model: Model, Model: Model,
where: ctx.query.where, where: ctx.query.where,
data: data, data: data,
hookState: hookState hookState: hookState,
options: options
}; };
Model.notifyObserversOf('before save', context, function(err, ctx) { Model.notifyObserversOf('before save', context, function(err, ctx) {
if (err) return cb(err); if (err) return cb(err);
@ -418,7 +428,8 @@ DataAccessObject.updateOrCreate = DataAccessObject.upsert = function upsert(data
Model: Model, Model: Model,
instance: obj, instance: obj,
isNewInstance: result ? result.isNewInstance : undefined, isNewInstance: result ? result.isNewInstance : undefined,
hookState: hookState hookState: hookState,
options: options
}; };
Model.notifyObserversOf('after save', context, function(err) { Model.notifyObserversOf('after save', context, function(err) {
cb(err, obj); cb(err, obj);
@ -502,9 +513,10 @@ DataAccessObject.findOrCreate = function findOrCreate(query, data, options, cb)
assert(typeof options === 'object', 'The options argument must be an object'); assert(typeof options === 'object', 'The options argument must be an object');
assert(typeof cb === 'function', 'The cb argument must be a function'); assert(typeof cb === 'function', 'The cb argument must be a function');
var hookState = {};
var Model = this; var Model = this;
var self = this; var self = this;
var hookState = {};
function _findOrCreate(query, data) { function _findOrCreate(query, data) {
var modelName = self.modelName; var modelName = self.modelName;
@ -524,7 +536,8 @@ DataAccessObject.findOrCreate = function findOrCreate(query, data, options, cb)
Model: Model, Model: Model,
instance: obj, instance: obj,
isNewInstance: true, isNewInstance: true,
hookState: hookState hookState: hookState,
options: options
}; };
Model.notifyObserversOf('after save', context, function(err) { Model.notifyObserversOf('after save', context, function(err) {
if (cb.promise) { if (cb.promise) {
@ -558,7 +571,12 @@ DataAccessObject.findOrCreate = function findOrCreate(query, data, options, cb)
this.applyScope(query); this.applyScope(query);
var context = { Model: Model, query: query, hookState: hookState }; var context = {
Model: Model,
query: query,
hookState: hookState,
options: options
};
Model.notifyObserversOf('access', context, function (err, ctx) { Model.notifyObserversOf('access', context, function (err, ctx) {
if (err) return cb(err); if (err) return cb(err);
@ -575,7 +593,8 @@ DataAccessObject.findOrCreate = function findOrCreate(query, data, options, cb)
Model: Model, Model: Model,
instance: obj, instance: obj,
isNewInstance: true, isNewInstance: true,
hookState: hookState hookState: hookState,
options: options
}; };
Model.notifyObserversOf('before save', context, function(err, ctx) { Model.notifyObserversOf('before save', context, function(err, ctx) {
if (err) return cb(err); if (err) return cb(err);
@ -1117,8 +1136,8 @@ DataAccessObject.find = function find(query, options, cb) {
assert(typeof options === 'object', 'The options argument must be an object'); assert(typeof options === 'object', 'The options argument must be an object');
assert(typeof cb === 'function', 'The cb argument must be a function'); assert(typeof cb === 'function', 'The cb argument must be a function');
var self = this;
var hookState = {}; var hookState = {};
var self = this;
try { try {
this._normalize(query); this._normalize(query);
@ -1143,7 +1162,12 @@ DataAccessObject.find = function find(query, options, cb) {
// using all documents // using all documents
// TODO [fabien] use default scope here? // TODO [fabien] use default scope here?
var context = { Model: self, query: query, hookState: hookState }; var context = {
Model: self,
query: query,
hookState: hookState,
options: options
};
self.notifyObserversOf('access', context, function(err, ctx) { self.notifyObserversOf('access', context, function(err, ctx) {
if (err) return cb(err); if (err) return cb(err);
@ -1238,7 +1262,12 @@ DataAccessObject.find = function find(query, options, cb) {
if (options.notify === false) { if (options.notify === false) {
self.getDataSource().connector.all(self.modelName, query, allCb); self.getDataSource().connector.all(self.modelName, query, allCb);
} else { } else {
var context = { Model: this, query: query, hookState: hookState }; var context = {
Model: this,
query: query,
hookState: hookState,
options: options
};
this.notifyObserversOf('access', context, function(err, ctx) { this.notifyObserversOf('access', context, function(err, ctx) {
if (err) return cb(err); if (err) return cb(err);
var query = ctx.query; var query = ctx.query;
@ -1332,24 +1361,37 @@ DataAccessObject.remove = DataAccessObject.deleteAll = DataAccessObject.destroyA
assert(typeof options === 'object', 'The options argument must be an object'); assert(typeof options === 'object', 'The options argument must be an object');
assert(typeof cb === 'function', 'The cb argument must be a function'); assert(typeof cb === 'function', 'The cb argument must be a function');
var hookState = {};
var query = { where: where }; var query = { where: where };
this.applyScope(query); this.applyScope(query);
where = query.where; where = query.where;
var hookState = {};
var context = { var context = {
Model: Model, where: whereIsEmpty(where) ? {} : where, hookState: hookState Model: Model,
where: whereIsEmpty(where) ? {} : where,
hookState: hookState,
options: options
}; };
if (options.notify === false) { if (options.notify === false) {
doDelete(where); doDelete(where);
} else { } else {
query = { where: whereIsEmpty(where) ? {} : where }; query = { where: whereIsEmpty(where) ? {} : where };
var context = { Model: Model, query: query, hookState: hookState }; var context = {
Model: Model,
query: query,
hookState: hookState,
options: options
};
Model.notifyObserversOf('access', context, function(err, ctx) { Model.notifyObserversOf('access', context, function(err, ctx) {
if (err) return cb(err); if (err) return cb(err);
var context = { Model: Model, where: ctx.query.where, hookState: hookState }; var context = {
Model: Model,
where: ctx.query.where,
hookState: hookState,
options: options
};
Model.notifyObserversOf('before delete', context, function(err, ctx) { Model.notifyObserversOf('before delete', context, function(err, ctx) {
if (err) return cb(err); if (err) return cb(err);
doDelete(ctx.where); doDelete(ctx.where);
@ -1382,7 +1424,12 @@ DataAccessObject.remove = DataAccessObject.deleteAll = DataAccessObject.destroyA
return cb(err, info); return cb(err, info);
} }
var context = { Model: Model, where: where, hookState: hookState }; var context = {
Model: Model,
where: where,
hookState: hookState,
options: options
};
Model.notifyObserversOf('after delete', context, function(err) { Model.notifyObserversOf('after delete', context, function(err) {
cb(err, info); cb(err, info);
if (!err) if (!err)
@ -1489,6 +1536,8 @@ DataAccessObject.count = function (where, options, cb) {
assert(typeof options === 'object', 'The options argument must be an object'); assert(typeof options === 'object', 'The options argument must be an object');
assert(typeof cb === 'function', 'The cb argument must be a function'); assert(typeof cb === 'function', 'The cb argument must be a function');
var hookState = {};
var query = { where: where }; var query = { where: where };
this.applyScope(query); this.applyScope(query);
where = query.where; where = query.where;
@ -1504,9 +1553,13 @@ DataAccessObject.count = function (where, options, cb) {
} }
var Model = this; var Model = this;
var hookState = {};
var context = { Model: Model, query: { where: where }, hookState: hookState }; var context = {
Model: Model,
query: { where: where },
hookState: hookState,
options: options
};
this.notifyObserversOf('access', context, function(err, ctx) { this.notifyObserversOf('access', context, function(err, ctx) {
if (err) return cb(err); if (err) return cb(err);
where = ctx.query.where; where = ctx.query.where;
@ -1541,6 +1594,8 @@ DataAccessObject.prototype.save = function (options, cb) {
assert(typeof options === 'object', 'The options argument should be an object'); assert(typeof options === 'object', 'The options argument should be an object');
assert(typeof cb === 'function', 'The cb argument should be a function'); assert(typeof cb === 'function', 'The cb argument should be a function');
var hookState = {};
if (options.validate === undefined) { if (options.validate === undefined) {
options.validate = true; options.validate = true;
} }
@ -1554,9 +1609,13 @@ DataAccessObject.prototype.save = function (options, cb) {
var inst = this; var inst = this;
var modelName = Model.modelName; var modelName = Model.modelName;
var hookState = {};
var context = { Model: Model, instance: inst, hookState: hookState }; var context = {
Model: Model,
instance: inst,
hookState: hookState,
options: options
};
Model.notifyObserversOf('before save', context, function(err) { Model.notifyObserversOf('before save', context, function(err) {
if (err) return cb(err); if (err) return cb(err);
@ -1596,7 +1655,8 @@ DataAccessObject.prototype.save = function (options, cb) {
Model: Model, Model: Model,
instance: inst, instance: inst,
isNewInstance: result && result.isNewInstance, isNewInstance: result && result.isNewInstance,
hookState: hookState hookState: hookState,
options: options
}; };
Model.notifyObserversOf('after save', context, function(err) { Model.notifyObserversOf('after save', context, function(err) {
if (err) return cb(err, inst); if (err) return cb(err, inst);
@ -1674,6 +1734,8 @@ DataAccessObject.updateAll = function (where, data, options, cb) {
assert(typeof options === 'object', 'The options argument must be an object'); assert(typeof options === 'object', 'The options argument must be an object');
assert(typeof cb === 'function', 'The cb argument must be a function'); assert(typeof cb === 'function', 'The cb argument must be a function');
var hookState = {};
var query = { where: where }; var query = { where: where };
this.applyScope(query); this.applyScope(query);
this.applyProperties(data); this.applyProperties(data);
@ -1681,13 +1743,21 @@ DataAccessObject.updateAll = function (where, data, options, cb) {
where = query.where; where = query.where;
var Model = this; var Model = this;
var hookState = {};
var context = { Model: Model, query: { where: where }, hookState: hookState }; var context = {
Model: Model,
query: { where: where },
hookState: hookState,
options: options
};
Model.notifyObserversOf('access', context, function(err, ctx) { Model.notifyObserversOf('access', context, function(err, ctx) {
if (err) return cb(err); if (err) return cb(err);
var context = { var context = {
Model: Model, where: ctx.query.where, data: data, hookState: hookState Model: Model,
where: ctx.query.where,
data: data,
hookState: hookState,
options: options
}; };
Model.notifyObserversOf('before save', context, Model.notifyObserversOf('before save', context,
function(err, ctx) { function(err, ctx) {
@ -1713,7 +1783,11 @@ DataAccessObject.updateAll = function (where, data, options, cb) {
connector.update(Model.modelName, where, data, function(err, info) { connector.update(Model.modelName, where, data, function(err, info) {
if (err) return cb (err); if (err) return cb (err);
var context = { var context = {
Model: Model, where: where, data: data, hookState: hookState Model: Model,
where: where,
data: data,
hookState: hookState,
options: options
}; };
Model.notifyObserversOf('after save', context, function(err, ctx) { Model.notifyObserversOf('after save', context, function(err, ctx) {
return cb(err, info); return cb(err, info);
@ -1762,13 +1836,17 @@ DataAccessObject.prototype.remove =
assert(typeof options === 'object', 'The options argument should be an object'); assert(typeof options === 'object', 'The options argument should be an object');
assert(typeof cb === 'function', 'The cb argument should be a function'); assert(typeof cb === 'function', 'The cb argument should be a function');
var hookState = {};
var inst = this; var inst = this;
var Model = this.constructor; var Model = this.constructor;
var id = getIdValue(this.constructor, this); var id = getIdValue(this.constructor, this);
var hookState = {};
var context = { var context = {
Model: Model, query: byIdQuery(Model, id), hookState: hookState Model: Model,
query: byIdQuery(Model, id),
hookState: hookState,
options: options
}; };
Model.notifyObserversOf('access', context, function(err, ctx) { Model.notifyObserversOf('access', context, function(err, ctx) {
@ -1777,7 +1855,8 @@ DataAccessObject.prototype.remove =
Model: Model, Model: Model,
where: ctx.query.where, where: ctx.query.where,
instance: inst, instance: inst,
hookState: hookState hookState: hookState,
options: options
}; };
Model.notifyObserversOf('before delete', context, function(err, ctx) { Model.notifyObserversOf('before delete', context, function(err, ctx) {
if (err) return cb(err); if (err) return cb(err);
@ -1796,7 +1875,8 @@ DataAccessObject.prototype.remove =
Model: Model, Model: Model,
where: where, where: where,
instance: inst, instance: inst,
hookState: hookState hookState: hookState,
options: options
}; };
Model.notifyObserversOf('after delete', context, function(err) { Model.notifyObserversOf('after delete', context, function(err) {
cb(err); cb(err);
@ -1817,7 +1897,8 @@ DataAccessObject.prototype.remove =
Model: Model, Model: Model,
where: where, where: where,
instance: inst, instance: inst,
hookState: hookState hookState: hookState,
options: options
}; };
Model.notifyObserversOf('after delete', context, function(err) { Model.notifyObserversOf('after delete', context, function(err) {
cb(err); cb(err);
@ -1944,10 +2025,11 @@ DataAccessObject.prototype.updateAttributes = function updateAttributes(data, op
assert(typeof options === 'object', 'The options argument must be an object'); assert(typeof options === 'object', 'The options argument must be an object');
assert(typeof cb === 'function', 'The cb argument must be a function'); assert(typeof cb === 'function', 'The cb argument must be a function');
var hookState = {};
var inst = this; var inst = this;
var Model = this.constructor; var Model = this.constructor;
var model = Model.modelName; var model = Model.modelName;
var hookState = {};
// Convert the data to be plain object so that update won't be confused // Convert the data to be plain object so that update won't be confused
if (data instanceof Model) { if (data instanceof Model) {
@ -1974,7 +2056,8 @@ DataAccessObject.prototype.updateAttributes = function updateAttributes(data, op
where: byIdQuery(Model, getIdValue(Model, inst)).where, where: byIdQuery(Model, getIdValue(Model, inst)).where,
data: data, data: data,
currentInstance: inst, currentInstance: inst,
hookState: hookState hookState: hookState,
options: options
}; };
Model.notifyObserversOf('before save', context, function(err, ctx) { Model.notifyObserversOf('before save', context, function(err, ctx) {
@ -2015,7 +2098,8 @@ DataAccessObject.prototype.updateAttributes = function updateAttributes(data, op
Model: Model, Model: Model,
instance: inst, instance: inst,
isNewInstance: false, isNewInstance: false,
hookState: hookState hookState: hookState,
options: options
}; };
Model.notifyObserversOf('after save', context, function(err) { Model.notifyObserversOf('after save', context, function(err) {
if(!err) Model.emit('changed', inst); if(!err) Model.emit('changed', inst);

View File

@ -473,8 +473,8 @@ module.exports = function(dataSource, should) {
observedContexts.should.eql(aTestModelCtx({ instance: { observedContexts.should.eql(aTestModelCtx({ instance: {
id: existingInstance.id, id: existingInstance.id,
name: 'changed', name: 'changed',
extra: undefined extra: undefined,
}})); }, options: { throws: false, validate: true } }));
done(); done();
}); });
}); });
@ -524,8 +524,8 @@ module.exports = function(dataSource, should) {
name: 'changed', name: 'changed',
extra: undefined extra: undefined
}, },
isNewInstance: false isNewInstance: false,
})); options: { throws: false, validate: true } }));
done(); done();
}); });
}); });
@ -1297,6 +1297,23 @@ module.exports = function(dataSource, should) {
done(); done();
}); });
}); });
it('accepts hookState from options', function(done) {
TestModel.observe('after save', pushContextAndNext());
TestModel.updateAll(
{ id: existingInstance.id },
{ name: 'updated name' },
{ foo: 'bar' },
function(err) {
if (err) return done(err);
observedContexts.options.should.eql({
foo: 'bar'
});
done();
});
});
}); });
function pushContextAndNext(fn) { function pushContextAndNext(fn) {
@ -1351,6 +1368,9 @@ module.exports = function(dataSource, should) {
if (!ctx.hookState) { if (!ctx.hookState) {
ctx.hookState = { test: true }; ctx.hookState = { test: true };
} }
if (!ctx.options) {
ctx.options = {};
}
return deepCloneToObject(ctx); return deepCloneToObject(ctx);
} }