-
Notifications
You must be signed in to change notification settings - Fork 54
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[TECH] Ajoute la domainTransaction dans le AsyncLocalStorage (PIX-13257…
…). #9423
- Loading branch information
Showing
8 changed files
with
152 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,44 @@ | ||
import { AsyncLocalStorage } from 'node:async_hooks'; | ||
|
||
import { knex } from '../../../db/knex-database-connection.js'; | ||
|
||
const asyncLocalStorage = new AsyncLocalStorage(); | ||
|
||
class DomainTransaction { | ||
constructor(knexTransaction) { | ||
this.knexTransaction = knexTransaction; | ||
} | ||
|
||
static execute(lambda) { | ||
static execute(lambda, transactionConfig) { | ||
return knex.transaction((trx) => { | ||
return lambda(new DomainTransaction(trx)); | ||
}); | ||
const domainTransaction = new DomainTransaction(trx); | ||
return asyncLocalStorage.run({ transaction: domainTransaction }, lambda, domainTransaction); | ||
}, transactionConfig); | ||
} | ||
|
||
static getConnection() { | ||
const store = asyncLocalStorage.getStore(); | ||
|
||
if (store?.transaction) { | ||
const domainTransaction = store.transaction; | ||
return domainTransaction.knexTransaction; | ||
} | ||
return knex; | ||
} | ||
|
||
static emptyTransaction() { | ||
return new DomainTransaction(null); | ||
} | ||
} | ||
export { DomainTransaction }; | ||
|
||
/** | ||
* @template F | ||
* @param {F} func | ||
* @param {import('knex').Knex.TransactionConfig | undefined} transactionConfig | ||
* @returns {F} | ||
*/ | ||
function withTransaction(func, transactionConfig) { | ||
return (...args) => DomainTransaction.execute(() => func(...args), transactionConfig); | ||
} | ||
|
||
export { asyncLocalStorage, DomainTransaction, withTransaction }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import { | ||
asyncLocalStorage, | ||
DomainTransaction, | ||
withTransaction, | ||
} from '../../../../src/shared/domain/DomainTransaction.js'; | ||
import { expect, knex, sinon } from '../../../../tests/test-helper.js'; | ||
|
||
describe('Unit | Infrastructure | DomainTransaction', function () { | ||
describe('#getConnection', function () { | ||
it('should return connection from store', function () { | ||
const transaction = Symbol('transaction'); | ||
const domainTransaction = new DomainTransaction(transaction); | ||
const storeStub = { transaction: domainTransaction }; | ||
sinon.stub(asyncLocalStorage, 'getStore'); | ||
asyncLocalStorage.getStore.returns(storeStub); | ||
|
||
const connection = DomainTransaction.getConnection(); | ||
|
||
expect(connection).to.equal(transaction); | ||
}); | ||
|
||
it('should return knex connection by default', function () { | ||
sinon.stub(asyncLocalStorage, 'getStore'); | ||
|
||
const connection = DomainTransaction.getConnection(); | ||
|
||
expect(connection).to.equal(knex); | ||
}); | ||
}); | ||
|
||
describe('#execute', function () { | ||
it('should store transaction', async function () { | ||
const transactionStub = {}; | ||
const domainTransaction = new DomainTransaction(transactionStub); | ||
sinon.stub(asyncLocalStorage, 'run'); | ||
sinon.stub(knex, 'transaction'); | ||
knex.transaction.callsFake((fn) => fn(transactionStub)); | ||
|
||
await DomainTransaction.execute(function () { | ||
// Something | ||
}); | ||
|
||
expect(asyncLocalStorage.run).to.have.been.calledWith({ transaction: domainTransaction }); | ||
}); | ||
|
||
it('should return function result', async function () { | ||
const transactionConfiguration = { isolationLevel: 'read committed' }; | ||
const expectedResult = Symbol('return'); | ||
sinon.stub(knex, 'transaction'); | ||
knex.transaction.callsFake((fn) => fn({})); | ||
|
||
await DomainTransaction.execute(() => expectedResult, transactionConfiguration); | ||
|
||
expect(knex.transaction.getCalls()[0].args).to.includes(transactionConfiguration); | ||
}); | ||
|
||
it('should use configuration for transaction', async function () { | ||
const transactionStub = {}; | ||
const domainTransaction = new DomainTransaction(transactionStub); | ||
sinon.stub(asyncLocalStorage, 'run'); | ||
sinon.stub(knex, 'transaction'); | ||
knex.transaction.callsFake((fn) => fn(transactionStub)); | ||
|
||
await DomainTransaction.execute(function () { | ||
// Something | ||
}); | ||
|
||
expect(asyncLocalStorage.run).to.have.been.calledWith({ transaction: domainTransaction }); | ||
}); | ||
}); | ||
|
||
describe('#withTransaction', function () { | ||
it('should get transaction from store', async function () { | ||
const transactionStub = { commit: sinon.stub() }; | ||
sinon.stub(knex, 'transaction'); | ||
knex.transaction.callsFake(() => transactionStub); | ||
const myUseCase = withTransaction(() => { | ||
return DomainTransaction.getConnection(); | ||
}); | ||
const connection = await myUseCase(); | ||
|
||
expect(connection).to.equal(transactionStub); | ||
}); | ||
|
||
it('should use configuration for transaction', async function () { | ||
const transactionStub = {}; | ||
const domainTransaction = new DomainTransaction(transactionStub); | ||
sinon.stub(asyncLocalStorage, 'run'); | ||
sinon.stub(knex, 'transaction'); | ||
knex.transaction.callsFake((fn) => fn(transactionStub)); | ||
|
||
const myUseCase = withTransaction(function () { | ||
// Something | ||
}); | ||
await myUseCase(); | ||
|
||
expect(asyncLocalStorage.run).to.have.been.calledWith({ transaction: domainTransaction }); | ||
}); | ||
}); | ||
}); |