Improve instance-level operation hooks
"before delete" and "after delete" hooks receive `ctx.instance` when a single model is being deleted. "before save" hook receives `ctx.currentInstance` when triggered by `prototype.updateAttributes()`. Note that "after save" hook triggered by `prototype.updateAttributes()` already provides `ctx.instance`.
This commit is contained in:
parent
2a24273b4f
commit
8605da3ac6
28
lib/dao.js
28
lib/dao.js
|
@ -1732,7 +1732,7 @@ 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 self = 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 hookState = {};
|
||||||
|
@ -1743,7 +1743,12 @@ DataAccessObject.prototype.remove =
|
||||||
|
|
||||||
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,
|
||||||
|
instance: inst,
|
||||||
|
hookState: hookState
|
||||||
|
};
|
||||||
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);
|
||||||
doDeleteInstance(ctx.where);
|
doDeleteInstance(ctx.where);
|
||||||
|
@ -1757,7 +1762,12 @@ DataAccessObject.prototype.remove =
|
||||||
// We must switch to full query-based delete.
|
// We must switch to full query-based delete.
|
||||||
Model.deleteAll(where, { notify: false }, function(err) {
|
Model.deleteAll(where, { notify: false }, function(err) {
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
var context = { Model: Model, where: where, hookState: hookState };
|
var context = {
|
||||||
|
Model: Model,
|
||||||
|
where: where,
|
||||||
|
instance: inst,
|
||||||
|
hookState: hookState
|
||||||
|
};
|
||||||
Model.notifyObserversOf('after delete', context, function(err) {
|
Model.notifyObserversOf('after delete', context, function(err) {
|
||||||
cb(err);
|
cb(err);
|
||||||
if (!err) Model.emit('deleted', id);
|
if (!err) Model.emit('deleted', id);
|
||||||
|
@ -1766,14 +1776,19 @@ DataAccessObject.prototype.remove =
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.trigger('destroy', function (destroyed) {
|
inst.trigger('destroy', function (destroyed) {
|
||||||
self._adapter().destroy(self.constructor.modelName, id, function (err) {
|
inst._adapter().destroy(inst.constructor.modelName, id, function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return cb(err);
|
return cb(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
destroyed(function () {
|
destroyed(function () {
|
||||||
var context = { Model: Model, where: where, hookState: hookState };
|
var context = {
|
||||||
|
Model: Model,
|
||||||
|
where: where,
|
||||||
|
instance: inst,
|
||||||
|
hookState: hookState
|
||||||
|
};
|
||||||
Model.notifyObserversOf('after delete', context, function(err) {
|
Model.notifyObserversOf('after delete', context, function(err) {
|
||||||
cb(err);
|
cb(err);
|
||||||
if (!err) Model.emit('deleted', id);
|
if (!err) Model.emit('deleted', id);
|
||||||
|
@ -1893,6 +1908,7 @@ DataAccessObject.prototype.updateAttributes = function updateAttributes(data, op
|
||||||
Model: Model,
|
Model: Model,
|
||||||
where: byIdQuery(Model, getIdValue(Model, inst)).where,
|
where: byIdQuery(Model, getIdValue(Model, inst)).where,
|
||||||
data: data,
|
data: data,
|
||||||
|
currentInstance: inst,
|
||||||
hookState: hookState
|
hookState: hookState
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -535,12 +535,15 @@ module.exports = function(dataSource, should) {
|
||||||
it('triggers `before save` hook', function(done) {
|
it('triggers `before save` hook', function(done) {
|
||||||
TestModel.observe('before save', pushContextAndNext());
|
TestModel.observe('before save', pushContextAndNext());
|
||||||
|
|
||||||
existingInstance.name = 'changed';
|
var currentInstance = deepCloneToObject(existingInstance);
|
||||||
|
|
||||||
existingInstance.updateAttributes({ name: 'changed' }, function(err) {
|
existingInstance.updateAttributes({ name: 'changed' }, function(err) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
|
existingInstance.name.should.equal('changed');
|
||||||
observedContexts.should.eql(aTestModelCtx({
|
observedContexts.should.eql(aTestModelCtx({
|
||||||
where: { id: existingInstance.id },
|
where: { id: existingInstance.id },
|
||||||
data: { name: 'changed' }
|
data: { name: 'changed' },
|
||||||
|
currentInstance: currentInstance
|
||||||
}));
|
}));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -736,10 +739,24 @@ module.exports = function(dataSource, should) {
|
||||||
{ id: existingInstance.id, name: 'updated name' },
|
{ id: existingInstance.id, name: 'updated name' },
|
||||||
function(err, instance) {
|
function(err, instance) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
|
if (dataSource.connector.updateOrCreate) {
|
||||||
|
// Atomic implementations of `updateOrCreate` cannot
|
||||||
|
// provide full instance as that depends on whether
|
||||||
|
// UPDATE or CREATE will be triggered
|
||||||
observedContexts.should.eql(aTestModelCtx({
|
observedContexts.should.eql(aTestModelCtx({
|
||||||
where: { id: existingInstance.id },
|
where: { id: existingInstance.id },
|
||||||
data: { id: existingInstance.id, name: 'updated name' }
|
data: { id: existingInstance.id, name: 'updated name' }
|
||||||
}));
|
}));
|
||||||
|
} else {
|
||||||
|
// currentInstance is set, because a non-atomic `updateOrCreate`
|
||||||
|
// will use `prototype.updateAttributes` internally, which
|
||||||
|
// exposes this to the context
|
||||||
|
observedContexts.should.eql(aTestModelCtx({
|
||||||
|
where: { id: existingInstance.id },
|
||||||
|
data: { id: existingInstance.id, name: 'updated name' },
|
||||||
|
currentInstance: existingInstance
|
||||||
|
}));
|
||||||
|
}
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1026,7 +1043,8 @@ module.exports = function(dataSource, should) {
|
||||||
existingInstance.delete(function(err) {
|
existingInstance.delete(function(err) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
observedContexts.should.eql(aTestModelCtx({
|
observedContexts.should.eql(aTestModelCtx({
|
||||||
where: { id: existingInstance.id }
|
where: { id: existingInstance.id },
|
||||||
|
instance: existingInstance
|
||||||
}));
|
}));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -1068,7 +1086,8 @@ module.exports = function(dataSource, should) {
|
||||||
existingInstance.delete(function(err) {
|
existingInstance.delete(function(err) {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
observedContexts.should.eql(aTestModelCtx({
|
observedContexts.should.eql(aTestModelCtx({
|
||||||
where: { id: existingInstance.id }
|
where: { id: existingInstance.id },
|
||||||
|
instance: existingInstance
|
||||||
}));
|
}));
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -1109,11 +1128,13 @@ module.exports = function(dataSource, should) {
|
||||||
observedContexts.should.eql([
|
observedContexts.should.eql([
|
||||||
aTestModelCtx({
|
aTestModelCtx({
|
||||||
hookState: { foo: 'bar', test: true },
|
hookState: { foo: 'bar', test: true },
|
||||||
where: { id: '1' }
|
where: { id: '1' },
|
||||||
|
instance: existingInstance
|
||||||
}),
|
}),
|
||||||
aTestModelCtx({
|
aTestModelCtx({
|
||||||
hookState: { foo: 'BAR', test: true },
|
hookState: { foo: 'BAR', test: true },
|
||||||
where: { id: '1' }
|
where: { id: '1' },
|
||||||
|
instance: existingInstance
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
done();
|
done();
|
||||||
|
|
Loading…
Reference in New Issue