Skip to content

Commit 7ab6c7c

Browse files
author
Lars-Erik Roald
committed
hooks tests
1 parent 1845a98 commit 7ab6c7c

File tree

9 files changed

+512
-33
lines changed

9 files changed

+512
-33
lines changed

src/getTSDefinition.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,7 @@ export interface ExpressConfig {
441441
concurrency?: Concurrency;
442442
readonly?: boolean;
443443
disableBulkDeletes?: boolean;
444+
hooks?: ExpressHooks;
444445
}
445446
446447
export interface ExpressContext {
@@ -449,6 +450,18 @@ export interface ExpressContext {
449450
client: RdbClient;
450451
}
451452
453+
export interface ExpressTransactionHooks {
454+
beforeBegin?: (db: Pool, request: import('express').Request, response: import('express').Response) => void | Promise<void>;
455+
afterBegin?: (db: Pool, request: import('express').Request, response: import('express').Response) => void | Promise<void>;
456+
beforeCommit?: (db: Pool, request: import('express').Request, response: import('express').Response) => void | Promise<void>;
457+
afterCommit?: (db: Pool, request: import('express').Request, response: import('express').Response) => void | Promise<void>;
458+
afterRollback?: (db: Pool, request: import('express').Request, response: import('express').Response, error?: unknown) => void | Promise<void>;
459+
}
460+
461+
export interface ExpressHooks extends ExpressTransactionHooks {
462+
transaction?: ExpressTransactionHooks;
463+
}
464+
452465
export interface ExpressTables {${getExpressTables()}
453466
}
454467
`;
@@ -515,4 +528,4 @@ export interface ExpressTables {${getExpressTables()}
515528
}
516529
}
517530

518-
module.exports = getTSDefinition;
531+
module.exports = getTSDefinition;

src/hostExpress.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,18 @@ function hostExpress(hostLocal, client, options = {}) {
88
const dbOptions = { db: options.db || client.db };
99
let c = {};
1010
const readonly = { readonly: options.readonly};
11+
const sharedHooks = options.hooks;
1112
for (let tableName in client.tables) {
13+
const tableOptions = options[tableName] || {};
14+
const hooks = tableOptions.hooks || sharedHooks;
1215
c[tableName] = hostLocal({
1316
...dbOptions,
1417
...readonly,
15-
...options[tableName],
18+
...tableOptions,
1619
table: client.tables[tableName],
17-
isHttp: true, client
20+
isHttp: true,
21+
client,
22+
hooks
1823

1924
});
2025
}
@@ -117,4 +122,4 @@ function hostExpress(hostLocal, client, options = {}) {
117122
return handler;
118123
}
119124

120-
module.exports = hostExpress;
125+
module.exports = hostExpress;

src/hostLocal.js

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ const readonlyOps = ['getManyDto', 'getMany', 'aggregate', 'count'];
1313
// disableBulkDeletes, isBrowser }
1414
function hostLocal() {
1515
const _options = arguments[0];
16-
let { table, transaction, db, isHttp, hooks } = _options;
16+
let { table, transaction, db, isHttp, hooks, client } = _options;
17+
const transactionHooks = hooks && hooks.transaction;
18+
const getTransactionHook = (name) =>
19+
(transactionHooks && transactionHooks[name]) || (hooks && hooks[name]);
1720

1821
let c = { get, post, patch, query, sqliteFunction, express };
1922

@@ -66,19 +69,39 @@ function hostLocal() {
6669
else
6770
db = dbPromise;
6871
}
69-
const hasTransactionHooks = !!(hooks?.beforeTransactionBegin
70-
|| hooks?.afterTransactionBegin
71-
|| hooks?.beforeTransactionCommit
72-
|| hooks?.afterTransactionCommit);
72+
const beforeBegin = getTransactionHook('beforeBegin');
73+
const afterBegin = getTransactionHook('afterBegin');
74+
const beforeCommit = getTransactionHook('beforeCommit');
75+
const afterCommit = getTransactionHook('afterCommit');
76+
const afterRollback = getTransactionHook('afterRollback');
77+
const hasTransactionHooks = !!(beforeBegin
78+
|| afterBegin
79+
|| beforeCommit
80+
|| afterCommit
81+
|| afterRollback);
7382
if (!hasTransactionHooks && readonlyOps.includes(body.path))
7483
await db.transaction({ readonly: true }, fn);
7584
else {
76-
if (hooks?.beforeTransactionBegin) {
77-
await hooks.beforeTransactionBegin(db, request, response);
78-
79-
}
80-
81-
await db.transaction(fn);
85+
await db.transaction(async (context) => {
86+
const hookDb = typeof client === 'function'
87+
? client({ transaction: (fn) => fn(context) })
88+
: (client || db);
89+
if (afterCommit)
90+
setSessionSingleton(context, 'afterCommitHook', () =>
91+
afterCommit(hookDb, request, response)
92+
);
93+
if (afterRollback)
94+
setSessionSingleton(context, 'afterRollbackHook', (error) =>
95+
afterRollback(hookDb, request, response, error)
96+
);
97+
if (beforeBegin)
98+
await beforeBegin(hookDb, request, response);
99+
if (afterBegin)
100+
await afterBegin(hookDb, request, response);
101+
await fn(context);
102+
if (beforeCommit)
103+
await beforeCommit(hookDb, request, response);
104+
});
82105
}
83106

84107
}

src/map2.d.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -924,16 +924,29 @@ type ExpressConfig<M extends Record<string, TableDefinition<M>>> = {
924924
[TableName in keyof M]?: ExpressTableConfig<M>;
925925
} & {
926926
db?: Pool | ((connectors: Connectors) => Pool | Promise<Pool>);
927+
hooks?: ExpressHooks<M>;
927928
}
928929

929930
type ExpressTableConfig<M extends Record<string, TableDefinition<M>>> = {
930931
baseFilter?: RawFilter | ((db: DBClient<M>, req: import('express').Request, res: import('express').Response) => RawFilter);
931932
}
932933

934+
type ExpressTransactionHooks<M extends Record<string, TableDefinition<M>>> = {
935+
beforeBegin?: (db: DBClient<M>, req: import('express').Request, res: import('express').Response) => void | Promise<void>;
936+
afterBegin?: (db: DBClient<M>, req: import('express').Request, res: import('express').Response) => void | Promise<void>;
937+
beforeCommit?: (db: DBClient<M>, req: import('express').Request, res: import('express').Response) => void | Promise<void>;
938+
afterCommit?: (db: DBClient<M>, req: import('express').Request, res: import('express').Response) => void | Promise<void>;
939+
afterRollback?: (db: DBClient<M>, req: import('express').Request, res: import('express').Response, error?: unknown) => void | Promise<void>;
940+
}
941+
942+
type ExpressHooks<M extends Record<string, TableDefinition<M>>> = ExpressTransactionHooks<M> & {
943+
transaction?: ExpressTransactionHooks<M>;
944+
}
945+
933946
export type DeepExpand<T> =
934947
T extends Date ? T :
935948
T extends Array<infer U> ? Array<DeepExpand<U>> :
936949
T extends object ? { [K in keyof T]: DeepExpand<T[K]> } :
937950
T;
938951

939-
export function db<M extends Record<string, TableDefinition<M>>>(): DBClient<M>;
952+
export function db<M extends Record<string, TableDefinition<M>>>(): DBClient<M>;

src/nodeSqlite/newDatabase.js

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,12 @@ function newDatabase(connectionString, poolOptions, hooks) {
1818

1919
// Normalize hooks with safe no-ops
2020
hooks = hooks || {};
21+
const transactionHooks = hooks.transaction || {};
22+
const getTransactionHook = (name) =>
23+
(transactionHooks && transactionHooks[name]) || (hooks && hooks[name]);
2124
const callHook = async (name, ...args) => {
2225
try {
23-
const fn = hooks && hooks[name];
26+
const fn = getTransactionHook(name);
2427
if (typeof fn === 'function') {
2528
return await fn(...args);
2629
}
@@ -34,7 +37,6 @@ function newDatabase(connectionString, poolOptions, hooks) {
3437
let c = {poolFactory: pool, hostLocal, express};
3538

3639
c.transaction = function(options, fn) {
37-
console.dir('trancation.........yes');
3840
if ((arguments.length === 1) && (typeof options === 'function')) {
3941
fn = options;
4042
options = undefined;
@@ -44,14 +46,13 @@ function newDatabase(connectionString, poolOptions, hooks) {
4446

4547
if (!fn)
4648
throw new Error('transaction requires a function');
47-
console.dir('run fn in trans........');
4849
return domain.run(runInTransaction);
4950

5051
function begin() {
5152
return Promise.resolve()
52-
.then(() => callHook('beforeTransactionBegin', c, req))
53+
.then(() => callHook('beforeBegin', c, req))
5354
.then(() => _begin(domain, options))
54-
.then((res) => Promise.resolve(callHook('afterTransactionBegin', c, req)).then(() => res));
55+
.then((res) => Promise.resolve(callHook('afterBegin', c, req)).then(() => res));
5556
}
5657

5758
async function runInTransaction() {
@@ -61,11 +62,11 @@ function newDatabase(connectionString, poolOptions, hooks) {
6162
.then(begin)
6263
.then(() => fn(domain))
6364
.then((res) => result = res)
64-
.then(() => Promise.resolve(callHook('beforeTransactionCommit', c, req)))
65+
.then(() => Promise.resolve(callHook('beforeCommit', c, req)))
6566
.then(() => commit(domain))
66-
.then(() => callHook('afterTransactionCommit', c, req))
67+
.then(() => callHook('afterCommit', c, req))
6768
.then(null, (e) => Promise.resolve(rollback(domain, e))
68-
.then(() => callHook('afterTransactionRollback', c, req, e))
69+
.then(() => callHook('afterRollback', c, req, e))
6970
);
7071
return result;
7172
}
@@ -85,20 +86,20 @@ function newDatabase(connectionString, poolOptions, hooks) {
8586
}
8687
run.rollback = function(error) {
8788
return Promise.resolve(rollback(domain, error))
88-
.then(() => callHook('afterTransactionRollback', c, req, error));
89+
.then(() => callHook('afterRollback', c, req, error));
8990
};
9091
run.commit = function() {
91-
return Promise.resolve(callHook('beforeTransactionCommit', c, req))
92+
return Promise.resolve(callHook('beforeCommit', c, req))
9293
.then(() => commit(domain))
93-
.then(() => callHook('afterTransactionCommit', c, req));
94+
.then(() => callHook('afterCommit', c, req));
9495
};
9596
return run;
9697

9798
function begin() {
9899
return Promise.resolve()
99-
.then(() => callHook('beforeTransactionBegin', c, req))
100+
.then(() => callHook('beforeBegin', c, req))
100101
.then(() => _begin(domain, options))
101-
.then((res) => Promise.resolve(callHook('afterTransactionBegin', c, req)).then(() => res));
102+
.then((res) => Promise.resolve(callHook('afterBegin', c, req)).then(() => res));
102103
}
103104
};
104105

src/table/commit.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,34 @@ let popChanges = require('./popChanges');
66
const getSessionSingleton = require('./getSessionSingleton');
77

88
function _commit(context, result) {
9+
let hookError;
910
return popAndPushChanges()
11+
.then(callAfterCommit)
1012
.then(releaseDbClient.bind(null, context))
11-
.then(onReleased);
13+
.then(onReleased)
14+
.then(throwHookErrorIfAny);
1215

1316
function onReleased() {
1417
return result;
1518
}
1619

20+
function throwHookErrorIfAny(res) {
21+
if (hookError)
22+
throw hookError;
23+
return res;
24+
}
25+
26+
function callAfterCommit() {
27+
const hook = getSessionSingleton(context, 'afterCommitHook');
28+
if (!hook)
29+
return Promise.resolve();
30+
return Promise.resolve()
31+
.then(() => hook())
32+
.catch((e) => {
33+
hookError = e;
34+
});
35+
}
36+
1737
async function popAndPushChanges() {
1838
let changes = popChanges(context);
1939
while (changes.length > 0) {

src/table/rollback.js

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@ const conflictId = '12345678-1234-1234-1234-123456789012';
88
const getSessionSingleton = require('./getSessionSingleton');
99

1010
function _rollback(context, e) {
11+
let hookError;
1112
var chain = resultToPromise()
1213
.then(() => popChanges(context))
1314
.then(executeRollback)
14-
.then(() => releaseDbClient(context));
15+
.then(callAfterRollback)
16+
.then(() => releaseDbClient(context))
17+
.then(throwHookErrorIfAny);
1518

1619

1720
function executeRollback() {
@@ -21,6 +24,23 @@ function _rollback(context, e) {
2124
return executeQuery(context, rollbackCommand);
2225
}
2326

27+
function callAfterRollback() {
28+
const hook = getSessionSingleton(context, 'afterRollbackHook');
29+
if (!hook)
30+
return Promise.resolve();
31+
return Promise.resolve()
32+
.then(() => hook(e))
33+
.catch((err) => {
34+
hookError = err;
35+
});
36+
}
37+
38+
function throwHookErrorIfAny(res) {
39+
if (hookError)
40+
throw hookError;
41+
return res;
42+
}
43+
2444
if (e) {
2545
if (e.message?.indexOf('ORA-01476: divisor is equal to zero') > -1)
2646
return newThrow(context, new Error('Conflict when updating a column'), chain);
@@ -38,4 +58,4 @@ function rollback(context, e) {
3858
return Promise.resolve().then(() => _rollback(context, e));
3959
}
4060

41-
module.exports = rollback;
61+
module.exports = rollback;

0 commit comments

Comments
 (0)