Skip to content

Commit b1ec3de

Browse files
author
Mike Eldridge
committed
#10 - transaction support via knex
1 parent 5829c1e commit b1ec3de

File tree

5 files changed

+220
-7
lines changed

5 files changed

+220
-7
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"babel-loader": "5.3.2",
3232
"bluebird": "2.10.2",
3333
"chai": "3.3.0",
34+
"co": "^4.6.0",
3435
"co-mocha": "1.1.2",
3536
"mocha": "2.3.3",
3637
"standard": "5.3.1",

src/index.js

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ function getTable (resourceConfig) {
1919
return resourceConfig.table || underscore(resourceConfig.name)
2020
}
2121

22-
function filterQuery (resourceConfig, params) {
22+
function filterQuery (resourceConfig, params, options) {
2323
let table = getTable(resourceConfig)
24-
let query = this.query.select(`${table}.*`).from(table)
24+
let query = options && options.transaction || this.query
25+
query = query.select(`${table}.*`).from(table)
2526
params = params || {}
2627
params.where = params.where || {}
2728
params.orderBy = params.orderBy || params.sort
@@ -297,7 +298,8 @@ class DSSqlAdapter {
297298
let instance
298299
options = options || {}
299300
options.with = options.with || []
300-
return this.query
301+
let query = options && options.transaction || this.query
302+
return query
301303
.select('*')
302304
.from(getTable(resourceConfig))
303305
.where(resourceConfig.idAttribute, toString(id))
@@ -324,7 +326,8 @@ class DSSqlAdapter {
324326

325327
create (resourceConfig, attrs, options) {
326328
attrs = DSUtils.removeCircular(DSUtils.omit(attrs, resourceConfig.relationFields || []))
327-
return this.query(getTable(resourceConfig))
329+
let query = options && options.transaction || this.query
330+
return query(getTable(resourceConfig))
328331
.insert(attrs, resourceConfig.idAttribute)
329332
.then(ids => {
330333
if (attrs[resourceConfig.idAttribute]) {
@@ -339,7 +342,8 @@ class DSSqlAdapter {
339342

340343
update (resourceConfig, id, attrs, options) {
341344
attrs = DSUtils.removeCircular(DSUtils.omit(attrs, resourceConfig.relationFields || []))
342-
return this.query(getTable(resourceConfig))
345+
let query = options && options.transaction || this.query
346+
return query(getTable(resourceConfig))
343347
.where(resourceConfig.idAttribute, toString(id))
344348
.update(attrs)
345349
.then(() => this.find(resourceConfig, id, options))
@@ -360,8 +364,9 @@ class DSSqlAdapter {
360364
})
361365
}
362366

363-
destroy (resourceConfig, id) {
364-
return this.query(getTable(resourceConfig))
367+
destroy (resourceConfig, id, options) {
368+
let query = options && options.transaction || this.query
369+
return query(getTable(resourceConfig))
365370
.where(resourceConfig.idAttribute, toString(id))
366371
.del().then(() => undefined)
367372
}

test/create_trx.spec.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
describe('DSSqlAdapter#create + transaction', function () {
2+
it('commit should persist created user in a sql db', function* () {
3+
var id;
4+
var co = require('co');
5+
6+
yield adapter.query.transaction(co.wrap(function * (trx) {
7+
var createUser = yield adapter.create(User, {name: 'Jane'}, {transaction: trx});
8+
id = createUser.id;
9+
assert.equal(createUser.name, 'Jane');
10+
assert.isDefined(createUser.id);
11+
12+
var findUser = yield adapter.find(User, createUser.id, {transaction: trx});
13+
assert.equal(findUser.name, 'Jane');
14+
assert.isDefined(findUser.id);
15+
assert.equalObjects(findUser, {id: id, name: 'Jane', age: null, profileId: null});
16+
17+
return findUser;
18+
})).then(
19+
function (user) {
20+
assert.isObject(user, 'transaction returned user object');
21+
assert.equal(user.name, 'Jane');
22+
assert.isDefined(user.id);
23+
assert.equalObjects(user, {id: id, name: 'Jane', age: null, profileId: null});
24+
},
25+
function (err) {
26+
throw new Error('transaction threw exception!');
27+
}
28+
);
29+
30+
try {
31+
var findUser2 = yield adapter.find(User, id);
32+
assert.isObject(findUser2, 'user committed to database');
33+
} catch(err) {
34+
throw new Error('transaction failed to commit!');
35+
}
36+
});
37+
38+
it('rollback should not persist created user in a sql db', function* () {
39+
var id;
40+
var co = require('co');
41+
42+
yield adapter.query.transaction(co.wrap(function * (trx) {
43+
var createUser = yield adapter.create(User, {name: 'John'}, {transaction: trx});
44+
id = createUser.id;
45+
assert.equal(createUser.name, 'John');
46+
assert.isDefined(createUser.id);
47+
48+
var findUser = yield adapter.find(User, createUser.id, {transaction: trx});
49+
assert.equal(findUser.name, 'John');
50+
assert.isDefined(findUser.id);
51+
assert.equalObjects(findUser, {id: id, name: 'John', age: null, profileId: null});
52+
53+
throw new Error('rollback');
54+
})).then(
55+
function () { throw new Error('transaction did not throw exception!') },
56+
function (err) { assert.equal(err.message, 'rollback') }
57+
);
58+
59+
try {
60+
var findUser2 = yield adapter.find(User, id);
61+
throw new Error('transaction failed to roll back!');
62+
} catch(err) {
63+
assert.equal(err.message, 'Not Found!');
64+
}
65+
});
66+
});

test/destroy_trx.spec.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
describe('DSSqlAdapter#destroy + transaction', function () {
2+
it('commit should destroy a user from a Sql db', function* () {
3+
var co = require('co');
4+
5+
var createUser = yield adapter.create(User, {name: 'John'})
6+
var id = createUser.id;
7+
8+
yield adapter.query.transaction(co.wrap(function * (trx) {
9+
var destroyUser = yield adapter.destroy(User, createUser.id, {transaction: trx});
10+
assert.isFalse(!!destroyUser);
11+
}));
12+
13+
try {
14+
var findUser = yield adapter.find(User, id);
15+
throw new Error('Should not have reached here!');
16+
} catch (err) {
17+
assert.equal(err.message, 'Not Found!');
18+
}
19+
});
20+
21+
it('rollback should not destroy a user from a Sql db', function* () {
22+
var co = require('co');
23+
24+
var createUser = yield adapter.create(User, {name: 'John'})
25+
var id = createUser.id;
26+
27+
yield adapter.query.transaction(co.wrap(function * (trx) {
28+
var destroyUser = yield adapter.destroy(User, createUser.id, {transaction: trx});
29+
assert.isFalse(!!destroyUser);
30+
31+
throw new Error('rollback');
32+
})).then(
33+
function () { throw new Error('transaction did not throw exception!') },
34+
function (err) { assert.equal(err.message, 'rollback') }
35+
);
36+
37+
try {
38+
var findUser = yield adapter.find(User, id);
39+
assert.isObject(findUser, 'user still exists');
40+
} catch (err) {
41+
if (err.message == 'Not Found!') {
42+
throw new Error('transaction did not roll back');
43+
} else {
44+
throw new Error('caught exception trying to locate user');
45+
}
46+
}
47+
});
48+
});

test/update_trx.spec.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
describe('DSSqlAdapter#update + transaction', function () {
2+
it('commit should update a user in a Sql db', function* () {
3+
var co = require('co');
4+
5+
var user = yield adapter.create(User, {name: 'John'})
6+
var id = user.id;
7+
assert.equal(user.name, 'John');
8+
assert.isDefined(user.id);
9+
10+
var foundUser = yield adapter.find(User, user.id);
11+
assert.equal(foundUser.name, 'John');
12+
assert.isDefined(foundUser.id);
13+
assert.equalObjects(foundUser, {id: id, name: 'John', age: null, profileId: null});
14+
15+
yield adapter.query.transaction(co.wrap(function * (trx) {
16+
var updatedUser = yield adapter.update(User, foundUser.id, {name: 'Johnny'}, {transaction: trx});
17+
assert.equal(updatedUser.name, 'Johnny');
18+
assert.isDefined(updatedUser.id);
19+
assert.equalObjects(updatedUser, {id: id, name: 'Johnny', age: null, profileId: null});
20+
21+
var foundUser2 = yield adapter.find(User, updatedUser.id, {transaction: trx});
22+
assert.equal(foundUser2.name, 'Johnny');
23+
assert.isDefined(foundUser2.id);
24+
assert.equalObjects(foundUser2, {id: id, name: 'Johnny', age: null, profileId: null});
25+
26+
return foundUser2;
27+
})).then(
28+
function (user) { assert.isObject(user, 'transaction returned user object') },
29+
function (err) { throw new Error('transaction threw exception!') }
30+
);
31+
32+
var foundUser3 = yield adapter.find(User, user.id);
33+
assert.equal(foundUser3.name, 'Johnny');
34+
assert.isDefined(foundUser3.id);
35+
assert.equalObjects(foundUser3, {id: id, name: 'Johnny', age: null, profileId: null});
36+
37+
var destroyUser = yield adapter.destroy(User, foundUser3.id);
38+
assert.isFalse(!!destroyUser);
39+
40+
try {
41+
yield adapter.find(User, id);
42+
throw new Error('Should not have reached here!');
43+
} catch (err) {
44+
assert.equal(err.message, 'Not Found!');
45+
}
46+
});
47+
48+
it('rollback should not update a user in a Sql db', function* () {
49+
var co = require('co');
50+
51+
var user = yield adapter.create(User, {name: 'John'})
52+
var id = user.id;
53+
assert.equal(user.name, 'John');
54+
assert.isDefined(user.id);
55+
56+
var foundUser = yield adapter.find(User, user.id);
57+
assert.equal(foundUser.name, 'John');
58+
assert.isDefined(foundUser.id);
59+
assert.equalObjects(foundUser, {id: id, name: 'John', age: null, profileId: null});
60+
61+
yield adapter.query.transaction(co.wrap(function * (trx) {
62+
var updatedUser = yield adapter.update(User, foundUser.id, {name: 'Johnny'}, {transaction: trx});
63+
assert.equal(updatedUser.name, 'Johnny');
64+
assert.isDefined(updatedUser.id);
65+
assert.equalObjects(updatedUser, {id: id, name: 'Johnny', age: null, profileId: null});
66+
67+
var foundUser2 = yield adapter.find(User, updatedUser.id, {transaction: trx});
68+
assert.equal(foundUser2.name, 'Johnny');
69+
assert.isDefined(foundUser2.id);
70+
assert.equalObjects(foundUser2, {id: id, name: 'Johnny', age: null, profileId: null});
71+
72+
throw new Error('rollback');
73+
})).then(
74+
function () { throw new Error('transaction did not throw exception!') },
75+
function (err) { assert.equal(err.message, 'rollback') }
76+
);
77+
78+
var foundUser3 = yield adapter.find(User, user.id);
79+
assert.equal(foundUser3.name, 'John');
80+
assert.isDefined(foundUser3.id);
81+
assert.equalObjects(foundUser3, {id: id, name: 'John', age: null, profileId: null});
82+
83+
var destroyUser = yield adapter.destroy(User, foundUser3.id);
84+
assert.isFalse(!!destroyUser);
85+
86+
try {
87+
yield adapter.find(User, id);
88+
throw new Error('Should not have reached here!');
89+
} catch (err) {
90+
assert.equal(err.message, 'Not Found!');
91+
}
92+
});
93+
});

0 commit comments

Comments
 (0)