Skip to content

Commit 9542cdb

Browse files
authored
feat(transactional): enable adapters to opt out of transactional proxy support (#160)
1 parent e98711c commit 9542cdb

File tree

4 files changed

+56
-3
lines changed

4 files changed

+56
-3
lines changed

docs/docs/06_plugins/01_available-plugins/01-transactional/index.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,11 @@ class AccountService {
212212

213213
When a transaction is not active, the `Transaction` instance refers to the default non-transactional instance. However, if the CLS context is _not active_, the `Transaction` instance will be `undefined` instead, which could cause runtime errors.
214214

215-
Therefore, this feature works reliably only when the CLS context is active _prior to starting the transaction_, which should be the case in most cases, however, for that reason, this is an opt-in feature that must be explicitly enabled with the `enableTransactionProxy: true` option of the `ClsPluginTransactional` constructor.
215+
Therefore, this feature works reliably only when the CLS context is active _prior to starting the transaction_.
216+
217+
Additionally, _some adapters do not support this feature_ due to the nature of how transactions work in the library they implement.
218+
219+
For these reasons, this is an opt-in feature that must be explicitly enabled with the `enableTransactionProxy: true` option of the `ClsPluginTransactional` constructor.
216220

217221
```ts
218222
new ClsPluginTransactional({
@@ -223,7 +227,7 @@ new ClsPluginTransactional({
223227
// highlight-start
224228
enableTransactionProxy: true,
225229
// highlight-end
226-
}),
230+
});
227231
```
228232

229233
:::

packages/transactional/src/lib/interfaces.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ export interface MergedTransactionalAdapterOptions<TTx, TOptions>
2020
connectionName: string | undefined;
2121
enableTransactionProxy: boolean;
2222
defaultTxOptions: Partial<TOptions>;
23-
onModuleInit?: () => void | Promise<void>;
2423
}
2524

2625
export type TransactionalOptionsAdapterFactory<TConnection, TTx, TOptions> = (
@@ -59,6 +58,15 @@ export interface TransactionalAdapter<TConnection, TTx, TOptions>
5958
TTx,
6059
TOptions
6160
>;
61+
62+
/**
63+
* Whether this adapter support the {@link TransactionalPluginOptions.enableTransactionProxy} option.
64+
*
65+
* The default is `true`. Set to `false` to explicitly forbid this feature.
66+
*
67+
* When set to `false`, and {@link TransactionalPluginOptions.enableTransactionProxy} is `true`, an error will be thrown.
68+
*/
69+
supportsTransactionProxy?: boolean;
6270
}
6371

6472
export interface TransactionalPluginOptions<TConnection, TTx, TOptions> {
@@ -78,6 +86,8 @@ export interface TransactionalPluginOptions<TConnection, TTx, TOptions> {
7886
* Whether to enable injecting the Transaction instance directly using `@InjectTransaction()`
7987
*
8088
* Default: `false`
89+
*
90+
* Note: Not all adapters support this feature, please refer to the docs for the adapter you are using.
8191
*/
8292
enableTransactionProxy?: boolean;
8393
}

packages/transactional/src/lib/plugin-transactional.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { getTransactionToken } from './inject-transaction.decorator';
44
import {
55
MergedTransactionalAdapterOptions,
66
OptionalLifecycleHooks,
7+
TransactionalAdapter,
78
TransactionalPluginOptions,
89
} from './interfaces';
910
import {
@@ -60,6 +61,9 @@ export class ClsPluginTransactional implements ClsPlugin {
6061
this.exports.push(transactionHostToken);
6162

6263
if (options.enableTransactionProxy) {
64+
if (options.adapter.supportsTransactionProxy === false) {
65+
throw new TransactionProxyUnsupportedError(options.adapter);
66+
}
6367
const transactionProxyToken = getTransactionToken(
6468
options.connectionName,
6569
);
@@ -98,3 +102,11 @@ export class ClsPluginTransactional implements ClsPlugin {
98102
};
99103
}
100104
}
105+
106+
export class TransactionProxyUnsupportedError extends Error {
107+
constructor(adapter: TransactionalAdapter<any, any, any>) {
108+
super(
109+
`The adapter ${adapter.constructor.name} does not support the "Transaction Proxy" feature, please disable the "enableTransactionProxy" option.`,
110+
);
111+
}
112+
}

packages/transactional/test/inject-transaction.spec.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
Transaction,
99
Transactional,
1010
TransactionHost,
11+
TransactionProxyUnsupportedError,
1112
} from '../src';
1213
import {
1314
MockDbConnection,
@@ -201,3 +202,29 @@ describe('InjectTransaction with multiple named connections', () => {
201202
});
202203
});
203204
});
205+
206+
class TransactionAdapterMockWithoutTransactionProxySupport extends TransactionAdapterMock {
207+
supportsTransactionProxy = false;
208+
}
209+
210+
describe('Using enableTransactionProxy when the adapter does not support it', () => {
211+
it('should throw an error', async () => {
212+
const modulePromise = () =>
213+
Test.createTestingModule({
214+
imports: [
215+
ClsModule.forRoot({
216+
plugins: [
217+
new ClsPluginTransactional({
218+
enableTransactionProxy: true,
219+
adapter:
220+
new TransactionAdapterMockWithoutTransactionProxySupport(
221+
{ connectionToken: MockDbConnection1 },
222+
),
223+
}),
224+
],
225+
}),
226+
],
227+
}).compile();
228+
expect(modulePromise).toThrowError(TransactionProxyUnsupportedError);
229+
});
230+
});

0 commit comments

Comments
 (0)