Skip to content

Commit

Permalink
refactor(transaction): use events instead of hooks
Browse files Browse the repository at this point in the history
Since the transaction events doesn't have to do anything with the hooks
response, there is no point blocking for the hooks to complete and
instead we use events
  • Loading branch information
thetutlage committed Oct 1, 2019
1 parent ad65a1a commit 2b04b85
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 75 deletions.
11 changes: 7 additions & 4 deletions adonis-typings/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ declare module '@ioc:Adonis/Lucid/Database' {
} from '@ioc:Adonis/Lucid/DatabaseQueryBuilder'

import {
HooksContract,
ModelConstructorContract,
ModelQueryBuilderContract,
} from '@ioc:Adonis/Lucid/Model'
Expand Down Expand Up @@ -153,11 +152,9 @@ declare module '@ioc:Adonis/Lucid/Database' {
* The shape of transaction client to run queries under a given
* transaction on a single connection
*/
export interface TransactionClientContract extends QueryClientContract {
export interface TransactionClientContract extends QueryClientContract, EventEmitter {
knexClient: knex.Transaction,

hooks: HooksContract<'commit' | 'rollback', (client: TransactionClientContract) => void | Promise<void>>

/**
* Is transaction completed or not
*/
Expand All @@ -172,6 +169,12 @@ declare module '@ioc:Adonis/Lucid/Database' {
* Rollback transaction
*/
rollback (): Promise<void>

on (event: 'commit', handler: (client: this) => void): this
on (event: 'rollback', handler: (client: this) => void): this

once (event: 'commit', handler: (client: this) => void): this
once (event: 'rollback', handler: (client: this) => void): this
}

/**
Expand Down
63 changes: 11 additions & 52 deletions src/TransactionClient/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
/// <reference path="../../adonis-typings/index.ts" />

import knex from 'knex'
import { EventEmitter } from 'events'
import { TransactionClientContract } from '@ioc:Adonis/Lucid/Database'
import { ProfilerRowContract, ProfilerContract } from '@ioc:Adonis/Core/Profiler'

import { Hooks } from '../Hooks'
import { ModelQueryBuilder } from '../Orm/QueryBuilder'
import { RawQueryBuilder } from '../Database/QueryBuilder/Raw'
import { InsertQueryBuilder } from '../Database/QueryBuilder/Insert'
Expand All @@ -23,7 +23,7 @@ import { DatabaseQueryBuilder } from '../Database/QueryBuilder/Database'
* Transaction uses a dedicated connection from the connection pool
* and executes queries inside a given transaction.
*/
export class TransactionClient implements TransactionClientContract {
export class TransactionClient extends EventEmitter implements TransactionClientContract {
/**
* Always true
*/
Expand All @@ -40,16 +40,12 @@ export class TransactionClient implements TransactionClientContract {
*/
public profiler?: ProfilerRowContract | ProfilerContract

/**
* Reference to client hooks
*/
public hooks = new Hooks<'rollback' | 'commit', any>()

constructor (
public knexClient: knex.Transaction,
public dialect: string,
public connectionName: string,
) {
super()
}

/**
Expand Down Expand Up @@ -161,64 +157,27 @@ export class TransactionClient implements TransactionClientContract {
* Commit the transaction
*/
public async commit () {
/**
* Execute before hooks
*/
await this.hooks.execute('before', 'commit', this)

/**
* Commit and hold the error (if any)
*/
let commitError: any = null
try {
await this.knexClient.commit()
this.emit('commit', this)
this.removeAllListeners()
} catch (error) {
commitError = error
}

/**
* Raise exception when commit fails
*/
if (commitError) {
this.hooks.clearAll()
throw commitError
this.removeAllListeners()
throw error
}

/**
* Execute after hooks
*/
await this.hooks.execute('after', 'commit', this)
this.hooks.clearAll()
}

/**
* Rollback the transaction
*/
public async rollback () {
/**
* Execute before hooks
*/
await this.hooks.execute('before', 'rollback', this)

let rollbackError: any = null
try {
await this.knexClient.rollback()
this.emit('rollback', this)
this.removeAllListeners()
} catch (error) {
rollbackError = error
}

/**
* Raise exception when commit fails
*/
if (rollbackError) {
this.hooks.clearAll()
throw rollbackError
this.removeAllListeners()
throw error
}

/**
* Execute after hooks
*/
await this.hooks.execute('after', 'rollback', this)
this.hooks.clearAll()
}
}
31 changes: 12 additions & 19 deletions test/database/transactions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,27 +100,24 @@ test.group('Transaction | query', (group) => {
assert.equal(results[0].username, 'virk')
})

test('execute before and after commit hooks', async (assert) => {
test('emit after commit event', async (assert) => {
const stack: string[] = []
const connection = new Connection('primary', getConfig(), getLogger())
connection.connect()

const db = await new QueryClient('dual', connection).transaction()

db.hooks.before('commit', (trx) => {
stack.push('before')
assert.instanceOf(trx, TransactionClient)
})

db.hooks.after('commit', (trx) => {
stack.push('after')
db.on('commit', (trx) => {
stack.push('commit')
assert.instanceOf(trx, TransactionClient)
})

await db.insertQuery().table('users').insert({ username: 'virk' })
await db.commit()
assert.deepEqual(db.hooks['_hooks'], {})
assert.deepEqual(stack, ['before', 'after'])

assert.deepEqual(db.listenerCount('commit'), 0)
assert.deepEqual(db.listenerCount('rollback'), 0)
assert.deepEqual(stack, ['commit'])
})

test('execute before and after rollback hooks', async (assert) => {
Expand All @@ -130,19 +127,15 @@ test.group('Transaction | query', (group) => {

const db = await new QueryClient('dual', connection).transaction()

db.hooks.before('rollback', (trx) => {
stack.push('before')
assert.instanceOf(trx, TransactionClient)
})

db.hooks.after('rollback', (trx) => {
stack.push('after')
db.on('rollback', (trx) => {
stack.push('rollback')
assert.instanceOf(trx, TransactionClient)
})

await db.insertQuery().table('users').insert({ username: 'virk' })
await db.rollback()
assert.deepEqual(db.hooks['_hooks'], {})
assert.deepEqual(stack, ['before', 'after'])
assert.deepEqual(db.listenerCount('commit'), 0)
assert.deepEqual(db.listenerCount('rollback'), 0)
assert.deepEqual(stack, ['rollback'])
})
})

0 comments on commit 2b04b85

Please sign in to comment.