@globalart/nestjs-unit-of-work 1.0.1

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.
package/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # @globalart/nestjs-unit-of-work
2
+
3
+ A NestJS module for working with Unit of Work pattern. Provides a convenient API for creating and managing unit of work.
4
+
5
+ ## Documentation
6
+
7
+ For complete documentation, examples, and API reference, please visit the [official documentation](https://globalart.js.org/packages/nestjs-unit-of-work).
8
+
9
+ ## License
10
+
11
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,174 @@
1
+ let _nestjs_common = require("@nestjs/common");
2
+ let typeorm = require("typeorm");
3
+ let async_hooks = require("async_hooks");
4
+ let _nestjs_core = require("@nestjs/core");
5
+ let rxjs = require("rxjs");
6
+
7
+ //#region src/enums/uow.enums.ts
8
+ let IsolationLevel = /* @__PURE__ */ function(IsolationLevel) {
9
+ IsolationLevel["READ_UNCOMMITTED"] = "READ UNCOMMITTED";
10
+ IsolationLevel["READ_COMMITTED"] = "READ COMMITTED";
11
+ IsolationLevel["REPEATABLE_READ"] = "REPEATABLE READ";
12
+ IsolationLevel["SERIALIZABLE"] = "SERIALIZABLE";
13
+ return IsolationLevel;
14
+ }({});
15
+
16
+ //#endregion
17
+ //#region src/core/uow-typeorm.service.ts
18
+ var TypeOrmUnitOfWork = class {
19
+ queryRunner;
20
+ transactionManager;
21
+ constructor(dataSource) {
22
+ this.dataSource = dataSource;
23
+ }
24
+ async begin(isolationLevel = IsolationLevel.READ_COMMITTED) {
25
+ this.queryRunner = this.dataSource.createQueryRunner();
26
+ await this.queryRunner.connect();
27
+ await this.queryRunner.startTransaction(isolationLevel);
28
+ this.transactionManager = this.queryRunner.manager;
29
+ }
30
+ async commit() {
31
+ if (!this.queryRunner) throw new Error("Unit of work is not started");
32
+ await this.queryRunner.commitTransaction();
33
+ await this.queryRunner.release();
34
+ }
35
+ async rollback() {
36
+ if (!this.queryRunner) return;
37
+ if (this.queryRunner.isTransactionActive) await this.queryRunner.rollbackTransaction();
38
+ if (!this.queryRunner.isReleased) await this.queryRunner.release();
39
+ }
40
+ conn() {
41
+ if (!this.transactionManager) throw new Error("Unit of work is not started or has been released");
42
+ return this.transactionManager;
43
+ }
44
+ get isActive() {
45
+ return !!this.queryRunner?.isTransactionActive;
46
+ }
47
+ };
48
+
49
+ //#endregion
50
+ //#region \0@oxc-project+runtime@0.110.0/helpers/decorate.js
51
+ function __decorate(decorators, target, key, desc) {
52
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
53
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
54
+ 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;
55
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
56
+ }
57
+
58
+ //#endregion
59
+ //#region src/core/uow.context.ts
60
+ let UnitOfWorkContext = class UnitOfWorkContext {
61
+ storage = new async_hooks.AsyncLocalStorage();
62
+ run(uow, callback) {
63
+ return this.storage.run(uow, callback);
64
+ }
65
+ get() {
66
+ return this.storage.getStore();
67
+ }
68
+ };
69
+ UnitOfWorkContext = __decorate([(0, _nestjs_common.Injectable)()], UnitOfWorkContext);
70
+
71
+ //#endregion
72
+ //#region \0@oxc-project+runtime@0.110.0/helpers/decorateMetadata.js
73
+ function __decorateMetadata(k, v) {
74
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
75
+ }
76
+
77
+ //#endregion
78
+ //#region src/core/uow.service.ts
79
+ var _ref$1, _ref2$1;
80
+ let UnitOfWorkManager = class UnitOfWorkManager {
81
+ constructor(dataSource, context) {
82
+ this.dataSource = dataSource;
83
+ this.context = context;
84
+ }
85
+ create() {
86
+ return new TypeOrmUnitOfWork(this.dataSource);
87
+ }
88
+ getEntityManager() {
89
+ const uow = this.context.get();
90
+ if (uow && uow.isActive) return uow.conn();
91
+ return this.dataSource.manager;
92
+ }
93
+ async runInTransaction(fn, isolationLevel = IsolationLevel.READ_COMMITTED) {
94
+ const uow = this.create();
95
+ return this.context.run(uow, async () => {
96
+ try {
97
+ await uow.begin(isolationLevel);
98
+ const result = await fn(uow);
99
+ await uow.commit();
100
+ return result;
101
+ } catch (error) {
102
+ await uow.rollback();
103
+ throw error;
104
+ }
105
+ });
106
+ }
107
+ };
108
+ UnitOfWorkManager = __decorate([(0, _nestjs_common.Injectable)(), __decorateMetadata("design:paramtypes", [typeof (_ref$1 = typeof typeorm.DataSource !== "undefined" && typeorm.DataSource) === "function" ? _ref$1 : Object, typeof (_ref2$1 = typeof UnitOfWorkContext !== "undefined" && UnitOfWorkContext) === "function" ? _ref2$1 : Object])], UnitOfWorkManager);
109
+
110
+ //#endregion
111
+ //#region src/decorators/uow.decorator.ts
112
+ const UOW_METADATA_KEY = "UOW_METADATA_KEY";
113
+ const UOW = (options) => (0, _nestjs_common.applyDecorators)((0, _nestjs_common.SetMetadata)(UOW_METADATA_KEY, options), (0, _nestjs_common.UseInterceptors)(UnitOfWorkInterceptor));
114
+
115
+ //#endregion
116
+ //#region src/interceptors/uow.interceptor.ts
117
+ var _ref, _ref2;
118
+ let UnitOfWorkInterceptor = class UnitOfWorkInterceptor {
119
+ constructor(reflector, uowManager) {
120
+ this.reflector = reflector;
121
+ this.uowManager = uowManager;
122
+ }
123
+ intercept(context, next) {
124
+ const uowMetadata = this.reflector.getAllAndOverride(UOW_METADATA_KEY, [context.getHandler(), context.getClass()]);
125
+ if (!uowMetadata) return next.handle();
126
+ return (0, rxjs.from)(this.uowManager.runInTransaction(async () => {
127
+ return await (0, rxjs.lastValueFrom)(next.handle());
128
+ }, uowMetadata.isolationLevel));
129
+ }
130
+ };
131
+ UnitOfWorkInterceptor = __decorate([(0, _nestjs_common.Injectable)(), __decorateMetadata("design:paramtypes", [typeof (_ref = typeof _nestjs_core.Reflector !== "undefined" && _nestjs_core.Reflector) === "function" ? _ref : Object, typeof (_ref2 = typeof UnitOfWorkManager !== "undefined" && UnitOfWorkManager) === "function" ? _ref2 : Object])], UnitOfWorkInterceptor);
132
+
133
+ //#endregion
134
+ //#region src/core/uow.module.ts
135
+ var _UnitOfWorkModule;
136
+ const providers = [
137
+ UnitOfWorkManager,
138
+ UnitOfWorkContext,
139
+ UnitOfWorkInterceptor
140
+ ];
141
+ let UnitOfWorkModule = _UnitOfWorkModule = class UnitOfWorkModule {
142
+ static forRoot() {
143
+ return {
144
+ global: true,
145
+ module: _UnitOfWorkModule,
146
+ providers,
147
+ exports: [...providers]
148
+ };
149
+ }
150
+ };
151
+ UnitOfWorkModule = _UnitOfWorkModule = __decorate([(0, _nestjs_common.Global)(), (0, _nestjs_common.Module)({})], UnitOfWorkModule);
152
+
153
+ //#endregion
154
+ exports.IsolationLevel = IsolationLevel;
155
+ exports.UOW = UOW;
156
+ Object.defineProperty(exports, 'UnitOfWorkInterceptor', {
157
+ enumerable: true,
158
+ get: function () {
159
+ return UnitOfWorkInterceptor;
160
+ }
161
+ });
162
+ Object.defineProperty(exports, 'UnitOfWorkManager', {
163
+ enumerable: true,
164
+ get: function () {
165
+ return UnitOfWorkManager;
166
+ }
167
+ });
168
+ Object.defineProperty(exports, 'UnitOfWorkModule', {
169
+ enumerable: true,
170
+ get: function () {
171
+ return UnitOfWorkModule;
172
+ }
173
+ });
174
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["AsyncLocalStorage"],"sources":["../src/enums/uow.enums.ts","../src/core/uow-typeorm.service.ts","../src/core/uow.context.ts","../src/core/uow.service.ts","../src/decorators/uow.decorator.ts","../src/interceptors/uow.interceptor.ts","../src/core/uow.module.ts"],"sourcesContent":["export enum IsolationLevel {\n READ_UNCOMMITTED = 'READ UNCOMMITTED',\n READ_COMMITTED = 'READ COMMITTED',\n REPEATABLE_READ = 'REPEATABLE READ',\n SERIALIZABLE = 'SERIALIZABLE',\n}","import { IUnitOfWork } from '@globalart/ddd';\nimport { DataSource, EntityManager, QueryRunner } from 'typeorm';\nimport { IsolationLevel } from '../enums/uow.enums';\n\nexport class TypeOrmUnitOfWork implements IUnitOfWork<EntityManager> {\n private queryRunner?: QueryRunner;\n private transactionManager?: EntityManager;\n\n constructor(private readonly dataSource: DataSource) {}\n\n async begin(isolationLevel = IsolationLevel.READ_COMMITTED): Promise<void> {\n this.queryRunner = this.dataSource.createQueryRunner();\n await this.queryRunner.connect();\n await this.queryRunner.startTransaction(isolationLevel);\n this.transactionManager = this.queryRunner.manager;\n }\n\n async commit(): Promise<void> {\n if (!this.queryRunner) {\n throw new Error('Unit of work is not started');\n }\n await this.queryRunner.commitTransaction();\n await this.queryRunner.release();\n }\n\n async rollback(): Promise<void> {\n if (!this.queryRunner) {\n return;\n }\n if (this.queryRunner.isTransactionActive) {\n await this.queryRunner.rollbackTransaction();\n }\n if (!this.queryRunner.isReleased) {\n await this.queryRunner.release();\n }\n }\n\n conn(): EntityManager {\n if (!this.transactionManager) {\n throw new Error('Unit of work is not started or has been released');\n }\n return this.transactionManager;\n }\n\n get isActive(): boolean {\n return !!this.queryRunner?.isTransactionActive;\n }\n}\n","import { Injectable } from '@nestjs/common';\nimport { AsyncLocalStorage } from 'async_hooks';\nimport { TypeOrmUnitOfWork } from './uow-typeorm.service';\n\n@Injectable()\nexport class UnitOfWorkContext {\n private readonly storage = new AsyncLocalStorage<TypeOrmUnitOfWork>();\n\n run(uow: TypeOrmUnitOfWork, callback: () => any) {\n return this.storage.run(uow, callback);\n }\n\n get(): TypeOrmUnitOfWork | undefined {\n return this.storage.getStore();\n }\n}\n\n","import { Injectable } from '@nestjs/common';\nimport { DataSource, EntityManager } from 'typeorm';\nimport { IsolationLevel } from '../enums/uow.enums';\nimport { TypeOrmUnitOfWork } from './uow-typeorm.service';\nimport { UnitOfWorkContext } from './uow.context';\n\n@Injectable()\nexport class UnitOfWorkManager {\n constructor(\n private readonly dataSource: DataSource,\n private readonly context: UnitOfWorkContext,\n ) {}\n\n create(): TypeOrmUnitOfWork {\n return new TypeOrmUnitOfWork(this.dataSource);\n }\n\n getEntityManager(): EntityManager {\n const uow = this.context.get();\n if (uow && uow.isActive) {\n return uow.conn();\n }\n return this.dataSource.manager;\n }\n\n async runInTransaction<T>(\n fn: (uow: TypeOrmUnitOfWork) => Promise<T>,\n isolationLevel = IsolationLevel.READ_COMMITTED,\n ): Promise<T> {\n const uow = this.create();\n return this.context.run(uow, async () => {\n try {\n await uow.begin(isolationLevel);\n const result = await fn(uow);\n await uow.commit();\n return result;\n } catch (error) {\n await uow.rollback();\n throw error;\n }\n });\n }\n}\n","import { applyDecorators, SetMetadata, UseInterceptors } from '@nestjs/common';\nimport { IsolationLevel } from '../enums/uow.enums';\nimport { UnitOfWorkInterceptor } from '../interceptors/uow.interceptor';\n\nexport const UOW_METADATA_KEY = 'UOW_METADATA_KEY';\n\nexport interface UowOptions {\n isolationLevel?: IsolationLevel;\n}\n\nexport const UOW = (options?: UowOptions) => applyDecorators(\n SetMetadata(UOW_METADATA_KEY, options), \n UseInterceptors(UnitOfWorkInterceptor)\n);\n\n","import {\n CallHandler,\n ExecutionContext,\n Injectable,\n NestInterceptor,\n} from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport { Observable, from, lastValueFrom } from 'rxjs';\nimport { UOW_METADATA_KEY, UowOptions } from '../decorators/uow.decorator';\nimport { UnitOfWorkManager } from '../core/uow.service';\n\n@Injectable()\nexport class UnitOfWorkInterceptor implements NestInterceptor {\n constructor(\n private readonly reflector: Reflector,\n private readonly uowManager: UnitOfWorkManager,\n ) {}\n\n intercept(context: ExecutionContext, next: CallHandler): Observable<any> {\n const uowMetadata = this.reflector.getAllAndOverride<UowOptions>(\n UOW_METADATA_KEY,\n [context.getHandler(), context.getClass()],\n );\n\n if (!uowMetadata) {\n return next.handle();\n }\n\n return from(\n this.uowManager.runInTransaction(async () => {\n return await lastValueFrom(next.handle());\n }, uowMetadata.isolationLevel),\n );\n }\n}\n\n","import { DynamicModule, Module, Global } from \"@nestjs/common\";\nimport { UnitOfWorkManager } from \"./uow.service\";\nimport { UnitOfWorkContext } from \"./uow.context\";\nimport { UnitOfWorkInterceptor } from \"../interceptors/uow.interceptor\";\n\nconst providers = [\n UnitOfWorkManager,\n UnitOfWorkContext,\n UnitOfWorkInterceptor\n]\n\n@Global()\n@Module({})\nexport class UnitOfWorkModule {\n static forRoot(): DynamicModule {\n return {\n global: true,\n module: UnitOfWorkModule,\n providers,\n exports: [...providers],\n }\n }\n}\n"],"mappings":";;;;;;;AAAA,IAAY,0DAAL;AACL;AACA;AACA;AACA;;;;;;ACAF,IAAa,oBAAb,MAAqE;CACnE,AAAQ;CACR,AAAQ;CAER,YAAY,AAAiB,YAAwB;EAAxB;;CAE7B,MAAM,MAAM,iBAAiB,eAAe,gBAA+B;AACzE,OAAK,cAAc,KAAK,WAAW,mBAAmB;AACtD,QAAM,KAAK,YAAY,SAAS;AAChC,QAAM,KAAK,YAAY,iBAAiB,eAAe;AACvD,OAAK,qBAAqB,KAAK,YAAY;;CAG7C,MAAM,SAAwB;AAC5B,MAAI,CAAC,KAAK,YACR,OAAM,IAAI,MAAM,8BAA8B;AAEhD,QAAM,KAAK,YAAY,mBAAmB;AAC1C,QAAM,KAAK,YAAY,SAAS;;CAGlC,MAAM,WAA0B;AAC9B,MAAI,CAAC,KAAK,YACR;AAEF,MAAI,KAAK,YAAY,oBACnB,OAAM,KAAK,YAAY,qBAAqB;AAE9C,MAAI,CAAC,KAAK,YAAY,WACpB,OAAM,KAAK,YAAY,SAAS;;CAIpC,OAAsB;AACpB,MAAI,CAAC,KAAK,mBACR,OAAM,IAAI,MAAM,mDAAmD;AAErE,SAAO,KAAK;;CAGd,IAAI,WAAoB;AACtB,SAAO,CAAC,CAAC,KAAK,aAAa;;;;;;;;;;;;;;;ACxCxB,8BAAM,kBAAkB;CAC7B,AAAiB,UAAU,IAAIA,+BAAsC;CAErE,IAAI,KAAwB,UAAqB;AAC/C,SAAO,KAAK,QAAQ,IAAI,KAAK,SAAS;;CAGxC,MAAqC;AACnC,SAAO,KAAK,QAAQ,UAAU;;;gEATrB;;;;;;;;;;;ACGN,8BAAM,kBAAkB;CAC7B,YACE,AAAiB,YACjB,AAAiB,SACjB;EAFiB;EACA;;CAGnB,SAA4B;AAC1B,SAAO,IAAI,kBAAkB,KAAK,WAAW;;CAG/C,mBAAkC;EAChC,MAAM,MAAM,KAAK,QAAQ,KAAK;AAC9B,MAAI,OAAO,IAAI,SACb,QAAO,IAAI,MAAM;AAEnB,SAAO,KAAK,WAAW;;CAGzB,MAAM,iBACJ,IACA,iBAAiB,eAAe,gBACpB;EACZ,MAAM,MAAM,KAAK,QAAQ;AACzB,SAAO,KAAK,QAAQ,IAAI,KAAK,YAAY;AACvC,OAAI;AACF,UAAM,IAAI,MAAM,eAAe;IAC/B,MAAM,SAAS,MAAM,GAAG,IAAI;AAC5B,UAAM,IAAI,QAAQ;AAClB,WAAO;YACA,OAAO;AACd,UAAM,IAAI,UAAU;AACpB,UAAM;;IAER;;;gEAlCO;;;;ACFb,MAAa,mBAAmB;AAMhC,MAAa,OAAO,gFACN,kBAAkB,QAAQ,sCACtB,sBAAsB,CACvC;;;;;ACDM,kCAAM,sBAAiD;CAC5D,YACE,AAAiB,WACjB,AAAiB,YACjB;EAFiB;EACA;;CAGnB,UAAU,SAA2B,MAAoC;EACvE,MAAM,cAAc,KAAK,UAAU,kBACjC,kBACA,CAAC,QAAQ,YAAY,EAAE,QAAQ,UAAU,CAAC,CAC3C;AAED,MAAI,CAAC,YACH,QAAO,KAAK,QAAQ;AAGtB,wBACE,KAAK,WAAW,iBAAiB,YAAY;AAC3C,UAAO,8BAAoB,KAAK,QAAQ,CAAC;KACxC,YAAY,eAAe,CAC/B;;;oEArBQ;;;;;ACNb,MAAM,YAAY;CAChB;CACA;CACA;CACD;AAIM,iDAAM,iBAAiB;CAC5B,OAAO,UAAyB;AAC9B,SAAO;GACL,QAAQ;GACR;GACA;GACA,SAAS,CAAC,GAAG,UAAU;GACxB;;;+EATI,6BACD,EAAE,CAAC"}
@@ -0,0 +1,65 @@
1
+ import { DataSource, EntityManager } from "typeorm";
2
+ import { IUnitOfWork } from "@globalart/ddd";
3
+ import { CallHandler, DynamicModule, ExecutionContext, NestInterceptor } from "@nestjs/common";
4
+ import { Reflector } from "@nestjs/core";
5
+ import { Observable } from "rxjs";
6
+
7
+ //#region src/enums/uow.enums.d.ts
8
+ declare enum IsolationLevel {
9
+ READ_UNCOMMITTED = "READ UNCOMMITTED",
10
+ READ_COMMITTED = "READ COMMITTED",
11
+ REPEATABLE_READ = "REPEATABLE READ",
12
+ SERIALIZABLE = "SERIALIZABLE"
13
+ }
14
+ //#endregion
15
+ //#region src/core/uow-typeorm.service.d.ts
16
+ declare class TypeOrmUnitOfWork implements IUnitOfWork<EntityManager> {
17
+ private readonly dataSource;
18
+ private queryRunner?;
19
+ private transactionManager?;
20
+ constructor(dataSource: DataSource);
21
+ begin(isolationLevel?: IsolationLevel): Promise<void>;
22
+ commit(): Promise<void>;
23
+ rollback(): Promise<void>;
24
+ conn(): EntityManager;
25
+ get isActive(): boolean;
26
+ }
27
+ //#endregion
28
+ //#region src/core/uow.context.d.ts
29
+ declare class UnitOfWorkContext {
30
+ private readonly storage;
31
+ run(uow: TypeOrmUnitOfWork, callback: () => any): any;
32
+ get(): TypeOrmUnitOfWork | undefined;
33
+ }
34
+ //#endregion
35
+ //#region src/core/uow.service.d.ts
36
+ declare class UnitOfWorkManager {
37
+ private readonly dataSource;
38
+ private readonly context;
39
+ constructor(dataSource: DataSource, context: UnitOfWorkContext);
40
+ create(): TypeOrmUnitOfWork;
41
+ getEntityManager(): EntityManager;
42
+ runInTransaction<T>(fn: (uow: TypeOrmUnitOfWork) => Promise<T>, isolationLevel?: IsolationLevel): Promise<T>;
43
+ }
44
+ //#endregion
45
+ //#region src/core/uow.module.d.ts
46
+ declare class UnitOfWorkModule {
47
+ static forRoot(): DynamicModule;
48
+ }
49
+ //#endregion
50
+ //#region src/decorators/uow.decorator.d.ts
51
+ interface UowOptions {
52
+ isolationLevel?: IsolationLevel;
53
+ }
54
+ declare const UOW: (options?: UowOptions) => <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
55
+ //#endregion
56
+ //#region src/interceptors/uow.interceptor.d.ts
57
+ declare class UnitOfWorkInterceptor implements NestInterceptor {
58
+ private readonly reflector;
59
+ private readonly uowManager;
60
+ constructor(reflector: Reflector, uowManager: UnitOfWorkManager);
61
+ intercept(context: ExecutionContext, next: CallHandler): Observable<any>;
62
+ }
63
+ //#endregion
64
+ export { IsolationLevel, UOW, UnitOfWorkInterceptor, UnitOfWorkManager, UnitOfWorkModule };
65
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1,65 @@
1
+ import { CallHandler, DynamicModule, ExecutionContext, NestInterceptor } from "@nestjs/common";
2
+ import { DataSource, EntityManager } from "typeorm";
3
+ import { Reflector } from "@nestjs/core";
4
+ import { Observable } from "rxjs";
5
+ import { IUnitOfWork } from "@globalart/ddd";
6
+
7
+ //#region src/enums/uow.enums.d.ts
8
+ declare enum IsolationLevel {
9
+ READ_UNCOMMITTED = "READ UNCOMMITTED",
10
+ READ_COMMITTED = "READ COMMITTED",
11
+ REPEATABLE_READ = "REPEATABLE READ",
12
+ SERIALIZABLE = "SERIALIZABLE"
13
+ }
14
+ //#endregion
15
+ //#region src/core/uow-typeorm.service.d.ts
16
+ declare class TypeOrmUnitOfWork implements IUnitOfWork<EntityManager> {
17
+ private readonly dataSource;
18
+ private queryRunner?;
19
+ private transactionManager?;
20
+ constructor(dataSource: DataSource);
21
+ begin(isolationLevel?: IsolationLevel): Promise<void>;
22
+ commit(): Promise<void>;
23
+ rollback(): Promise<void>;
24
+ conn(): EntityManager;
25
+ get isActive(): boolean;
26
+ }
27
+ //#endregion
28
+ //#region src/core/uow.context.d.ts
29
+ declare class UnitOfWorkContext {
30
+ private readonly storage;
31
+ run(uow: TypeOrmUnitOfWork, callback: () => any): any;
32
+ get(): TypeOrmUnitOfWork | undefined;
33
+ }
34
+ //#endregion
35
+ //#region src/core/uow.service.d.ts
36
+ declare class UnitOfWorkManager {
37
+ private readonly dataSource;
38
+ private readonly context;
39
+ constructor(dataSource: DataSource, context: UnitOfWorkContext);
40
+ create(): TypeOrmUnitOfWork;
41
+ getEntityManager(): EntityManager;
42
+ runInTransaction<T>(fn: (uow: TypeOrmUnitOfWork) => Promise<T>, isolationLevel?: IsolationLevel): Promise<T>;
43
+ }
44
+ //#endregion
45
+ //#region src/core/uow.module.d.ts
46
+ declare class UnitOfWorkModule {
47
+ static forRoot(): DynamicModule;
48
+ }
49
+ //#endregion
50
+ //#region src/decorators/uow.decorator.d.ts
51
+ interface UowOptions {
52
+ isolationLevel?: IsolationLevel;
53
+ }
54
+ declare const UOW: (options?: UowOptions) => <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
55
+ //#endregion
56
+ //#region src/interceptors/uow.interceptor.d.ts
57
+ declare class UnitOfWorkInterceptor implements NestInterceptor {
58
+ private readonly reflector;
59
+ private readonly uowManager;
60
+ constructor(reflector: Reflector, uowManager: UnitOfWorkManager);
61
+ intercept(context: ExecutionContext, next: CallHandler): Observable<any>;
62
+ }
63
+ //#endregion
64
+ export { IsolationLevel, UOW, UnitOfWorkInterceptor, UnitOfWorkManager, UnitOfWorkModule };
65
+ //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs ADDED
@@ -0,0 +1,155 @@
1
+ import { Global, Injectable, Module, SetMetadata, UseInterceptors, applyDecorators } from "@nestjs/common";
2
+ import { DataSource } from "typeorm";
3
+ import { AsyncLocalStorage } from "async_hooks";
4
+ import { Reflector } from "@nestjs/core";
5
+ import { from, lastValueFrom } from "rxjs";
6
+
7
+ //#region src/enums/uow.enums.ts
8
+ let IsolationLevel = /* @__PURE__ */ function(IsolationLevel) {
9
+ IsolationLevel["READ_UNCOMMITTED"] = "READ UNCOMMITTED";
10
+ IsolationLevel["READ_COMMITTED"] = "READ COMMITTED";
11
+ IsolationLevel["REPEATABLE_READ"] = "REPEATABLE READ";
12
+ IsolationLevel["SERIALIZABLE"] = "SERIALIZABLE";
13
+ return IsolationLevel;
14
+ }({});
15
+
16
+ //#endregion
17
+ //#region src/core/uow-typeorm.service.ts
18
+ var TypeOrmUnitOfWork = class {
19
+ queryRunner;
20
+ transactionManager;
21
+ constructor(dataSource) {
22
+ this.dataSource = dataSource;
23
+ }
24
+ async begin(isolationLevel = IsolationLevel.READ_COMMITTED) {
25
+ this.queryRunner = this.dataSource.createQueryRunner();
26
+ await this.queryRunner.connect();
27
+ await this.queryRunner.startTransaction(isolationLevel);
28
+ this.transactionManager = this.queryRunner.manager;
29
+ }
30
+ async commit() {
31
+ if (!this.queryRunner) throw new Error("Unit of work is not started");
32
+ await this.queryRunner.commitTransaction();
33
+ await this.queryRunner.release();
34
+ }
35
+ async rollback() {
36
+ if (!this.queryRunner) return;
37
+ if (this.queryRunner.isTransactionActive) await this.queryRunner.rollbackTransaction();
38
+ if (!this.queryRunner.isReleased) await this.queryRunner.release();
39
+ }
40
+ conn() {
41
+ if (!this.transactionManager) throw new Error("Unit of work is not started or has been released");
42
+ return this.transactionManager;
43
+ }
44
+ get isActive() {
45
+ return !!this.queryRunner?.isTransactionActive;
46
+ }
47
+ };
48
+
49
+ //#endregion
50
+ //#region \0@oxc-project+runtime@0.110.0/helpers/decorate.js
51
+ function __decorate(decorators, target, key, desc) {
52
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
53
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
54
+ 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;
55
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
56
+ }
57
+
58
+ //#endregion
59
+ //#region src/core/uow.context.ts
60
+ let UnitOfWorkContext = class UnitOfWorkContext {
61
+ storage = new AsyncLocalStorage();
62
+ run(uow, callback) {
63
+ return this.storage.run(uow, callback);
64
+ }
65
+ get() {
66
+ return this.storage.getStore();
67
+ }
68
+ };
69
+ UnitOfWorkContext = __decorate([Injectable()], UnitOfWorkContext);
70
+
71
+ //#endregion
72
+ //#region \0@oxc-project+runtime@0.110.0/helpers/decorateMetadata.js
73
+ function __decorateMetadata(k, v) {
74
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
75
+ }
76
+
77
+ //#endregion
78
+ //#region src/core/uow.service.ts
79
+ var _ref$1, _ref2$1;
80
+ let UnitOfWorkManager = class UnitOfWorkManager {
81
+ constructor(dataSource, context) {
82
+ this.dataSource = dataSource;
83
+ this.context = context;
84
+ }
85
+ create() {
86
+ return new TypeOrmUnitOfWork(this.dataSource);
87
+ }
88
+ getEntityManager() {
89
+ const uow = this.context.get();
90
+ if (uow && uow.isActive) return uow.conn();
91
+ return this.dataSource.manager;
92
+ }
93
+ async runInTransaction(fn, isolationLevel = IsolationLevel.READ_COMMITTED) {
94
+ const uow = this.create();
95
+ return this.context.run(uow, async () => {
96
+ try {
97
+ await uow.begin(isolationLevel);
98
+ const result = await fn(uow);
99
+ await uow.commit();
100
+ return result;
101
+ } catch (error) {
102
+ await uow.rollback();
103
+ throw error;
104
+ }
105
+ });
106
+ }
107
+ };
108
+ UnitOfWorkManager = __decorate([Injectable(), __decorateMetadata("design:paramtypes", [typeof (_ref$1 = typeof DataSource !== "undefined" && DataSource) === "function" ? _ref$1 : Object, typeof (_ref2$1 = typeof UnitOfWorkContext !== "undefined" && UnitOfWorkContext) === "function" ? _ref2$1 : Object])], UnitOfWorkManager);
109
+
110
+ //#endregion
111
+ //#region src/decorators/uow.decorator.ts
112
+ const UOW_METADATA_KEY = "UOW_METADATA_KEY";
113
+ const UOW = (options) => applyDecorators(SetMetadata(UOW_METADATA_KEY, options), UseInterceptors(UnitOfWorkInterceptor));
114
+
115
+ //#endregion
116
+ //#region src/interceptors/uow.interceptor.ts
117
+ var _ref, _ref2;
118
+ let UnitOfWorkInterceptor = class UnitOfWorkInterceptor {
119
+ constructor(reflector, uowManager) {
120
+ this.reflector = reflector;
121
+ this.uowManager = uowManager;
122
+ }
123
+ intercept(context, next) {
124
+ const uowMetadata = this.reflector.getAllAndOverride(UOW_METADATA_KEY, [context.getHandler(), context.getClass()]);
125
+ if (!uowMetadata) return next.handle();
126
+ return from(this.uowManager.runInTransaction(async () => {
127
+ return await lastValueFrom(next.handle());
128
+ }, uowMetadata.isolationLevel));
129
+ }
130
+ };
131
+ UnitOfWorkInterceptor = __decorate([Injectable(), __decorateMetadata("design:paramtypes", [typeof (_ref = typeof Reflector !== "undefined" && Reflector) === "function" ? _ref : Object, typeof (_ref2 = typeof UnitOfWorkManager !== "undefined" && UnitOfWorkManager) === "function" ? _ref2 : Object])], UnitOfWorkInterceptor);
132
+
133
+ //#endregion
134
+ //#region src/core/uow.module.ts
135
+ var _UnitOfWorkModule;
136
+ const providers = [
137
+ UnitOfWorkManager,
138
+ UnitOfWorkContext,
139
+ UnitOfWorkInterceptor
140
+ ];
141
+ let UnitOfWorkModule = _UnitOfWorkModule = class UnitOfWorkModule {
142
+ static forRoot() {
143
+ return {
144
+ global: true,
145
+ module: _UnitOfWorkModule,
146
+ providers,
147
+ exports: [...providers]
148
+ };
149
+ }
150
+ };
151
+ UnitOfWorkModule = _UnitOfWorkModule = __decorate([Global(), Module({})], UnitOfWorkModule);
152
+
153
+ //#endregion
154
+ export { IsolationLevel, UOW, UnitOfWorkInterceptor, UnitOfWorkManager, UnitOfWorkModule };
155
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/enums/uow.enums.ts","../src/core/uow-typeorm.service.ts","../src/core/uow.context.ts","../src/core/uow.service.ts","../src/decorators/uow.decorator.ts","../src/interceptors/uow.interceptor.ts","../src/core/uow.module.ts"],"sourcesContent":["export enum IsolationLevel {\n READ_UNCOMMITTED = 'READ UNCOMMITTED',\n READ_COMMITTED = 'READ COMMITTED',\n REPEATABLE_READ = 'REPEATABLE READ',\n SERIALIZABLE = 'SERIALIZABLE',\n}","import { IUnitOfWork } from '@globalart/ddd';\nimport { DataSource, EntityManager, QueryRunner } from 'typeorm';\nimport { IsolationLevel } from '../enums/uow.enums';\n\nexport class TypeOrmUnitOfWork implements IUnitOfWork<EntityManager> {\n private queryRunner?: QueryRunner;\n private transactionManager?: EntityManager;\n\n constructor(private readonly dataSource: DataSource) {}\n\n async begin(isolationLevel = IsolationLevel.READ_COMMITTED): Promise<void> {\n this.queryRunner = this.dataSource.createQueryRunner();\n await this.queryRunner.connect();\n await this.queryRunner.startTransaction(isolationLevel);\n this.transactionManager = this.queryRunner.manager;\n }\n\n async commit(): Promise<void> {\n if (!this.queryRunner) {\n throw new Error('Unit of work is not started');\n }\n await this.queryRunner.commitTransaction();\n await this.queryRunner.release();\n }\n\n async rollback(): Promise<void> {\n if (!this.queryRunner) {\n return;\n }\n if (this.queryRunner.isTransactionActive) {\n await this.queryRunner.rollbackTransaction();\n }\n if (!this.queryRunner.isReleased) {\n await this.queryRunner.release();\n }\n }\n\n conn(): EntityManager {\n if (!this.transactionManager) {\n throw new Error('Unit of work is not started or has been released');\n }\n return this.transactionManager;\n }\n\n get isActive(): boolean {\n return !!this.queryRunner?.isTransactionActive;\n }\n}\n","import { Injectable } from '@nestjs/common';\nimport { AsyncLocalStorage } from 'async_hooks';\nimport { TypeOrmUnitOfWork } from './uow-typeorm.service';\n\n@Injectable()\nexport class UnitOfWorkContext {\n private readonly storage = new AsyncLocalStorage<TypeOrmUnitOfWork>();\n\n run(uow: TypeOrmUnitOfWork, callback: () => any) {\n return this.storage.run(uow, callback);\n }\n\n get(): TypeOrmUnitOfWork | undefined {\n return this.storage.getStore();\n }\n}\n\n","import { Injectable } from '@nestjs/common';\nimport { DataSource, EntityManager } from 'typeorm';\nimport { IsolationLevel } from '../enums/uow.enums';\nimport { TypeOrmUnitOfWork } from './uow-typeorm.service';\nimport { UnitOfWorkContext } from './uow.context';\n\n@Injectable()\nexport class UnitOfWorkManager {\n constructor(\n private readonly dataSource: DataSource,\n private readonly context: UnitOfWorkContext,\n ) {}\n\n create(): TypeOrmUnitOfWork {\n return new TypeOrmUnitOfWork(this.dataSource);\n }\n\n getEntityManager(): EntityManager {\n const uow = this.context.get();\n if (uow && uow.isActive) {\n return uow.conn();\n }\n return this.dataSource.manager;\n }\n\n async runInTransaction<T>(\n fn: (uow: TypeOrmUnitOfWork) => Promise<T>,\n isolationLevel = IsolationLevel.READ_COMMITTED,\n ): Promise<T> {\n const uow = this.create();\n return this.context.run(uow, async () => {\n try {\n await uow.begin(isolationLevel);\n const result = await fn(uow);\n await uow.commit();\n return result;\n } catch (error) {\n await uow.rollback();\n throw error;\n }\n });\n }\n}\n","import { applyDecorators, SetMetadata, UseInterceptors } from '@nestjs/common';\nimport { IsolationLevel } from '../enums/uow.enums';\nimport { UnitOfWorkInterceptor } from '../interceptors/uow.interceptor';\n\nexport const UOW_METADATA_KEY = 'UOW_METADATA_KEY';\n\nexport interface UowOptions {\n isolationLevel?: IsolationLevel;\n}\n\nexport const UOW = (options?: UowOptions) => applyDecorators(\n SetMetadata(UOW_METADATA_KEY, options), \n UseInterceptors(UnitOfWorkInterceptor)\n);\n\n","import {\n CallHandler,\n ExecutionContext,\n Injectable,\n NestInterceptor,\n} from '@nestjs/common';\nimport { Reflector } from '@nestjs/core';\nimport { Observable, from, lastValueFrom } from 'rxjs';\nimport { UOW_METADATA_KEY, UowOptions } from '../decorators/uow.decorator';\nimport { UnitOfWorkManager } from '../core/uow.service';\n\n@Injectable()\nexport class UnitOfWorkInterceptor implements NestInterceptor {\n constructor(\n private readonly reflector: Reflector,\n private readonly uowManager: UnitOfWorkManager,\n ) {}\n\n intercept(context: ExecutionContext, next: CallHandler): Observable<any> {\n const uowMetadata = this.reflector.getAllAndOverride<UowOptions>(\n UOW_METADATA_KEY,\n [context.getHandler(), context.getClass()],\n );\n\n if (!uowMetadata) {\n return next.handle();\n }\n\n return from(\n this.uowManager.runInTransaction(async () => {\n return await lastValueFrom(next.handle());\n }, uowMetadata.isolationLevel),\n );\n }\n}\n\n","import { DynamicModule, Module, Global } from \"@nestjs/common\";\nimport { UnitOfWorkManager } from \"./uow.service\";\nimport { UnitOfWorkContext } from \"./uow.context\";\nimport { UnitOfWorkInterceptor } from \"../interceptors/uow.interceptor\";\n\nconst providers = [\n UnitOfWorkManager,\n UnitOfWorkContext,\n UnitOfWorkInterceptor\n]\n\n@Global()\n@Module({})\nexport class UnitOfWorkModule {\n static forRoot(): DynamicModule {\n return {\n global: true,\n module: UnitOfWorkModule,\n providers,\n exports: [...providers],\n }\n }\n}\n"],"mappings":";;;;;;;AAAA,IAAY,0DAAL;AACL;AACA;AACA;AACA;;;;;;ACAF,IAAa,oBAAb,MAAqE;CACnE,AAAQ;CACR,AAAQ;CAER,YAAY,AAAiB,YAAwB;EAAxB;;CAE7B,MAAM,MAAM,iBAAiB,eAAe,gBAA+B;AACzE,OAAK,cAAc,KAAK,WAAW,mBAAmB;AACtD,QAAM,KAAK,YAAY,SAAS;AAChC,QAAM,KAAK,YAAY,iBAAiB,eAAe;AACvD,OAAK,qBAAqB,KAAK,YAAY;;CAG7C,MAAM,SAAwB;AAC5B,MAAI,CAAC,KAAK,YACR,OAAM,IAAI,MAAM,8BAA8B;AAEhD,QAAM,KAAK,YAAY,mBAAmB;AAC1C,QAAM,KAAK,YAAY,SAAS;;CAGlC,MAAM,WAA0B;AAC9B,MAAI,CAAC,KAAK,YACR;AAEF,MAAI,KAAK,YAAY,oBACnB,OAAM,KAAK,YAAY,qBAAqB;AAE9C,MAAI,CAAC,KAAK,YAAY,WACpB,OAAM,KAAK,YAAY,SAAS;;CAIpC,OAAsB;AACpB,MAAI,CAAC,KAAK,mBACR,OAAM,IAAI,MAAM,mDAAmD;AAErE,SAAO,KAAK;;CAGd,IAAI,WAAoB;AACtB,SAAO,CAAC,CAAC,KAAK,aAAa;;;;;;;;;;;;;;;ACxCxB,8BAAM,kBAAkB;CAC7B,AAAiB,UAAU,IAAI,mBAAsC;CAErE,IAAI,KAAwB,UAAqB;AAC/C,SAAO,KAAK,QAAQ,IAAI,KAAK,SAAS;;CAGxC,MAAqC;AACnC,SAAO,KAAK,QAAQ,UAAU;;;gCATjC,YAAY;;;;;;;;;;;ACGN,8BAAM,kBAAkB;CAC7B,YACE,AAAiB,YACjB,AAAiB,SACjB;EAFiB;EACA;;CAGnB,SAA4B;AAC1B,SAAO,IAAI,kBAAkB,KAAK,WAAW;;CAG/C,mBAAkC;EAChC,MAAM,MAAM,KAAK,QAAQ,KAAK;AAC9B,MAAI,OAAO,IAAI,SACb,QAAO,IAAI,MAAM;AAEnB,SAAO,KAAK,WAAW;;CAGzB,MAAM,iBACJ,IACA,iBAAiB,eAAe,gBACpB;EACZ,MAAM,MAAM,KAAK,QAAQ;AACzB,SAAO,KAAK,QAAQ,IAAI,KAAK,YAAY;AACvC,OAAI;AACF,UAAM,IAAI,MAAM,eAAe;IAC/B,MAAM,SAAS,MAAM,GAAG,IAAI;AAC5B,UAAM,IAAI,QAAQ;AAClB,WAAO;YACA,OAAO;AACd,UAAM,IAAI,UAAU;AACpB,UAAM;;IAER;;;gCAlCL,YAAY;;;;ACFb,MAAa,mBAAmB;AAMhC,MAAa,OAAO,YAAyB,gBAC3C,YAAY,kBAAkB,QAAQ,EACtC,gBAAgB,sBAAsB,CACvC;;;;;ACDM,kCAAM,sBAAiD;CAC5D,YACE,AAAiB,WACjB,AAAiB,YACjB;EAFiB;EACA;;CAGnB,UAAU,SAA2B,MAAoC;EACvE,MAAM,cAAc,KAAK,UAAU,kBACjC,kBACA,CAAC,QAAQ,YAAY,EAAE,QAAQ,UAAU,CAAC,CAC3C;AAED,MAAI,CAAC,YACH,QAAO,KAAK,QAAQ;AAGtB,SAAO,KACL,KAAK,WAAW,iBAAiB,YAAY;AAC3C,UAAO,MAAM,cAAc,KAAK,QAAQ,CAAC;KACxC,YAAY,eAAe,CAC/B;;;oCArBJ,YAAY;;;;;ACNb,MAAM,YAAY;CAChB;CACA;CACA;CACD;AAIM,iDAAM,iBAAiB;CAC5B,OAAO,UAAyB;AAC9B,SAAO;GACL,QAAQ;GACR;GACA;GACA,SAAS,CAAC,GAAG,UAAU;GACxB;;;mDATJ,QAAQ,EACR,OAAO,EAAE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@globalart/nestjs-unit-of-work",
3
+ "description": "Transactional integration for NestJS",
4
+ "version": "1.0.1",
5
+ "type": "module",
6
+ "main": "dist/index.mjs",
7
+ "module": "dist/index.mjs",
8
+ "types": "dist/index.d.mts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.mts",
13
+ "default": "./dist/index.mjs"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "README.md"
24
+ ],
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/GlobalArtInc/ecosystem.git#main",
28
+ "directory": "packages/nestjs-unit-of-work"
29
+ },
30
+ "license": "MIT",
31
+ "author": "GlobalArt, Inc",
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "keywords": [
36
+ "nestjs",
37
+ "unit-of-work"
38
+ ],
39
+ "scripts": {
40
+ "format": "prettier --write \"**/*.ts\"",
41
+ "build": "tsdown",
42
+ "build:watch": "tsdown --watch",
43
+ "prepublishOnly": "npm run build",
44
+ "publish:dev": "npm publish --access public --tag dev",
45
+ "publish:npm": "release-it --config ../../.release-it.json"
46
+ },
47
+ "dependencies": {
48
+ "@globalart/text-utils": "^1.0.5",
49
+ "@nestjs/common": "11.1.12",
50
+ "@nestjs/core": "11.1.12",
51
+ "@nestjs/microservices": "^11.1.12",
52
+ "@nestjs/typeorm": "^11.0.0",
53
+ "@globalart/ddd": "^1.1.8",
54
+ "typeorm": "^0.3.28",
55
+ "rxjs": "^7.8.2"
56
+ },
57
+ "devDependencies": {
58
+ "@types/node": "25.1.0",
59
+ "prettier": "^3.8.1",
60
+ "reflect-metadata": "^0.2.2",
61
+ "release-it": "19.2.4",
62
+ "tsdown": "0.20.1",
63
+ "typescript": "^5.9.3"
64
+ }
65
+ }