From 370966df999e0745b1de57115ec2fb939abb99e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Thu, 29 Jan 2015 10:09:01 +0100 Subject: [PATCH] Implement intent hook `before delete` Methods `DAO.deleteAll` and `DAO.prototype.delete` now invoke `before delete` hook too. The hook receives `ctx.where` describing models to be deleted. --- lib/dao.js | 14 ++++- test/persistence-hooks.suite.js | 92 +++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 2 deletions(-) diff --git a/lib/dao.js b/lib/dao.js index 51e64417..e002bf2e 100644 --- a/lib/dao.js +++ b/lib/dao.js @@ -995,7 +995,11 @@ DataAccessObject.remove = DataAccessObject.deleteAll = DataAccessObject.destroyA { Model: Model, query: query }, function(err, ctx) { if (err) return cb(err); - doDelete(ctx.query.where); + var context = { Model: Model, where: ctx.query.where }; + Model.notifyObserversOf('before delete', context, function(err, ctx) { + if (err) return cb(err); + doDelete(ctx.where); + }); }); } @@ -1311,7 +1315,13 @@ DataAccessObject.prototype.remove = { Model: Model, query: byIdQuery(Model, id) }, function(err, ctx) { if (err) return cb(err); - doDeleteInstance(ctx.query.where); + Model.notifyObserversOf( + 'before delete', + { Model: Model, where: ctx.query.where }, + function(err, ctx) { + if (err) return cb(err); + doDeleteInstance(ctx.where); + }); }); function doDeleteInstance(where) { diff --git a/test/persistence-hooks.suite.js b/test/persistence-hooks.suite.js index 6d4865e8..9a523d6a 100644 --- a/test/persistence-hooks.suite.js +++ b/test/persistence-hooks.suite.js @@ -893,6 +893,57 @@ module.exports = function(dataSource, should) { }); }); + it('triggers `before delete` hook with query', function(done) { + TestModel.observe('before delete', pushContextAndNext()); + + TestModel.deleteAll({ name: existingInstance.name }, function(err) { + if (err) return done(err); + observedContexts.should.eql(aTestModelCtx({ + where: { name: existingInstance.name } + })); + done(); + }); + }); + + it('triggers `before delete` hook without query', function(done) { + TestModel.observe('before delete', pushContextAndNext()); + + TestModel.deleteAll(function(err) { + if (err) return done(err); + observedContexts.should.eql(aTestModelCtx({ where: {} })); + done(); + }); + }); + + it('applies updates from `before delete` hook', function(done) { + TestModel.observe('before delete', function(ctx, next) { + ctx.where = { id: { neq: existingInstance.id } }; + next(); + }); + + TestModel.deleteAll(function(err) { + if (err) return done(err); + findTestModels(function(err, list) { + if (err) return done(err); + (list || []).map(get('id')).should.eql([existingInstance.id]); + done(); + }); + }); + }); + + it('aborts when `before delete` hook fails', function(done) { + TestModel.observe('before delete', nextWithError(expectedError)); + + TestModel.deleteAll(function(err, list) { + [err].should.eql([expectedError]); + TestModel.findById(existingInstance.id, function(err, inst) { + if (err) return done(err); + (inst ? inst.toObject() : 'null').should.eql(existingInstance.toObject()); + done(); + }); + }); + }); + it('triggers `after delete` hook without query', function(done) { TestModel.observe('after delete', pushContextAndNext()); @@ -954,6 +1005,47 @@ module.exports = function(dataSource, should) { }); }); + it('triggers `before delete` hook', function(done) { + TestModel.observe('before delete', pushContextAndNext()); + + existingInstance.delete(function(err) { + if (err) return done(err); + observedContexts.should.eql(aTestModelCtx({ + where: { id: existingInstance.id } + })); + done(); + }); + }); + + it('applies updated from `before delete` hook', function(done) { + TestModel.observe('before delete', function(ctx, next) { + ctx.where = { id: { neq: existingInstance.id } }; + next(); + }); + + existingInstance.delete(function(err) { + if (err) return done(err); + findTestModels(function(err, list) { + if (err) return done(err); + (list || []).map(get('id')).should.eql([existingInstance.id]); + done(); + }); + }); + }); + + it('aborts when `before delete` hook fails', function(done) { + TestModel.observe('before delete', nextWithError(expectedError)); + + existingInstance.delete(function(err, list) { + [err].should.eql([expectedError]); + TestModel.findById(existingInstance.id, function(err, inst) { + if (err) return done(err); + (inst ? inst.toObject() : 'null').should.eql(existingInstance.toObject()); + done(); + }); + }); + }); + it('triggers `after delete` hook', function(done) { TestModel.observe('after delete', pushContextAndNext());