Skip to content

Commit

Permalink
feat: support transaction on one request ctx (ali-sdk#7)
Browse files Browse the repository at this point in the history
* feat: support transaction on one request ctx

like koa's ctx: make sure only one active transaction on one ctx

* test: use codecov
  • Loading branch information
fengmk2 authored and dead-horse committed May 15, 2016
1 parent 3410bd1 commit 3bd4e44
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 76 deletions.
24 changes: 11 additions & 13 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
sudo: false
language: node_js

node_js:
- iojs-2

- 6
- 4
env:
global:
# ALI_SDK_RDS_* env
- secure: np6Gu8jqwZA9TMBh+2AG10G6YeTsQCFMYoIkVNhD32CpuPV5o4lD0VaKoXb83tOjzbcn1aXmfUkfe1NHG8ulJLayD3/tnDZcGiNdfqBEaFFppTF/Q0dkj8I5k7djf9uOxeqk0l3Lq0sFQ3dZOqb0Hpt7tCC58I8sRr6g7118UY4=
- secure: qjQ2ErTqOQ2v6JQgwmdTL1L9Xpu0wvq+teaHvoKp0ffqc4Bpdk2IcCHpSylbgJYLO8Dsox5knA62q7DjJDEVSk/0JabTsmrMiwdpI/ipzFez9Mv8lvYZe7suNKb9rcpWcqIPqQMki010tFVVQCPKhcbGIIQpijeZjRms2RiRb6w=
- secure: Sl/V1goTS1ot2rY59XEMP9/ZonrBCBbYpxHAOAd1plJuFfLHreJJG9ppH6jEW1bLoKvAXTpqYX3Vxn4hhOB5h2idX8b6cfxSXLRPh+aRyQVriv7uqyOr3ZnPmgq2pbdZj6KC4IE0Oej9DECAG8PReVrBkRyDIES0D9EeYXlYaFo=
- secure: tBQhkSxQnC69od0OIFOuz9blcdxjmEpCt3DWC4mkx+AfJqcTH2JMU4COxlprB4GsGf1ZWyPbdDuviXKLGK31TwJ+R99xNyr6wQBMJEMCxMBH7l/j4qL0zD07j9teV3OZsGlh74DfZv74I43xvtozWUrv9obWgRkPoHP9a0qB0Mo=
- secure: jNCqlCBSrqZNvVxxRKEXcELC8vX1AbZBr2K1NUNGBAApng0SiET+165T1Azk77O0CJnTt8vhVH/e45Nq9NnJac5LpaFEGcUbH3HOHoTSExcj+6ijn//JclrZwZDuUHogcyzf3fxfn0v+D+dZbIvcKBTyWAfwhLoN5uN1pfgzPpI=
- secure: El8Ge1OM0ADKiwr4XyBcL8baRnWBSlggjW7zLDKrXhN9Iz3ddyUPcMfApvZvbB4vIOy6ArJbV84TUevo6kLeBXRHwFb0tqf475HSpSvlrgaojcQCzbMLijbQI1i3hyny3S6dweyW/FdPpcH7H9bMuJq4GqhFc0dmSvdTA7gGXKY=

script: npm run test-travis
after_script: npm install coveralls@2 && cat ./coverage/lcov.info | coveralls
- secure: "LdAG4NSfmRU3DEBI0byF+78BfgOqGXDfnxSMA1ER70mnvcOYlqQoKS/ieFlVP1yqDZ+Ut4RNCezBEQt3sLstQEwt8vlvf+Zf+0UbZfrukPmII2nmF1/QwMkVcU/kQc0O2OZwbcXTtgFm/c3WM3SR+jDmHo98IKDxZc08IpJQg4s="
- secure: "Xd6QyLFhS7pB0+ySn1nE5TsrjL6OmKxBdatuQbXMTuKTMyKqnSGSbkdbjmX0FPXfXJQTUElyShat4UWRP4QJ1tWqrRCZkMy6bOIG7IjBh44peajEMvE11Lj2cNYmBKysX2I/iXM4Dw5ayUfeO/s/+g05UC0lBwwE1ePMkxI5E2w="
- secure: "DSxD3Uj4H+4D3rPYRQEoXZvz8dzIdS+iEE2IT0RklIFahgDjXrOhmO+10RUbglYEKZC3F60KnMjlJXUM6RGMTvjAK5MsSuQqplQdB2nM7vX9Fx73HdhmWO/TzX2kFwcUvOkYrdB7ZtnUA3PFLh8nFvCv9YV4P1QKdwdcuh0aF/E="
- secure: "X715wSwfvyIvYCPYzB1cmHrKxR9w3p0mrSuRX8pjSMfwRfYoh2gd/vZAmlgue9CB0zy9WlqKQpiJdOUscCQLW8oDP9X4LZYsBCSloyOIeywpgFPAFyZda0vO4A6dP0VgSAaEl1Qfq6hKts02rg+OkYnLdgxkrVahQPPfKOkTmBU="
script:
- npm run ci
after_script:
- npm i codecov && codecov
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
This software is licensed under the MIT License.

Copyright (c) 2015 ali-sdk and other contributors
Copyright (c) 2015 - 2016 ali-sdk and other contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
39 changes: 27 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,18 @@ ali-rds

[![NPM version][npm-image]][npm-url]
[![build status][travis-image]][travis-url]
[![Test coverage][coveralls-image]][coveralls-url]
[![Gittip][gittip-image]][gittip-url]
[![Test coverage][codecov-image]][codecov-url]
[![David deps][david-image]][david-url]
[![iojs version][iojs-image]][iojs-url]
[![node version][node-image]][node-url]
[![npm download][download-image]][download-url]

[npm-image]: https://img.shields.io/npm/v/ali-rds.svg?style=flat-square
[npm-url]: https://npmjs.org/package/ali-rds
[travis-image]: https://img.shields.io/travis/ali-sdk/ali-rds.svg?style=flat-square
[travis-url]: https://travis-ci.org/ali-sdk/ali-rds
[coveralls-image]: https://img.shields.io/coveralls/ali-sdk/ali-rds.svg?style=flat-square
[coveralls-url]: https://coveralls.io/r/ali-sdk/ali-rds?branch=master
[gittip-image]: https://img.shields.io/gittip/fengmk2.svg?style=flat-square
[gittip-url]: https://www.gittip.com/fengmk2/
[codecov-image]: https://codecov.io/github/ali-sdk/ali-rds/coverage.svg?branch=master
[codecov-url]: https://codecov.io/github/ali-sdk/ali-rds?branch=master
[david-image]: https://img.shields.io/david/ali-sdk/ali-rds.svg?style=flat-square
[david-url]: https://david-dm.org/ali-sdk/ali-rds
[iojs-image]: https://img.shields.io/badge/io.js-%3E=_1.0-yellow.svg?style=flat-square
[iojs-url]: http://iojs.org/
[node-image]: https://img.shields.io/badge/node.js-%3E=_0.10-green.svg?style=flat-square
[node-url]: http://nodejs.org/download/
[download-image]: https://img.shields.io/npm/dm/ali-rds.svg?style=flat-square
[download-url]: https://npmjs.org/package/ali-rds

Expand Down Expand Up @@ -248,6 +239,30 @@ var result = yield db.beginTransactionScope(function* (conn) {
// if error throw on scope, will auto rollback
```

#### Transaction on koa

API: `*beginTransactionScope(scope, ctx)`

Use koa's context to make sure only one active transaction on one ctx.

```js
function* foo(ctx, data1) {
return yield db.beginTransactionScope(function* (conn) {
yield conn.insert(table1, data1);
return { success: true };
}, ctx);
}

function* bar(ctx, data2) {
return yield db.beginTransactionScope(function* (conn) {
// execute foo with the same transaction scope
yield foo(ctx, { foo: 'bar' });
yield conn.insert(table2, data2);
return { success: true };
}, ctx);
}
```

### Raw Queries

- Query with arguments
Expand Down
23 changes: 0 additions & 23 deletions appveyor.yml

This file was deleted.

32 changes: 23 additions & 9 deletions lib/client.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
/**!
* ali-rds - lib/client.js
*
/**
* Copyright(c) ali-sdk and other contributors.
* MIT Licensed
*
Expand Down Expand Up @@ -81,17 +79,33 @@ proto.beginTransaction = function* () {
/**
* Auto commit or rollback on a transaction scope
*
* @param {Function*} scope
* @param {Function*} scope
* @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.beginTransactionScope = function* (scope) {
let tran = yield this.beginTransaction();
proto.beginTransactionScope = function* (scope, ctx) {
ctx = ctx || {};
if (!ctx._transactionConnection) {
ctx._transactionConnection = yield this.beginTransaction();
ctx._transactionScopeCount = 1;
} else {
ctx._transactionScopeCount++;
}
const tran = ctx._transactionConnection;
try {
let result = yield scope(tran);
yield tran.commit();
const result = yield scope(tran);
ctx._transactionScopeCount--;
if (ctx._transactionScopeCount === 0) {
ctx._transactionConnection = null;
yield tran.commit();
}
return result;
} catch (err) {
yield tran.rollback();
if (ctx._transactionConnection) {
ctx._transactionConnection = null;
yield tran.rollback();
}
throw err;
}
};
4 changes: 1 addition & 3 deletions lib/transaction.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
/**!
* ali-rds - lib/transaction.js
*
/**
* Copyright(c) ali-sdk and other contributors.
* MIT Licensed
*
Expand Down
13 changes: 5 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@
"description": "Aliyun RDS client",
"main": "lib/client.js",
"files": [
"lib/"
"lib"
],
"scripts": {
"test": "mocha --harmony --check-leaks -R spec -t 15000 -r co-mocha test/*.test.js",
"test-cov": "node --harmony node_modules/.bin/istanbul cover node_modules/.bin/_mocha -- --check-leaks -t 15000 -r co-mocha test/*.test.js",
"test-travis": "node --harmony node_modules/.bin/istanbul cover node_modules/.bin/_mocha --report lcovonly -- --check-leaks -t 15000 -r co-mocha test/*.test.js",
"test": "mocha -R spec -t 15000 -r co-mocha test/*.test.js",
"ci": "istanbul cover _mocha -- -t 15000 -r co-mocha test/*.test.js",
"jshint": "jshint .",
"autod": "autod -w --prefix '~'",
"cnpm": "npm install --registry=https://registry.npm.taobao.org"
"autod": "autod -w --prefix '~'"
},
"dependencies": {
"debug": "~2.2.0",
Expand All @@ -39,8 +37,7 @@
"ali-rds"
],
"engines": {
"node": ">= 0.11.14",
"iojs": ">= 1.0.0"
"node": ">= 4.0.0"
},
"author": "fengmk2 <m@fengmk2.com> (http://fengmk2.com)",
"license": "MIT"
Expand Down
130 changes: 126 additions & 4 deletions test/client.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
/**!
* ali-rds - client.test.js
*
/**
* Copyright(c) ali-sdk and other contributors.
* MIT Licensed
*
Expand All @@ -18,7 +16,7 @@ const assert = require('assert');
const rds = require('../');
const config = require('./config');

describe('client.test.js', function () {
describe('test/client.test.js', function () {
const prefix = 'prefix-' + process.version + '-';
const table = 'ali-sdk-test-user';
before(function* () {
Expand Down Expand Up @@ -275,6 +273,130 @@ describe('client.test.js', function () {
[table, prefix + 'm@beginTransactionScope-fail.com']);
assert.equal(rows.length, 0);
});

describe('beginTransactionScope(fn, ctx)', function() {
it('should insert 7 rows in a transaction with ctx', function* () {
const ctx = {};
const db = this.db;

function* hiInsert() {
return yield db.beginTransactionScope(function* (conn) {
yield conn.query('insert into ??(name, email, gmt_create, gmt_modified) \
values(?, ?, now(), now())',
[table, prefix + 'beginTransactionScopeCtx3', prefix + 'm@beginTransactionScopeCtx1.com']);
yield conn.query('insert into ??(name, email, gmt_create, gmt_modified) \
values(?, ?, now(), now())',
[table, prefix + 'beginTransactionScopeCtx4', prefix + 'm@beginTransactionScopeCtx1.com']);
return true;
}, ctx);
}

function* fooInsert() {
return yield db.beginTransactionScope(function* (conn) {
yield hiInsert();

yield conn.query('insert into ??(name, email, gmt_create, gmt_modified) \
values(?, ?, now(), now())',
[table, prefix + 'beginTransactionScopeCtx5', prefix + 'm@beginTransactionScopeCtx1.com']);
yield conn.query('insert into ??(name, email, gmt_create, gmt_modified) \
values(?, ?, now(), now())',
[table, prefix + 'beginTransactionScopeCtx6', prefix + 'm@beginTransactionScopeCtx1.com']);
return true;
}, ctx);
}

function* barInsert() {
return yield db.beginTransactionScope(function* (conn) {
yield conn.query('insert into ??(name, email, gmt_create, gmt_modified) \
values(?, ?, now(), now())',
[table, prefix + 'beginTransactionScopeCtx7', prefix + 'm@beginTransactionScopeCtx1.com']);
return true;
}, ctx);
}

const result = yield db.beginTransactionScope(function* (conn) {
yield conn.query('insert into ??(name, email, gmt_create, gmt_modified) \
values(?, ?, now(), now())',
[table, prefix + 'beginTransactionScopeCtx1', prefix + 'm@beginTransactionScopeCtx1.com']);
yield conn.query('insert into ??(name, email, gmt_create, gmt_modified) \
values(?, ?, now(), now())',
[table, prefix + 'beginTransactionScopeCtx2', prefix + 'm@beginTransactionScopeCtx1.com']);

const fooResult = yield fooInsert();
assert.equal(fooResult, true);
const barResult = yield barInsert();
assert.equal(barResult, true);

return true;
}, ctx);

assert.equal(result, true);

const rows = yield db.query('select * from ?? where email=? order by id',
[table, prefix + 'm@beginTransactionScopeCtx1.com']);
assert.equal(rows.length, 7);
assert.equal(rows[0].name, prefix + 'beginTransactionScopeCtx1');
assert.equal(rows[1].name, prefix + 'beginTransactionScopeCtx2');
assert.equal(rows[2].name, prefix + 'beginTransactionScopeCtx3');
assert.equal(rows[3].name, prefix + 'beginTransactionScopeCtx4');
assert.equal(rows[4].name, prefix + 'beginTransactionScopeCtx5');
assert.equal(rows[5].name, prefix + 'beginTransactionScopeCtx6');
assert.equal(rows[6].name, prefix + 'beginTransactionScopeCtx7');
assert.equal(ctx._transactionConnection, null);
assert.equal(ctx._transactionScopeCount, 0);
});

it('should auto rollback on fail', function* () {
const ctx = {};
const db = this.db;

function* fooInsert() {
return yield db.beginTransactionScope(function* (conn) {
yield conn.query('insert into ??(name, email, gmt_create, gmt_modified) \
values(?, ?, now(), now())',
[table, prefix + 'beginTransactionScope-ctx-fail1', prefix + 'm@beginTransactionScope-ctx-fail1.com']);
yield conn.query('insert into ??(name, email, gmt_create, gmt_modified) \
values(?, ?, now(), now())',
[table, prefix + 'beginTransactionScope-ctx-fail2', prefix + 'm@beginTransactionScope-ctx-fail1.com']);
return true;
}, ctx);
}

function* barInsert() {
return yield db.beginTransactionScope(function* (conn) {
yield fooInsert();
yield conn.query('insert into ??(name, email, gmt_create, gmt_modified) \
values(?, ?, now(), now())',
[table, prefix + 'beginTransactionScope-ctx-fail3', prefix + 'm@beginTransactionScope-ctx-fail1.com']);
return true;
}, ctx);
}

try {
yield db.beginTransactionScope(function* (conn) {
yield conn.query('insert into ??(name, email, gmt_create, gmt_modified) \
values(?, ?, now(), now())',
[table, prefix + 'beginTransactionScope-ctx-fail1', prefix + 'm@beginTransactionScope-ctx-fail1.com']);
yield conn.query('insert into ??(name, email, gmt_create, gmt_modified) \
values(?, ?, now(), now())',
[table, prefix + 'beginTransactionScope-ctx-fail2', prefix + 'm@beginTransactionScope-ctx-fail1.com']);

yield barInsert();
throw new Error('should not run this');

return true;
}, ctx);
} catch (err) {
assert.equal(err.code, 'ER_DUP_ENTRY');
}

const rows = yield db.query('select * from ?? where email=? order by id',
[table, prefix + 'm@beginTransactionScope-ctx-fail1.com']);
assert.equal(rows.length, 0);
assert.equal(ctx._transactionConnection, null);
assert.equal(ctx._transactionScopeCount, 3);
});
});
});

describe('get(table, obj, options), select(table, options)', function () {
Expand Down
4 changes: 1 addition & 3 deletions test/operator.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
/**!
* ali-rds - test/operator.test.js
*
/**
* Copyright(c) ali-sdk and other contributors.
* MIT Licensed
*
Expand Down

0 comments on commit 3bd4e44

Please sign in to comment.