2023-07-19 16:35:50 +02:00
|
|
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
|
|
import { Knex } from 'knex';
|
2022-09-12 15:24:53 +02:00
|
|
|
|
2023-09-21 16:49:53 +02:00
|
|
|
export type Callback = (...args: any[]) => Promise<any> | any;
|
2022-09-12 15:24:53 +02:00
|
|
|
|
2023-09-21 16:49:53 +02:00
|
|
|
export interface TransactionObject {
|
|
|
|
commit: () => Promise<void>;
|
|
|
|
rollback: () => Promise<void>;
|
|
|
|
get: () => Knex.Transaction;
|
|
|
|
}
|
2023-07-19 16:35:50 +02:00
|
|
|
export interface Store {
|
|
|
|
trx: Knex.Transaction | null;
|
|
|
|
commitCallbacks: Callback[];
|
|
|
|
rollbackCallbacks: Callback[];
|
|
|
|
}
|
|
|
|
|
|
|
|
const storage = new AsyncLocalStorage<Store>();
|
2022-09-12 15:24:53 +02:00
|
|
|
|
|
|
|
const transactionCtx = {
|
2024-01-30 11:00:08 +01:00
|
|
|
async run<TCallback extends Callback>(trx: Knex.Transaction, cb: TCallback) {
|
|
|
|
const store = storage.getStore();
|
2023-09-21 16:49:53 +02:00
|
|
|
return storage.run<ReturnType<TCallback>, void[]>(
|
2024-01-30 11:00:08 +01:00
|
|
|
{
|
|
|
|
trx,
|
|
|
|
// Fill with existing callbacks if nesting transactions
|
|
|
|
commitCallbacks: store?.commitCallbacks || [],
|
|
|
|
rollbackCallbacks: store?.rollbackCallbacks || [],
|
|
|
|
},
|
2023-09-21 16:49:53 +02:00
|
|
|
cb
|
|
|
|
);
|
2022-09-12 15:24:53 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
get() {
|
2023-04-11 16:10:24 +02:00
|
|
|
const store = storage.getStore();
|
|
|
|
return store?.trx;
|
|
|
|
},
|
|
|
|
|
2023-07-19 16:35:50 +02:00
|
|
|
async commit(trx: Knex.Transaction) {
|
2023-04-11 16:10:24 +02:00
|
|
|
const store = storage.getStore();
|
2023-05-18 12:57:47 +02:00
|
|
|
|
|
|
|
// Clear transaction from store
|
|
|
|
if (store?.trx) {
|
|
|
|
store.trx = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Commit transaction
|
|
|
|
await trx.commit();
|
|
|
|
|
2023-07-19 16:35:50 +02:00
|
|
|
if (!store?.commitCallbacks.length) {
|
|
|
|
return;
|
|
|
|
}
|
2023-05-18 12:57:47 +02:00
|
|
|
|
|
|
|
// Run callbacks
|
|
|
|
store.commitCallbacks.forEach((cb) => cb());
|
|
|
|
store.commitCallbacks = [];
|
|
|
|
},
|
|
|
|
|
2023-07-19 16:35:50 +02:00
|
|
|
async rollback(trx: Knex.Transaction) {
|
2023-05-18 12:57:47 +02:00
|
|
|
const store = storage.getStore();
|
|
|
|
|
|
|
|
// Clear transaction from store
|
2023-04-11 16:10:24 +02:00
|
|
|
if (store?.trx) {
|
|
|
|
store.trx = null;
|
|
|
|
}
|
2023-05-18 12:57:47 +02:00
|
|
|
|
|
|
|
// Rollback transaction
|
|
|
|
await trx.rollback();
|
|
|
|
|
2023-07-19 16:35:50 +02:00
|
|
|
if (!store?.rollbackCallbacks.length) {
|
|
|
|
return;
|
|
|
|
}
|
2023-05-18 12:57:47 +02:00
|
|
|
|
|
|
|
// Run callbacks
|
|
|
|
store.rollbackCallbacks.forEach((cb) => cb());
|
|
|
|
store.rollbackCallbacks = [];
|
|
|
|
},
|
|
|
|
|
2023-07-19 16:35:50 +02:00
|
|
|
onCommit(cb: Callback) {
|
2023-05-18 12:57:47 +02:00
|
|
|
const store = storage.getStore();
|
2023-05-22 15:19:53 +02:00
|
|
|
if (store?.commitCallbacks) {
|
2023-05-22 17:08:43 +02:00
|
|
|
store.commitCallbacks.push(cb);
|
2023-05-18 12:57:47 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2023-07-19 16:35:50 +02:00
|
|
|
onRollback(cb: Callback) {
|
2023-05-18 12:57:47 +02:00
|
|
|
const store = storage.getStore();
|
2023-05-22 15:19:53 +02:00
|
|
|
if (store?.rollbackCallbacks) {
|
2023-05-22 17:08:43 +02:00
|
|
|
store.rollbackCallbacks.push(cb);
|
2023-05-18 12:57:47 +02:00
|
|
|
}
|
2022-09-12 15:24:53 +02:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2023-07-19 16:35:50 +02:00
|
|
|
export { transactionCtx };
|