@nestjs-transactional/typeorm 1.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +361 -0
  3. package/dist/adapter/typeorm.adapter.d.ts +39 -0
  4. package/dist/adapter/typeorm.adapter.js +79 -0
  5. package/dist/adapter/typeorm.adapter.js.map +1 -0
  6. package/dist/helpers/get-entity-manager.d.ts +27 -0
  7. package/dist/helpers/get-entity-manager.js +52 -0
  8. package/dist/helpers/get-entity-manager.js.map +1 -0
  9. package/dist/index.d.ts +5 -0
  10. package/dist/index.js +21 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/module/typeorm-transactional.module.d.ts +157 -0
  13. package/dist/module/typeorm-transactional.module.js +289 -0
  14. package/dist/module/typeorm-transactional.module.js.map +1 -0
  15. package/dist/patching/data-source-patches.d.ts +48 -0
  16. package/dist/patching/data-source-patches.js +139 -0
  17. package/dist/patching/data-source-patches.js.map +1 -0
  18. package/dist/patching/entity-manager-patches.d.ts +31 -0
  19. package/dist/patching/entity-manager-patches.js +86 -0
  20. package/dist/patching/entity-manager-patches.js.map +1 -0
  21. package/dist/patching/index.d.ts +49 -0
  22. package/dist/patching/index.js +75 -0
  23. package/dist/patching/index.js.map +1 -0
  24. package/dist/patching/managed-registry.d.ts +59 -0
  25. package/dist/patching/managed-registry.js +112 -0
  26. package/dist/patching/managed-registry.js.map +1 -0
  27. package/dist/patching/repository-patches.d.ts +56 -0
  28. package/dist/patching/repository-patches.js +150 -0
  29. package/dist/patching/repository-patches.js.map +1 -0
  30. package/dist/patching/symbols.d.ts +53 -0
  31. package/dist/patching/symbols.js +56 -0
  32. package/dist/patching/symbols.js.map +1 -0
  33. package/dist/types/typeorm-transaction-handle.d.ts +17 -0
  34. package/dist/types/typeorm-transaction-handle.js +3 -0
  35. package/dist/types/typeorm-transaction-handle.js.map +1 -0
  36. package/package.json +79 -0
@@ -0,0 +1,157 @@
1
+ import { type DynamicModule, type InjectionToken, type ModuleMetadata } from '@nestjs/common';
2
+ /**
3
+ * Options accepted by {@link TypeOrmTransactionalModule.forRoot}.
4
+ *
5
+ * Phase 14.20 reshape: this module now resolves the actual TypeORM
6
+ * `DataSource` via DI (using `getDataSourceToken` from
7
+ * `@nestjs/typeorm`) instead of taking it as a constructor argument.
8
+ * The new contract is "TypeORM is configured by `@nestjs/typeorm`'s
9
+ * `TypeOrmModule.forRoot(...)`; we just bind to it by name."
10
+ */
11
+ export interface TypeOrmTransactionalOptions {
12
+ /**
13
+ * DataSource name as used by `@nestjs/typeorm`'s
14
+ * `TypeOrmModule.forRoot({ name })`. Defaults to `'default'`. The
15
+ * actual `DataSource` instance is resolved from DI under
16
+ * `getDataSourceToken(this.dataSource)`.
17
+ */
18
+ readonly dataSource?: string;
19
+ /**
20
+ * Mark this adapter as the registry-level default. Affects
21
+ * `@Transactional()` calls that omit the `dataSource` option.
22
+ * Defaults to `false`; the first registered adapter becomes the
23
+ * default automatically (per {@link AdapterRegistry.register}).
24
+ */
25
+ readonly isDefault?: boolean;
26
+ }
27
+ /**
28
+ * Asynchronous flavour of {@link TypeOrmTransactionalOptions}.
29
+ *
30
+ * **Per-DS DI token limitation**: the per-dataSource adapter token
31
+ * (`getTransactionalAdapterToken(ds)`) is NOT registered for
32
+ * `forRootAsync` because the dataSource name is only known after
33
+ * the async factory runs, while NestJS provider tokens must be
34
+ * declared statically. If per-DS injection of the adapter matters,
35
+ * use sync `forRoot({ dataSource })` instead. The
36
+ * `AdapterRegistry`-based access path
37
+ * (`@Transactional({ dataSource })`,
38
+ * `getCurrentEntityManager(dataSource)`,
39
+ * `manager.run({ dataSource })`) is unaffected — those route
40
+ * through the registry, which the eager-registration factory
41
+ * populates as a side effect.
42
+ *
43
+ * Mirrors the documented limitation on
44
+ * `TransactionalModule.forRootAsync` (Phase 14.10).
45
+ */
46
+ export interface TypeOrmTransactionalAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
47
+ readonly useFactory: (...args: never[]) => Promise<TypeOrmTransactionalOptions> | TypeOrmTransactionalOptions;
48
+ readonly inject?: readonly InjectionToken[];
49
+ }
50
+ /**
51
+ * NestJS module that binds a TypeORM {@link DataSource} to the core
52
+ * {@link AdapterRegistry} as a transactional adapter AND activates
53
+ * the transparent transactional patching machinery (Phase 14.20).
54
+ * Once registered:
55
+ *
56
+ * - Every `Repository` reachable via `@InjectRepository`,
57
+ * `dataSource.getRepository(...)`, `entityManager.getRepository(...)`,
58
+ * or `repo.extend(...)` automatically dispatches inside the active
59
+ * `@Transactional()` scope.
60
+ * - `dataSource.query(...)` and `dataSource.createQueryBuilder(...)`
61
+ * pick up the transactional `QueryRunner`.
62
+ * - `@InjectEntityManager() em.getRepository(E).save(...)` works
63
+ * transactionally (the wrapped `EntityManager.prototype.getRepository`
64
+ * stamps the manager reference). Direct
65
+ * `@InjectEntityManager() em.save(E, ...)` is a documented
66
+ * limitation — use the Repository pattern or
67
+ * `getCurrentEntityManager()` as escape hatch.
68
+ *
69
+ * Multi-dataSource deployments call {@link forRoot} once per
70
+ * dataSource (mirrors `OutboxModule` per ADR-019 and
71
+ * `TransactionalModule` per ADR-018):
72
+ *
73
+ * ```ts
74
+ * @Module({
75
+ * imports: [
76
+ * TypeOrmModule.forRoot({ type: 'postgres', ... }),
77
+ * TypeOrmModule.forRoot({ type: 'postgres', name: 'billing', ... }),
78
+ *
79
+ * TransactionalModule.forRoot({}), // infra
80
+ * TypeOrmTransactionalModule.forRoot(), // default
81
+ * TypeOrmTransactionalModule.forRoot({ dataSource: 'billing' }),
82
+ * ],
83
+ * })
84
+ * export class AppModule {}
85
+ * ```
86
+ *
87
+ * Patches are applied process-wide on the first `forRoot`/`forRootAsync`
88
+ * call (idempotent on re-entry). DataSource instances are tracked in
89
+ * a `WeakSet`; non-managed DataSources are never touched by the
90
+ * patches — they continue to behave as TypeORM does normally.
91
+ */
92
+ export declare class TypeOrmTransactionalModule {
93
+ /**
94
+ * @internal
95
+ * Counter for `forRootAsync`-only token uniqueness. Mirrors the
96
+ * pattern used in `TransactionalModule.forRootAsync` — every
97
+ * async call gets a unique provider symbol so consecutive calls
98
+ * don't collide.
99
+ */
100
+ private static asyncCounter;
101
+ /**
102
+ * Test-only — drop the managed-DataSources `WeakSet` so cached
103
+ * repositories from a prior test fall through to their original
104
+ * (autocommit) manager. Prototype-level patches are NOT removed;
105
+ * they were installed once-and-stay, by design (see
106
+ * `repository-patches.ts` JSDoc). Per-instance `DataSource`
107
+ * patches survive on those `DataSource` instances — tests that
108
+ * destroy and recreate the `DataSource` between cases (the
109
+ * typical pattern) are unaffected.
110
+ *
111
+ * Re-registering the SAME `DataSource` after a reset is safe:
112
+ * `patchDataSourceInstance` is idempotent via a marker symbol,
113
+ * and `markAsManaged` re-stamps the same name harmlessly.
114
+ *
115
+ * Production code should never call this.
116
+ *
117
+ * @internal
118
+ */
119
+ static resetForTesting(): void;
120
+ /**
121
+ * Synchronous registration. Each call binds one DataSource (by
122
+ * name) to the transactional infrastructure. Patches are
123
+ * activated idempotently on the first call.
124
+ *
125
+ * @example Default DataSource
126
+ * ```ts
127
+ * TypeOrmTransactionalModule.forRoot()
128
+ * ```
129
+ *
130
+ * @example Named DataSource
131
+ * ```ts
132
+ * TypeOrmTransactionalModule.forRoot({ dataSource: 'billing' })
133
+ * ```
134
+ */
135
+ static forRoot(options?: TypeOrmTransactionalOptions): DynamicModule;
136
+ /**
137
+ * Asynchronous registration. Resolves
138
+ * {@link TypeOrmTransactionalOptions} via a NestJS-style async
139
+ * factory before binding the adapter. See
140
+ * {@link TypeOrmTransactionalAsyncOptions} for the per-DS-token
141
+ * limitation.
142
+ *
143
+ * @example
144
+ * ```ts
145
+ * TypeOrmTransactionalModule.forRootAsync({
146
+ * imports: [ConfigModule],
147
+ * inject: [ConfigService],
148
+ * useFactory: (cfg: ConfigService) => ({
149
+ * dataSource: cfg.get('DATA_SOURCE_NAME'),
150
+ * isDefault: true,
151
+ * }),
152
+ * });
153
+ * ```
154
+ */
155
+ static forRootAsync(options: TypeOrmTransactionalAsyncOptions): DynamicModule;
156
+ }
157
+ //# sourceMappingURL=typeorm-transactional.module.d.ts.map
@@ -0,0 +1,289 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var TypeOrmTransactionalModule_1;
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.TypeOrmTransactionalModule = void 0;
17
+ const common_1 = require("@nestjs/common");
18
+ const core_1 = require("@nestjs/core");
19
+ const typeorm_1 = require("@nestjs/typeorm");
20
+ const core_2 = require("@nestjs-transactional/core");
21
+ const typeorm_adapter_1 = require("../adapter/typeorm.adapter");
22
+ const patching_1 = require("../patching");
23
+ // ---------------------------------------------------------------
24
+ // Apply Repository / EntityManager prototype patches at MODULE-LOAD
25
+ // time, NOT at `forRoot` factory time.
26
+ //
27
+ // Why module-load: NestJS resolves providers in dependency order
28
+ // during `compile()`. A `useFactory` provider that calls
29
+ // `dataSource.getRepository(Entity)` (e.g. `@InjectRepository`'s
30
+ // internal factory) runs BEFORE `TypeOrmTransactionalModule.forRoot`'s
31
+ // factory if it has no DI dependency on the latter. A Repository
32
+ // constructed before the patches are installed gets its
33
+ // `this.manager = manager` assignment as an own-property, which
34
+ // permanently shadows the prototype getter — that Repository
35
+ // instance can never dispatch through the active transactional
36
+ // EntityManager.
37
+ //
38
+ // Installing the patches as a side effect of importing this file
39
+ // guarantees they're in place before any DI factory could ever
40
+ // observe an unpatched `Repository.prototype`. Idempotent: a second
41
+ // import (e.g. a stale duplicate copy on disk under pnpm hoist
42
+ // glitches) is a no-op via the install-once flag inside each patch.
43
+ // ---------------------------------------------------------------
44
+ (0, patching_1.applyAllPatches)();
45
+ const ASYNC_OPTIONS_TOKEN = (id) => Symbol(`TYPEORM_TRANSACTIONAL_ASYNC_OPTIONS[${id}]`);
46
+ /**
47
+ * NestJS module that binds a TypeORM {@link DataSource} to the core
48
+ * {@link AdapterRegistry} as a transactional adapter AND activates
49
+ * the transparent transactional patching machinery (Phase 14.20).
50
+ * Once registered:
51
+ *
52
+ * - Every `Repository` reachable via `@InjectRepository`,
53
+ * `dataSource.getRepository(...)`, `entityManager.getRepository(...)`,
54
+ * or `repo.extend(...)` automatically dispatches inside the active
55
+ * `@Transactional()` scope.
56
+ * - `dataSource.query(...)` and `dataSource.createQueryBuilder(...)`
57
+ * pick up the transactional `QueryRunner`.
58
+ * - `@InjectEntityManager() em.getRepository(E).save(...)` works
59
+ * transactionally (the wrapped `EntityManager.prototype.getRepository`
60
+ * stamps the manager reference). Direct
61
+ * `@InjectEntityManager() em.save(E, ...)` is a documented
62
+ * limitation — use the Repository pattern or
63
+ * `getCurrentEntityManager()` as escape hatch.
64
+ *
65
+ * Multi-dataSource deployments call {@link forRoot} once per
66
+ * dataSource (mirrors `OutboxModule` per ADR-019 and
67
+ * `TransactionalModule` per ADR-018):
68
+ *
69
+ * ```ts
70
+ * @Module({
71
+ * imports: [
72
+ * TypeOrmModule.forRoot({ type: 'postgres', ... }),
73
+ * TypeOrmModule.forRoot({ type: 'postgres', name: 'billing', ... }),
74
+ *
75
+ * TransactionalModule.forRoot({}), // infra
76
+ * TypeOrmTransactionalModule.forRoot(), // default
77
+ * TypeOrmTransactionalModule.forRoot({ dataSource: 'billing' }),
78
+ * ],
79
+ * })
80
+ * export class AppModule {}
81
+ * ```
82
+ *
83
+ * Patches are applied process-wide on the first `forRoot`/`forRootAsync`
84
+ * call (idempotent on re-entry). DataSource instances are tracked in
85
+ * a `WeakSet`; non-managed DataSources are never touched by the
86
+ * patches — they continue to behave as TypeORM does normally.
87
+ */
88
+ let TypeOrmTransactionalModule = class TypeOrmTransactionalModule {
89
+ static { TypeOrmTransactionalModule_1 = this; }
90
+ /**
91
+ * @internal
92
+ * Counter for `forRootAsync`-only token uniqueness. Mirrors the
93
+ * pattern used in `TransactionalModule.forRootAsync` — every
94
+ * async call gets a unique provider symbol so consecutive calls
95
+ * don't collide.
96
+ */
97
+ static asyncCounter = 0;
98
+ /**
99
+ * Test-only — drop the managed-DataSources `WeakSet` so cached
100
+ * repositories from a prior test fall through to their original
101
+ * (autocommit) manager. Prototype-level patches are NOT removed;
102
+ * they were installed once-and-stay, by design (see
103
+ * `repository-patches.ts` JSDoc). Per-instance `DataSource`
104
+ * patches survive on those `DataSource` instances — tests that
105
+ * destroy and recreate the `DataSource` between cases (the
106
+ * typical pattern) are unaffected.
107
+ *
108
+ * Re-registering the SAME `DataSource` after a reset is safe:
109
+ * `patchDataSourceInstance` is idempotent via a marker symbol,
110
+ * and `markAsManaged` re-stamps the same name harmlessly.
111
+ *
112
+ * Production code should never call this.
113
+ *
114
+ * @internal
115
+ */
116
+ static resetForTesting() {
117
+ (0, patching_1.resetPatchingForTesting)();
118
+ this.asyncCounter = 0;
119
+ }
120
+ /**
121
+ * Synchronous registration. Each call binds one DataSource (by
122
+ * name) to the transactional infrastructure. Patches are
123
+ * activated idempotently on the first call.
124
+ *
125
+ * @example Default DataSource
126
+ * ```ts
127
+ * TypeOrmTransactionalModule.forRoot()
128
+ * ```
129
+ *
130
+ * @example Named DataSource
131
+ * ```ts
132
+ * TypeOrmTransactionalModule.forRoot({ dataSource: 'billing' })
133
+ * ```
134
+ */
135
+ static forRoot(options = {}) {
136
+ const dataSourceName = options.dataSource ?? 'default';
137
+ const dataSourceToken = (0, typeorm_1.getDataSourceToken)(dataSourceName);
138
+ const adapterToken = (0, core_2.getTransactionalAdapterToken)(dataSourceName);
139
+ const adapterProvider = {
140
+ provide: adapterToken,
141
+ useFactory: (ds, registry) => registerManagedDataSource({
142
+ dataSource: ds,
143
+ dataSourceName,
144
+ isDefault: options.isDefault ?? false,
145
+ registry,
146
+ }),
147
+ inject: [dataSourceToken, core_2.ADAPTER_REGISTRY],
148
+ };
149
+ return {
150
+ module: TypeOrmTransactionalModule_1,
151
+ providers: [adapterProvider],
152
+ exports: [adapterToken],
153
+ };
154
+ }
155
+ /**
156
+ * Asynchronous registration. Resolves
157
+ * {@link TypeOrmTransactionalOptions} via a NestJS-style async
158
+ * factory before binding the adapter. See
159
+ * {@link TypeOrmTransactionalAsyncOptions} for the per-DS-token
160
+ * limitation.
161
+ *
162
+ * @example
163
+ * ```ts
164
+ * TypeOrmTransactionalModule.forRootAsync({
165
+ * imports: [ConfigModule],
166
+ * inject: [ConfigService],
167
+ * useFactory: (cfg: ConfigService) => ({
168
+ * dataSource: cfg.get('DATA_SOURCE_NAME'),
169
+ * isDefault: true,
170
+ * }),
171
+ * });
172
+ * ```
173
+ */
174
+ static forRootAsync(options) {
175
+ const id = this.asyncCounter++;
176
+ const asyncToken = ASYNC_OPTIONS_TOKEN(id);
177
+ const asyncOptionsProvider = {
178
+ provide: asyncToken,
179
+ useFactory: options.useFactory,
180
+ inject: options.inject ? [...options.inject] : undefined,
181
+ };
182
+ // The DataSource token depends on the async-resolved name, so
183
+ // we cannot put `getDataSourceToken(...)` into the registration
184
+ // provider's `inject` array statically. We also cannot resolve
185
+ // it inside a `useFactory` provider via `ModuleRef` — at the
186
+ // time `useFactory` providers run, NestJS has not yet
187
+ // initialised siblings whose DI dependencies do not point at
188
+ // them, so `@nestjs/typeorm`'s DataSource provider may still be
189
+ // a pending Promise. The historical use of `moduleRef.resolve`
190
+ // (or even `moduleRef.get`) cascaded into a hard-to-diagnose
191
+ // `Invalid value used in weak set` followed by
192
+ // `this.postgres.Pool is not a constructor` when paired with
193
+ // `TypeOrmModule.forRootAsync` (Phase 14.8e Convention #22).
194
+ //
195
+ // The robust pattern is `OnModuleInit`: by the time the hook
196
+ // runs, every provider in the module tree has been instantiated
197
+ // (including async DataSource factories from `@nestjs/typeorm`).
198
+ // `moduleRef.get(...)` then returns the real DataSource
199
+ // instance, and `registerManagedDataSource` succeeds.
200
+ const RegistrationCls = createAsyncRegistrationClass(id, asyncToken);
201
+ const providers = [asyncOptionsProvider, RegistrationCls];
202
+ return {
203
+ module: TypeOrmTransactionalModule_1,
204
+ imports: options.imports ?? [],
205
+ providers,
206
+ // Nothing exports `registrationToken` for this path — the
207
+ // service runs side-effect-only via OnModuleInit. Export
208
+ // the registration class so consumers wanting explicit
209
+ // ordering can depend on it being initialised.
210
+ exports: [RegistrationCls],
211
+ };
212
+ }
213
+ };
214
+ exports.TypeOrmTransactionalModule = TypeOrmTransactionalModule;
215
+ exports.TypeOrmTransactionalModule = TypeOrmTransactionalModule = TypeOrmTransactionalModule_1 = __decorate([
216
+ (0, common_1.Module)({})
217
+ ], TypeOrmTransactionalModule);
218
+ /**
219
+ * Generate a unique `OnModuleInit` registration class per
220
+ * `forRootAsync` call. The class injects the async-resolved
221
+ * `TypeOrmTransactionalOptions`, the global `AdapterRegistry`, and
222
+ * `ModuleRef`. In `onModuleInit()` it resolves the actual
223
+ * `DataSource` (every DI provider is ready by then) and calls
224
+ * {@link registerManagedDataSource}.
225
+ *
226
+ * Uniqueness per `id` matters because each `forRootAsync` call
227
+ * registers its OWN provider class — multiple async registrations
228
+ * in the same app must not collide on the same constructor token.
229
+ *
230
+ * Module-level `Reflect` metadata required by NestJS DI is set up
231
+ * via `@Inject(asyncToken)` on the constructor parameter.
232
+ */
233
+ function createAsyncRegistrationClass(id, asyncToken) {
234
+ let TypeOrmTransactionalAsyncRegistration = class TypeOrmTransactionalAsyncRegistration {
235
+ resolved;
236
+ registry;
237
+ moduleRef;
238
+ constructor(resolved, registry, moduleRef) {
239
+ this.resolved = resolved;
240
+ this.registry = registry;
241
+ this.moduleRef = moduleRef;
242
+ }
243
+ onModuleInit() {
244
+ const dataSourceName = this.resolved.dataSource ?? 'default';
245
+ const dataSourceToken = (0, typeorm_1.getDataSourceToken)(dataSourceName);
246
+ const ds = this.moduleRef.get(dataSourceToken, {
247
+ strict: false,
248
+ });
249
+ registerManagedDataSource({
250
+ dataSource: ds,
251
+ dataSourceName,
252
+ isDefault: this.resolved.isDefault ?? false,
253
+ registry: this.registry,
254
+ });
255
+ }
256
+ };
257
+ TypeOrmTransactionalAsyncRegistration = __decorate([
258
+ (0, common_1.Injectable)(),
259
+ __param(0, (0, common_1.Inject)(asyncToken)),
260
+ __param(1, (0, common_1.Inject)(core_2.ADAPTER_REGISTRY)),
261
+ __metadata("design:paramtypes", [Object, core_2.AdapterRegistry,
262
+ core_1.ModuleRef])
263
+ ], TypeOrmTransactionalAsyncRegistration);
264
+ // Distinguish each generated class so a TypeScript reflection /
265
+ // logging consumer can tell them apart. Class identity itself is
266
+ // already unique per call (each `class` expression yields a fresh
267
+ // constructor), but a meaningful `name` helps with stack traces.
268
+ Object.defineProperty(TypeOrmTransactionalAsyncRegistration, 'name', {
269
+ value: `TypeOrmTransactionalAsyncRegistration_${id}`,
270
+ });
271
+ return TypeOrmTransactionalAsyncRegistration;
272
+ }
273
+ /**
274
+ * Common registration path used by both `forRoot`'s factory
275
+ * provider and the `forRootAsync` `OnModuleInit` registration
276
+ * class. Centralises the four-step dance of patch-on-first-use,
277
+ * mark-as-managed, instance-patch, and register-with-AdapterRegistry
278
+ * so the two entry points cannot drift out of step.
279
+ */
280
+ function registerManagedDataSource(args) {
281
+ const { dataSource, dataSourceName, isDefault, registry } = args;
282
+ (0, patching_1.applyAllPatches)();
283
+ (0, patching_1.markAsManaged)(dataSource, dataSourceName);
284
+ (0, patching_1.patchDataSourceInstance)(dataSource);
285
+ const adapter = new typeorm_adapter_1.TypeOrmTransactionAdapter(dataSource, dataSourceName);
286
+ registry.register({ adapterName: 'typeorm', instanceName: dataSourceName, adapter }, isDefault);
287
+ return adapter;
288
+ }
289
+ //# sourceMappingURL=typeorm-transactional.module.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typeorm-transactional.module.js","sourceRoot":"","sources":["../../src/module/typeorm-transactional.module.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import type { DataSource } from 'typeorm';
2
+ /**
3
+ * Apply per-instance patches to a single `DataSource` at the time
4
+ * it's registered as managed. Three patches go on the instance
5
+ * itself (NOT the prototype) because TypeORM sets the affected
6
+ * properties as own-properties in the `DataSource` constructor —
7
+ * patching `DataSource.prototype` would be shadowed by every
8
+ * instance.
9
+ *
10
+ * Patches applied:
11
+ *
12
+ * 1. `dataSource.manager` — replaced with a getter/setter pair.
13
+ * The getter returns the active transactional `EntityManager`
14
+ * when one is registered for this dataSource's name; otherwise
15
+ * falls back to the original (closure-captured) manager. The
16
+ * setter is preserved so any TypeORM-internal reassignment
17
+ * updates the captured original.
18
+ *
19
+ * 2. `dataSource.query(sql, params, queryRunner?)` — wrapped to
20
+ * default the `queryRunner` argument from the active
21
+ * transactional EntityManager when one is available. Without
22
+ * this wrap, raw SQL via `dataSource.query(...)` would always
23
+ * run on the autocommit pool, even inside a `@Transactional()`.
24
+ *
25
+ * 3. `dataSource.createQueryBuilder(entity?, alias?, queryRunner?)`
26
+ * — wrapped likewise, so query builders created via the
27
+ * DataSource (rather than via a Repository) also pick up the
28
+ * transactional QueryRunner.
29
+ *
30
+ * `dataSource.transaction(...)` is NOT patched — it delegates to
31
+ * `manager.transaction(...)` internally (which already uses the
32
+ * patched `manager` getter), and re-routing it through any of our
33
+ * machinery would just be a no-op forward.
34
+ *
35
+ * **Idempotent**: a marker symbol ({@link TYPEORM_DATA_SOURCE_PATCHED})
36
+ * is stamped on each patched DataSource so that double registration
37
+ * (e.g. test reset followed by re-registration of the same
38
+ * DataSource) does not stack getter/setter pairs. Calling this
39
+ * function on an already-patched DataSource is a no-op.
40
+ *
41
+ * Note: the patches are applied to a specific `DataSource` instance
42
+ * and survive on that instance until garbage collection. There is
43
+ * no per-instance revert API; tests that need a clean slate
44
+ * destroy the DataSource and create a fresh one (the standard
45
+ * pattern; integration tests already do this in `afterAll`).
46
+ */
47
+ export declare function patchDataSourceInstance(dataSource: DataSource): void;
48
+ //# sourceMappingURL=data-source-patches.d.ts.map
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ /* eslint-disable @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-assignment */
3
+ // The patching machinery overrides instance-level methods on
4
+ // TypeORM `DataSource` objects (`manager` getter/setter,
5
+ // `query`, `createQueryBuilder`) via runtime property descriptors.
6
+ // The inputs and outputs are intentionally typed as `any` because
7
+ // TypeORM's generic signatures don't survive the wrap; the runtime
8
+ // contract is documented in JSDoc above each patch. File-level
9
+ // disable keeps the patch code readable.
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.patchDataSourceInstance = patchDataSourceInstance;
12
+ const managed_registry_1 = require("./managed-registry");
13
+ const symbols_1 = require("./symbols");
14
+ /**
15
+ * Apply per-instance patches to a single `DataSource` at the time
16
+ * it's registered as managed. Three patches go on the instance
17
+ * itself (NOT the prototype) because TypeORM sets the affected
18
+ * properties as own-properties in the `DataSource` constructor —
19
+ * patching `DataSource.prototype` would be shadowed by every
20
+ * instance.
21
+ *
22
+ * Patches applied:
23
+ *
24
+ * 1. `dataSource.manager` — replaced with a getter/setter pair.
25
+ * The getter returns the active transactional `EntityManager`
26
+ * when one is registered for this dataSource's name; otherwise
27
+ * falls back to the original (closure-captured) manager. The
28
+ * setter is preserved so any TypeORM-internal reassignment
29
+ * updates the captured original.
30
+ *
31
+ * 2. `dataSource.query(sql, params, queryRunner?)` — wrapped to
32
+ * default the `queryRunner` argument from the active
33
+ * transactional EntityManager when one is available. Without
34
+ * this wrap, raw SQL via `dataSource.query(...)` would always
35
+ * run on the autocommit pool, even inside a `@Transactional()`.
36
+ *
37
+ * 3. `dataSource.createQueryBuilder(entity?, alias?, queryRunner?)`
38
+ * — wrapped likewise, so query builders created via the
39
+ * DataSource (rather than via a Repository) also pick up the
40
+ * transactional QueryRunner.
41
+ *
42
+ * `dataSource.transaction(...)` is NOT patched — it delegates to
43
+ * `manager.transaction(...)` internally (which already uses the
44
+ * patched `manager` getter), and re-routing it through any of our
45
+ * machinery would just be a no-op forward.
46
+ *
47
+ * **Idempotent**: a marker symbol ({@link TYPEORM_DATA_SOURCE_PATCHED})
48
+ * is stamped on each patched DataSource so that double registration
49
+ * (e.g. test reset followed by re-registration of the same
50
+ * DataSource) does not stack getter/setter pairs. Calling this
51
+ * function on an already-patched DataSource is a no-op.
52
+ *
53
+ * Note: the patches are applied to a specific `DataSource` instance
54
+ * and survive on that instance until garbage collection. There is
55
+ * no per-instance revert API; tests that need a clean slate
56
+ * destroy the DataSource and create a fresh one (the standard
57
+ * pattern; integration tests already do this in `afterAll`).
58
+ */
59
+ function patchDataSourceInstance(dataSource) {
60
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
61
+ if (dataSource[symbols_1.TYPEORM_DATA_SOURCE_PATCHED] === true) {
62
+ return;
63
+ }
64
+ // (1) `manager` — getter/setter on the instance.
65
+ let originalManager = dataSource.manager;
66
+ Object.defineProperty(dataSource, 'manager', {
67
+ configurable: true,
68
+ get() {
69
+ const dsName = (0, managed_registry_1.getManagedDataSourceName)(dataSource);
70
+ if (dsName === undefined) {
71
+ return originalManager;
72
+ }
73
+ const active = (0, managed_registry_1.getActiveEntityManager)(dsName);
74
+ return active ?? originalManager;
75
+ },
76
+ set(manager) {
77
+ originalManager = manager;
78
+ },
79
+ });
80
+ // (2) `query(sql, params, queryRunner?)` — pick up the active QR
81
+ // when none is supplied. The wrapper bypasses the generic type
82
+ // shape of `DataSource.query` via `any` casts; the runtime
83
+ // contract is unchanged (sql first, params second, qr third).
84
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
85
+ const originalQuery = dataSource.query.bind(dataSource);
86
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
87
+ dataSource.query = function patchedQuery(
88
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
89
+ ...args) {
90
+ if (args.length >= 3) {
91
+ // Caller passed a queryRunner explicitly — respect it.
92
+ return originalQuery(...args);
93
+ }
94
+ const activeQueryRunner = pickActiveQueryRunner(this);
95
+ if (activeQueryRunner !== undefined) {
96
+ return originalQuery(args[0], args[1], activeQueryRunner);
97
+ }
98
+ return originalQuery(...args);
99
+ };
100
+ // (3) `createQueryBuilder(entity?, alias?, queryRunner?)` —
101
+ // mirror logic for QB creation.
102
+ const originalCreateQueryBuilder = dataSource.createQueryBuilder.bind(dataSource);
103
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
104
+ dataSource.createQueryBuilder = function patchedCreateQueryBuilder(
105
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
106
+ ...args) {
107
+ const activeQueryRunner = pickActiveQueryRunner(this);
108
+ if (args.length === 0) {
109
+ return activeQueryRunner !== undefined
110
+ ? originalCreateQueryBuilder(activeQueryRunner)
111
+ : originalCreateQueryBuilder();
112
+ }
113
+ if (args.length >= 3) {
114
+ return originalCreateQueryBuilder(...args);
115
+ }
116
+ if (activeQueryRunner !== undefined) {
117
+ return originalCreateQueryBuilder(args[0], args[1], activeQueryRunner);
118
+ }
119
+ return originalCreateQueryBuilder(...args);
120
+ };
121
+ // Stamp marker so re-entry is a no-op.
122
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
123
+ dataSource[symbols_1.TYPEORM_DATA_SOURCE_PATCHED] = true;
124
+ }
125
+ /**
126
+ * Helper — look up the active transactional EntityManager for this
127
+ * DataSource and return its `queryRunner` (or `undefined` if no
128
+ * transaction is active). Centralised so the `query` and
129
+ * `createQueryBuilder` patches share one resolution rule.
130
+ */
131
+ function pickActiveQueryRunner(ds) {
132
+ const dsName = (0, managed_registry_1.getManagedDataSourceName)(ds);
133
+ if (dsName === undefined) {
134
+ return undefined;
135
+ }
136
+ const active = (0, managed_registry_1.getActiveEntityManager)(dsName);
137
+ return active?.queryRunner;
138
+ }
139
+ //# sourceMappingURL=data-source-patches.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-source-patches.js","sourceRoot":"","sources":["../../src/patching/data-source-patches.ts"],"names":[],"mappings":"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"}