Skip to content

Commit cfdcf26

Browse files
committed
feat: add Transaction
1 parent abb4804 commit cfdcf26

File tree

5 files changed

+229
-42
lines changed

5 files changed

+229
-42
lines changed

README.md

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -110,34 +110,19 @@ console.log(result);
110110

111111
### Transactions
112112

113-
- Get connection first
113+
beginTransaction, commit or rollback
114114

115115
```js
116-
var conn = yield db.getConnection();
117-
```
118-
119-
- beginTransaction, commit or rollback
120-
121-
```js
122-
var conn = yield db.getConnection();
123-
try {
124-
yield conn.beginTransaction();
125-
} catch (err) {
126-
conn.release();
127-
throw err;
128-
}
116+
var tran = yield db.beginTransaction();
129117

130118
try {
131-
yield conn.query(insertSQL1);
132-
yield conn.query(insertSQL2);
133-
yield conn.commit();
119+
yield tran.query(insertSQL1);
120+
yield tran.query(insertSQL2);
121+
yield tran.commit();
134122
} catch (err) {
135123
// error, rollback
136-
yield conn.rollback(); // rollback call won't throw err
124+
yield tran.rollback(); // rollback call won't throw err
137125
throw err;
138-
} finally {
139-
// should release connection whatever
140-
conn.release();
141126
}
142127
```
143128

lib/client.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@
1414
* Module dependencies.
1515
*/
1616

17-
var debug = require('debug')('ali-rds:client');
1817
var mysql = require('mysql');
1918
var util = require('util');
2019
var Operator = require('./operator');
2120
var RDSConnection = require('./connection');
21+
var RDSTransaction = require('./transaction');
2222

2323
module.exports = RDSClient;
2424
module.exports.literals = require('./literals');
@@ -47,7 +47,6 @@ proto._query = function (sql) {
4747

4848
proto.getConnection = function () {
4949
var pool = this.pool;
50-
var needFields = this._needFields;
5150
return function (callback) {
5251
pool.getConnection(function (err, connection) {
5352
if (err) {
@@ -56,12 +55,17 @@ proto.getConnection = function () {
5655
}
5756
return callback(err);
5857
}
59-
var conn = new RDSConnection(connection, needFields);
58+
var conn = new RDSConnection(connection);
6059
callback(null, conn);
6160
});
6261
};
6362
};
6463

64+
/**
65+
* Begin a transaction
66+
*
67+
* @return {Transaction} transaction instance
68+
*/
6569
proto.beginTransaction = function* () {
6670
var conn = yield this.getConnection();
6771
try {
@@ -70,5 +74,6 @@ proto.beginTransaction = function* () {
7074
conn.release();
7175
throw err;
7276
}
73-
return conn;
77+
78+
return new RDSTransaction(conn);
7479
};

lib/transaction.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**!
2+
* ali-rds - lib/transaction.js
3+
*
4+
* Copyright(c) ali-sdk and other contributors.
5+
* MIT Licensed
6+
*
7+
* Authors:
8+
* fengmk2 <m@fengmk2.com> (http://fengmk2.com)
9+
*/
10+
11+
'use strict';
12+
13+
/**
14+
* Module dependencies.
15+
*/
16+
17+
const util = require('util');
18+
const Operator = require('./operator');
19+
20+
module.exports = RDSTransaction;
21+
22+
function RDSTransaction(conn) {
23+
Operator.call(this);
24+
this.conn = conn;
25+
this.isCommit = false;
26+
this.isRollback = false;
27+
}
28+
util.inherits(RDSTransaction, Operator);
29+
30+
const proto = RDSTransaction.prototype;
31+
32+
proto.commit = function* () {
33+
this._check();
34+
try {
35+
return yield this.conn.commit();
36+
} finally {
37+
this.conn.release();
38+
this.conn = null;
39+
}
40+
};
41+
42+
proto.rollback = function* () {
43+
this._check();
44+
try {
45+
return yield this.conn.rollback();
46+
} finally {
47+
this.conn.release();
48+
this.conn = null;
49+
}
50+
};
51+
52+
proto._query = function* (sql) {
53+
this._check();
54+
return yield this.conn._query(sql);
55+
};
56+
57+
proto._check = function () {
58+
if (!this.conn) {
59+
throw new Error('transaction was commit or rollback');
60+
}
61+
};

test/client.test.js

Lines changed: 142 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,69 @@ describe('client.test.js', function () {
7474
});
7575

7676
describe('transactions', function () {
77+
it('should beginTransaction error', function* () {
78+
var db = rds({});
79+
try {
80+
yield db.beginTransaction();
81+
throw new Error('should not run this');
82+
} catch (err) {
83+
assert.equal(err.name, 'RDSClientGetConnectionError');
84+
assert.equal(err.code, 'ECONNREFUSED');
85+
}
86+
});
87+
88+
it('should throw error after transaction rollback', function* () {
89+
var tran = yield this.db.beginTransaction();
90+
yield tran.rollback();
91+
92+
try {
93+
yield tran.select(table);
94+
throw new Error('should not run this');
95+
} catch (err) {
96+
assert.equal(err.message, 'transaction was commit or rollback');
97+
}
98+
99+
try {
100+
yield tran.rollback();
101+
throw new Error('should not run this');
102+
} catch (err) {
103+
assert.equal(err.message, 'transaction was commit or rollback');
104+
}
105+
106+
try {
107+
yield tran.commit();
108+
throw new Error('should not run this');
109+
} catch (err) {
110+
assert.equal(err.message, 'transaction was commit or rollback');
111+
}
112+
});
113+
114+
it('should throw error after transaction commit', function* () {
115+
var tran = yield this.db.beginTransaction();
116+
yield tran.commit();
117+
118+
try {
119+
yield tran.select(table);
120+
throw new Error('should not run this');
121+
} catch (err) {
122+
assert.equal(err.message, 'transaction was commit or rollback');
123+
}
124+
125+
try {
126+
yield tran.commit();
127+
throw new Error('should not run this');
128+
} catch (err) {
129+
assert.equal(err.message, 'transaction was commit or rollback');
130+
}
131+
132+
try {
133+
yield tran.rollback();
134+
throw new Error('should not run this');
135+
} catch (err) {
136+
assert.equal(err.message, 'transaction was commit or rollback');
137+
}
138+
});
139+
77140
it('should insert 2 rows in a transaction', function* () {
78141
var conn = yield this.db.getConnection();
79142
try {
@@ -108,22 +171,19 @@ describe('client.test.js', function () {
108171
});
109172

110173
it('should use db.beginTransaction()', function* () {
111-
var conn = yield this.db.beginTransaction();
174+
var tran = yield this.db.beginTransaction();
112175
try {
113-
yield conn.query('insert into `ali-sdk-test-user`(name, email, gmt_create, gmt_modified) \
176+
yield tran.query('insert into `ali-sdk-test-user`(name, email, gmt_create, gmt_modified) \
114177
values(?, ?, now(), now())',
115178
[prefix + 'beginTransaction1', prefix + 'm@beginTransaction.com']);
116-
yield conn.query('insert into `ali-sdk-test-user`(name, email, gmt_create, gmt_modified) \
179+
yield tran.query('insert into `ali-sdk-test-user`(name, email, gmt_create, gmt_modified) \
117180
values(?, ?, now(), now())',
118181
[prefix + 'beginTransaction2', prefix + 'm@beginTransaction.com']);
119-
yield conn.commit();
182+
yield tran.commit();
120183
} catch (err) {
121184
// error, rollback
122-
yield conn.rollback(); // rollback call won't throw err
185+
yield tran.rollback(); // rollback call won't throw err
123186
throw err;
124-
} finally {
125-
// should release connection whatever
126-
conn.release();
127187
}
128188

129189
var rows = yield this.db.query('select * from `ali-sdk-test-user` where email=? order by id',
@@ -257,12 +317,29 @@ describe('client.test.js', function () {
257317
assert.equal(users.length, 0);
258318
});
259319

260-
it('should list without options.where', function* () {
261-
var users = yield this.db.select('ali-sdk-test-user');
320+
it('should select without options.where', function* () {
321+
var users = yield this.db.select(table);
262322
assert(users);
263323
assert.equal(users.length > 2, true);
264324
assert.deepEqual(Object.keys(users[0]), [ 'id', 'gmt_create', 'gmt_modified', 'name', 'email' ]);
265325
});
326+
327+
it('should select with options.orders', function* () {
328+
var users = yield this.db.select(table, {
329+
orders: 'id'
330+
});
331+
assert(users[0].id < users[1].id);
332+
333+
var users = yield this.db.select(table, {
334+
orders: [['id', 'desc'], null, 1]
335+
});
336+
assert(users[0].id > users[1].id);
337+
338+
var users = yield this.db.select(table, {
339+
orders: ['id', ['name', 'foo']]
340+
});
341+
assert(users[0].id < users[1].id);
342+
});
266343
});
267344

268345
describe('insert(table, row[s])', function () {
@@ -274,6 +351,17 @@ describe('client.test.js', function () {
274351
assert.equal(result.affectedRows, 1);
275352
});
276353

354+
it('should insert with columns', function* () {
355+
var result = yield this.db.insert(table, {
356+
name: prefix + 'fengmk2-insert-with-columns',
357+
email: prefix + 'm@fengmk2-insert-with-columns.com',
358+
ignoretitle: 'foo title'
359+
}, {
360+
columns: ['name', 'email']
361+
});
362+
assert.equal(result.affectedRows, 1);
363+
});
364+
277365
it('should insert multi rows', function* () {
278366
var result = yield this.db.insert(table, [
279367
{
@@ -359,8 +447,6 @@ describe('client.test.js', function () {
359447
} catch (err) {
360448
yield tran.rollback();
361449
assert.equal(err.code, 'ER_DUP_ENTRY');
362-
} finally {
363-
tran.release();
364450
}
365451

366452
var rows = yield this.db.select(table, {
@@ -372,19 +458,50 @@ describe('client.test.js', function () {
372458

373459
describe('update(table, obj, options)', function () {
374460
before(function* () {
375-
yield this.db.insert('ali-sdk-test-user', {
461+
yield this.db.insert(table, {
376462
name: prefix + 'fengmk2-update',
377-
email: prefix + 'm@fengmk2-update.com'
463+
email: prefix + 'm@fengmk2-update.com',
464+
gmt_create: this.db.literals.now,
465+
gmt_modified: this.db.literals.now,
466+
});
467+
});
468+
469+
it('should throw error when cannot auto detect update condition', function* () {
470+
try {
471+
yield this.db.update(table, {});
472+
throw new Error('should not run this');
473+
} catch (err) {
474+
assert.equal(err.message,
475+
'Can\'t not auto detect update condition, please set options.where, or make sure obj.id exists');
476+
}
477+
});
478+
479+
it('should get and update', function* () {
480+
yield this.db.insert(table, {
481+
name: prefix + 'fengmk2-update2',
482+
email: prefix + 'm@fengmk2-update2.com',
483+
gmt_create: this.db.literals.now,
484+
gmt_modified: this.db.literals.now,
485+
});
486+
487+
var user = yield this.db.get(table, {
488+
name: prefix + 'fengmk2-update2',
378489
});
490+
user.email = prefix + 'm@fengmk2-update2-again.com';
491+
var result = yield this.db.update(table, user);
492+
assert.equal(result.affectedRows, 1);
493+
494+
var row = yield this.db.get(table, {id: user.id});
495+
assert.equal(row.email, user.email);
379496
});
380497

381498
it('should update exists row', function* () {
382-
var user = yield this.db.get('ali-sdk-test-user', {
499+
var user = yield this.db.get(table, {
383500
name: prefix + 'fengmk2-update',
384501
});
385502
assert.equal(user.email, prefix + 'm@fengmk2-update.com');
386503

387-
var result = yield this.db.update('ali-sdk-test-user', {
504+
var result = yield this.db.update(table, {
388505
name: prefix + 'fengmk2-update',
389506
email: prefix + 'm@fengmk2-update2.com',
390507
gmt_create: 'now()', // invalid date
@@ -396,12 +513,20 @@ describe('client.test.js', function () {
396513
});
397514
assert.equal(result.affectedRows, 1);
398515

399-
var user = yield this.db.get('ali-sdk-test-user', {
516+
var user = yield this.db.get(table, {
400517
name: prefix + 'fengmk2-update',
401518
});
402519
assert.equal(user.email, prefix + 'm@fengmk2-update2.com');
403520
assert.equal(user.gmt_create, '0000-00-00 00:00:00');
404521
assert(user.gmt_modified instanceof Date);
522+
523+
user.email = prefix + 'm@fengmk2-update3.com';
524+
var result = yield this.db.update(table, user, {
525+
columns: ['email']
526+
});
527+
assert.equal(result.affectedRows, 1);
528+
var row = yield this.db.get(table, {id: user.id});
529+
assert.equal(row.email, user.email);
405530
});
406531
});
407532

0 commit comments

Comments
 (0)