Skip to content

Commit

Permalink
feat(lucid): add support for transactions
Browse files Browse the repository at this point in the history
now model instance useTransaction method makes it easier to use transactions for database writes

Closes #43
  • Loading branch information
thetutlage committed Jul 16, 2017
1 parent 0986fc9 commit 5c32b3f
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/Lucid/Model/Mixins/Persistance.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ Peristance.insert = function * () {
throw new NE.RuntimeException('cannot save an empty model')
}
const query = this.constructor.query()
if (this.transaction) {
query.transacting(this.transaction)
}
const save = yield query.insertAttributes(values).returning(this.constructor.primaryKey)
if (save[0]) {
this.$primaryKeyValue = save[0]
Expand Down Expand Up @@ -64,6 +67,9 @@ Peristance.update = function * () {
if (!_.size(dirtyValues)) {
return 0
}
if (this.transaction) {
query.transacting(this.transaction)
}
const affected = yield query.where('id', this.$primaryKeyValue).updateAttributes(dirtyValues)
if (affected > 0) {
_.merge(this.attributes, dirtyValues)
Expand All @@ -87,6 +93,9 @@ Peristance.update = function * () {
Peristance.delete = function * () {
const deleteHandler = function * () {
const query = this.constructor.query().where('id', this.$primaryKeyValue)
if (this.transaction) {
query.transacting(this.transaction)
}
const values = {}
const affected = yield query.deleteAttributes(values)
if (affected > 0) {
Expand All @@ -109,6 +118,9 @@ Peristance.delete = function * () {
Peristance.restore = function * () {
const restoreHandler = function * () {
const query = this.constructor.query().where('id', this.$primaryKeyValue)
if (this.transaction) {
query.transacting(this.transaction)
}
const values = {}
const affected = yield query.restoreAttributes(values)
if (affected > 0) {
Expand Down
148 changes: 148 additions & 0 deletions test/unit/lucid.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1303,4 +1303,152 @@ test.group('Model', (group) => {
const fn = () => User.addGlobalScope('foo')
assert.throw(fn, 'E_INVALID_PARAMETER: Model.addGlobalScope expects a closure as first parameter')
})

context('Model Transactions', function () {
it('should be able to rollback save operation', function * () {
const trx = yield Database.beginTransaction()
class User extends Model {}
User.bootIfNotBooted()
const user = new User()
user.fill({username: 'foo', firstname: 'Mr.Foo'})
user.useTransaction(trx)
yield user.save()
trx.rollback()
const getUsers = yield User.all()
expect(getUsers.size()).to.equal(0)
})

it('should be able to commit save operation', function * () {
const trx = yield Database.beginTransaction()
class User extends Model {}
User.bootIfNotBooted()
const user = new User()
user.fill({username: 'foo', firstname: 'Mr.Foo'})
user.useTransaction(trx)
yield user.save()
trx.commit()
const getUsers = yield User.all()
expect(getUsers.size()).to.equal(1)
})

it('should be able to rollback update operation', function * () {
class User extends Model {}
User.bootIfNotBooted()
const user = new User()
user.fill({username: 'foo', firstname: 'Mr.Foo'})
yield user.save()
const getUsers = yield User.all()
expect(getUsers.size()).to.equal(1)
const trx = yield Database.beginTransaction()
user.lastname = 'Baz'
user.useTransaction(trx)
yield user.save()
trx.rollback()
const freshUser = yield user.fresh()
expect(freshUser.lastname).to.equal(null)
})

it('should be able to commit update operation', function * () {
class User extends Model {}
User.bootIfNotBooted()
const user = new User()
user.fill({username: 'foo', firstname: 'Mr.Foo'})
yield user.save()
const getUsers = yield User.all()
expect(getUsers.size()).to.equal(1)
const trx = yield Database.beginTransaction()
user.lastname = 'Baz'
user.useTransaction(trx)
yield user.save()
trx.commit()
const freshUser = yield user.fresh()
expect(freshUser.lastname).to.equal('Baz')
})

it('should not make use of same transaction after resetTransaction method', function * () {
const trx = yield Database.beginTransaction()
class User extends Model {}
User.bootIfNotBooted()
const user = new User()
user.fill({username: 'foo', firstname: 'Mr.Foo'})
user.useTransaction(trx)
yield user.save()
trx.commit()
const getUsers = yield User.all()
expect(getUsers.size()).to.equal(1)
user.lastname = 'Baz'
user.resetTransaction()
yield user.save()
const freshUser = yield user.fresh()
expect(freshUser.lastname).to.equal('Baz')
})

it('should be able to rollback delete operation', function * () {
class User extends Model {}
User.bootIfNotBooted()
const user = new User()
user.fill({username: 'foo', firstname: 'Mr.Foo'})
yield user.save()
const trx = yield Database.beginTransaction()
user.useTransaction(trx)
yield user.delete()
trx.rollback()
const getUsers = yield User.all()
expect(getUsers.size()).to.equal(1)
})

it('should be able to commit delete operation', function * () {
class User extends Model {}
User.bootIfNotBooted()
const user = new User()
user.fill({username: 'foo', firstname: 'Mr.Foo'})
yield user.save()
const trx = yield Database.beginTransaction()
user.useTransaction(trx)
yield user.delete()
trx.commit()
const getUsers = yield User.all()
expect(getUsers.size()).to.equal(0)
})

it('should be able to rollback restore operation', function * () {
class User extends Model {
static get deleteTimestamp () {
return 'deleted_at'
}
}
User.bootIfNotBooted()
const user = new User()
user.fill({username: 'foo', firstname: 'Mr.Foo'})
yield user.save()
yield user.delete()
const freshUser = yield User.query().withTrashed().first()
const trx = yield Database.beginTransaction()
freshUser.useTransaction(trx)
yield freshUser.restore()
trx.rollback()
const getUsers = yield User.all()
expect(getUsers.size()).to.equal(0)
})

it('should be able to commit restore operation', function * () {
class User extends Model {
static get deleteTimestamp () {
return 'deleted_at'
}
}
User.bootIfNotBooted()
const user = new User()
user.fill({username: 'foo', firstname: 'Mr.Foo'})
yield user.save()
yield user.delete()
const freshUser = yield User.query().withTrashed().first()
const trx = yield Database.beginTransaction()
freshUser.useTransaction(trx)
yield freshUser.restore()
trx.commit()
const getUsers = yield User.all()
expect(getUsers.size()).to.equal(1)
})
})
})

0 comments on commit 5c32b3f

Please sign in to comment.