1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-31 00:16:47 +01:00
unleash.unleash/src/lib/db/transaction.ts
Gastón Fournier 0da48cc0d1
chore: revamp transactional impl (#4916)
## About the changes
This transactional implementation decorates a service with a
transactional method that removes the need to start transactions in the
method using the service.

This is a gradual rollout with a feature toggle, just because
transactions are not easy.
2023-10-04 15:16:37 +02:00

54 lines
1.5 KiB
TypeScript

import { Knex } from 'knex';
export type KnexTransaction = Knex.Transaction;
export type MockTransaction = null;
export type UnleashTransaction = KnexTransaction | MockTransaction;
export type TransactionCreator<S> = <T>(
scope: (trx: S) => void | Promise<T>,
) => Promise<T>;
export const createKnexTransactionStarter = (
knex: Knex,
): TransactionCreator<UnleashTransaction> => {
function transaction<T>(
scope: (trx: KnexTransaction) => void | Promise<T>,
) {
return knex.transaction(scope);
}
return transaction;
};
export type DbServiceFactory<S> = (db: Knex) => S;
export type WithTransactional<S> = S & {
transactional: <R>(fn: (service: S) => R) => Promise<R>;
};
export function withTransactional<S>(
serviceFactory: (db: Knex) => S,
db: Knex,
): WithTransactional<S> {
const service = serviceFactory(db) as WithTransactional<S>;
service.transactional = async <R>(fn: (service: S) => R) =>
db.transaction(async (trx: Knex.Transaction) => {
const transactionalService = serviceFactory(trx);
return fn(transactionalService);
});
return service;
}
/** Just for testing purposes */
export function withFakeTransactional<S>(service: S): WithTransactional<S> {
const serviceWithFakeTransactional = service as WithTransactional<S>;
serviceWithFakeTransactional.transactional = async <R>(
fn: (service: S) => R,
) => fn(serviceWithFakeTransactional);
return serviceWithFakeTransactional;
}