diff --git a/lib/client.js b/lib/client.js index f5672a1..a886789 100644 --- a/lib/client.js +++ b/lib/client.js @@ -98,6 +98,41 @@ proto.beginTransactionScope = function* (scope, ctx) { } }; +/** + * doomed to be rollbacked after transaction scope + * useful on writing test that depend on database + * + * @param {Function} scope - scope with code + * @param {Object} [ctx] - transaction env context, like koa's ctx. + * To make sure only one active transaction on this ctx. + * @return {Object} - scope return result + */ +proto.beginDoomedTransactionScope = function* (scope, ctx) { + ctx = ctx || {}; + if (!ctx._transactionConnection) { + ctx._transactionConnection = yield this.beginTransaction(); + ctx._transactionScopeCount = 1; + } else { + ctx._transactionScopeCount++; + } + const tran = ctx._transactionConnection; + try { + const result = yield scope(tran); + ctx._transactionScopeCount--; + if (ctx._transactionScopeCount === 0) { + ctx._transactionConnection = null; + } + return result; + } catch (err) { + if (ctx._transactionConnection) { + ctx._transactionConnection = null; + } + throw err; + } finally { + yield tran.rollback(); + } +}; + proto.end = function(callback) { // callback style if (callback) { diff --git a/test/client.test.js b/test/client.test.js index a459bc8..ea45a8d 100644 --- a/test/client.test.js +++ b/test/client.test.js @@ -415,6 +415,34 @@ describe('client.test.js', function() { }); }); + describe('beginDoomedTransactionScope(scope)', function() { + + it('should insert 0 rows in a doomed transaction with ctx', function* () { + const ctx = {}; + const db = this.db; + + function* insert() { + return yield db.beginDoomedTransactionScope(function* (conn) { + yield conn.query('insert into ??(name, email, gmt_create, gmt_modified) \ + values(?, ?, now(), now())', + [ table, prefix + 'beginDoomedTransactionScopeCtx1', prefix + 'm@beginDoomedTransactionScopeCtx1.com' ]); + yield conn.query('insert into ??(name, email, gmt_create, gmt_modified) \ + values(?, ?, now(), now())', + [ table, prefix + 'beginDoomedTransactionScopeCtx2', prefix + 'm@beginDoomedTransactionScopeCtx1.com' ]); + return true; + }, ctx); + } + + yield insert(); + + const rows = yield db.query('select * from ?? where email=? order by id', + [ table, prefix + 'm@beginDoomedTransactionScopeCtx1.com' ]); + assert.equal(rows.length, 0); + assert.equal(ctx._transactionConnection, null); + assert.equal(ctx._transactionScopeCount, 0); + }); + }); + describe('get(table, obj, options), select(table, options)', function() { before(function* () { let result = yield this.db.insert(table, {