@dangao/bun-server 1.0.0 → 1.0.3

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 (200) hide show
  1. package/package.json +4 -2
  2. package/readme.md +163 -2
  3. package/src/auth/controller.ts +148 -0
  4. package/src/auth/decorators.ts +81 -0
  5. package/src/auth/index.ts +12 -0
  6. package/src/auth/jwt.ts +169 -0
  7. package/src/auth/oauth2.ts +244 -0
  8. package/src/auth/types.ts +248 -0
  9. package/src/cache/cache-module.ts +67 -0
  10. package/src/cache/decorators.ts +202 -0
  11. package/src/cache/index.ts +27 -0
  12. package/src/cache/service.ts +151 -0
  13. package/src/cache/types.ts +420 -0
  14. package/src/config/config-module.ts +76 -0
  15. package/src/config/index.ts +8 -0
  16. package/src/config/service.ts +93 -0
  17. package/src/config/types.ts +27 -0
  18. package/src/controller/controller.ts +251 -0
  19. package/src/controller/decorators.ts +84 -0
  20. package/src/controller/index.ts +7 -0
  21. package/src/controller/metadata.ts +27 -0
  22. package/src/controller/param-binder.ts +157 -0
  23. package/src/core/application.ts +233 -0
  24. package/src/core/context.ts +228 -0
  25. package/src/core/index.ts +4 -0
  26. package/src/core/server.ts +128 -0
  27. package/src/core/types.ts +2 -0
  28. package/src/database/connection-manager.ts +239 -0
  29. package/src/database/connection-pool.ts +322 -0
  30. package/src/database/database-extension.ts +62 -0
  31. package/src/database/database-module.ts +115 -0
  32. package/src/database/health-indicator.ts +51 -0
  33. package/src/database/index.ts +47 -0
  34. package/src/database/orm/decorators.ts +155 -0
  35. package/src/database/orm/drizzle-repository.ts +39 -0
  36. package/src/database/orm/index.ts +23 -0
  37. package/src/database/orm/repository-decorator.ts +39 -0
  38. package/src/database/orm/repository.ts +103 -0
  39. package/src/database/orm/service.ts +49 -0
  40. package/src/database/orm/transaction-decorator.ts +45 -0
  41. package/src/database/orm/transaction-interceptor.ts +243 -0
  42. package/src/database/orm/transaction-manager.ts +276 -0
  43. package/src/database/orm/transaction-types.ts +140 -0
  44. package/src/database/orm/types.ts +99 -0
  45. package/src/database/service.ts +221 -0
  46. package/src/database/types.ts +171 -0
  47. package/src/di/container.ts +398 -0
  48. package/src/di/decorators.ts +228 -0
  49. package/src/di/index.ts +4 -0
  50. package/src/di/module-registry.ts +188 -0
  51. package/src/di/module.ts +65 -0
  52. package/src/di/types.ts +67 -0
  53. package/src/error/error-codes.ts +222 -0
  54. package/src/error/filter.ts +43 -0
  55. package/src/error/handler.ts +66 -0
  56. package/src/error/http-exception.ts +115 -0
  57. package/src/error/i18n.ts +217 -0
  58. package/src/error/index.ts +16 -0
  59. package/src/extensions/index.ts +5 -0
  60. package/src/extensions/logger-extension.ts +31 -0
  61. package/src/extensions/logger-module.ts +69 -0
  62. package/src/extensions/types.ts +14 -0
  63. package/src/files/index.ts +5 -0
  64. package/src/files/static-middleware.ts +53 -0
  65. package/src/files/storage.ts +67 -0
  66. package/src/files/types.ts +33 -0
  67. package/src/files/upload-middleware.ts +45 -0
  68. package/src/health/controller.ts +76 -0
  69. package/src/health/health-module.ts +51 -0
  70. package/src/health/index.ts +12 -0
  71. package/src/health/types.ts +28 -0
  72. package/src/index.ts +270 -0
  73. package/src/metrics/collector.ts +209 -0
  74. package/src/metrics/controller.ts +40 -0
  75. package/src/metrics/index.ts +15 -0
  76. package/src/metrics/metrics-module.ts +58 -0
  77. package/src/metrics/middleware.ts +46 -0
  78. package/src/metrics/prometheus.ts +79 -0
  79. package/src/metrics/types.ts +103 -0
  80. package/src/middleware/builtin/cors.ts +60 -0
  81. package/src/middleware/builtin/error-handler.ts +90 -0
  82. package/src/middleware/builtin/file-upload.ts +42 -0
  83. package/src/middleware/builtin/index.ts +14 -0
  84. package/src/middleware/builtin/logger.ts +91 -0
  85. package/src/middleware/builtin/rate-limit.ts +252 -0
  86. package/src/middleware/builtin/static-file.ts +88 -0
  87. package/src/middleware/decorators.ts +91 -0
  88. package/src/middleware/index.ts +11 -0
  89. package/src/middleware/middleware.ts +13 -0
  90. package/src/middleware/pipeline.ts +93 -0
  91. package/src/queue/decorators.ts +110 -0
  92. package/src/queue/index.ts +26 -0
  93. package/src/queue/queue-module.ts +64 -0
  94. package/src/queue/service.ts +302 -0
  95. package/src/queue/types.ts +341 -0
  96. package/src/request/body-parser.ts +133 -0
  97. package/src/request/file-handler.ts +46 -0
  98. package/src/request/index.ts +5 -0
  99. package/src/request/request.ts +107 -0
  100. package/src/request/response.ts +150 -0
  101. package/src/router/decorators.ts +122 -0
  102. package/src/router/index.ts +6 -0
  103. package/src/router/registry.ts +98 -0
  104. package/src/router/route.ts +140 -0
  105. package/src/router/router.ts +241 -0
  106. package/src/router/types.ts +27 -0
  107. package/src/security/access-decision-manager.ts +34 -0
  108. package/src/security/authentication-manager.ts +47 -0
  109. package/src/security/context.ts +92 -0
  110. package/src/security/filter.ts +162 -0
  111. package/src/security/index.ts +8 -0
  112. package/src/security/providers/index.ts +3 -0
  113. package/src/security/providers/jwt-provider.ts +60 -0
  114. package/src/security/providers/oauth2-provider.ts +70 -0
  115. package/src/security/security-module.ts +145 -0
  116. package/src/security/types.ts +165 -0
  117. package/src/session/decorators.ts +45 -0
  118. package/src/session/index.ts +19 -0
  119. package/src/session/middleware.ts +143 -0
  120. package/src/session/service.ts +218 -0
  121. package/src/session/session-module.ts +69 -0
  122. package/src/session/types.ts +373 -0
  123. package/src/swagger/decorators.ts +133 -0
  124. package/src/swagger/generator.ts +234 -0
  125. package/src/swagger/index.ts +7 -0
  126. package/src/swagger/swagger-extension.ts +41 -0
  127. package/src/swagger/swagger-module.ts +83 -0
  128. package/src/swagger/types.ts +188 -0
  129. package/src/swagger/ui.ts +98 -0
  130. package/src/testing/harness.ts +96 -0
  131. package/src/validation/decorators.ts +95 -0
  132. package/src/validation/errors.ts +28 -0
  133. package/src/validation/index.ts +14 -0
  134. package/src/validation/types.ts +35 -0
  135. package/src/validation/validator.ts +63 -0
  136. package/src/websocket/decorators.ts +51 -0
  137. package/src/websocket/index.ts +12 -0
  138. package/src/websocket/registry.ts +133 -0
  139. package/tests/cache/cache-module.test.ts +212 -0
  140. package/tests/config/config-module.test.ts +151 -0
  141. package/tests/controller/controller.test.ts +189 -0
  142. package/tests/core/application.test.ts +57 -0
  143. package/tests/core/context-body.test.ts +44 -0
  144. package/tests/core/context.test.ts +86 -0
  145. package/tests/core/edge-cases.test.ts +432 -0
  146. package/tests/database/database-module.test.ts +385 -0
  147. package/tests/database/orm.test.ts +164 -0
  148. package/tests/database/postgres-mysql-integration.test.ts +395 -0
  149. package/tests/database/transaction.test.ts +238 -0
  150. package/tests/di/container.test.ts +264 -0
  151. package/tests/di/module.test.ts +128 -0
  152. package/tests/error/error-codes.test.ts +121 -0
  153. package/tests/error/error-handler.test.ts +68 -0
  154. package/tests/error/error-handling.test.ts +254 -0
  155. package/tests/error/http-exception.test.ts +37 -0
  156. package/tests/error/i18n-integration.test.ts +175 -0
  157. package/tests/extensions/logger-extension.test.ts +40 -0
  158. package/tests/files/static-middleware.test.ts +67 -0
  159. package/tests/files/upload-middleware.test.ts +43 -0
  160. package/tests/health/health-module.test.ts +116 -0
  161. package/tests/integration/application-router.test.ts +85 -0
  162. package/tests/integration/body-parsing.test.ts +88 -0
  163. package/tests/integration/cache-e2e.test.ts +114 -0
  164. package/tests/integration/oauth2-e2e.test.ts +615 -0
  165. package/tests/integration/session-e2e.test.ts +207 -0
  166. package/tests/metrics/metrics-module.test.ts +178 -0
  167. package/tests/middleware/builtin.test.ts +206 -0
  168. package/tests/middleware/file-upload.test.ts +41 -0
  169. package/tests/middleware/middleware.test.ts +120 -0
  170. package/tests/middleware/pipeline.test.ts +72 -0
  171. package/tests/middleware/rate-limit.test.ts +314 -0
  172. package/tests/middleware/static-file.test.ts +62 -0
  173. package/tests/perf/harness.test.ts +48 -0
  174. package/tests/perf/optimization.test.ts +183 -0
  175. package/tests/perf/regression.test.ts +120 -0
  176. package/tests/queue/queue-module.test.ts +217 -0
  177. package/tests/request/body-parser.test.ts +96 -0
  178. package/tests/request/response.test.ts +99 -0
  179. package/tests/router/decorators.test.ts +48 -0
  180. package/tests/router/registry.test.ts +51 -0
  181. package/tests/router/route.test.ts +71 -0
  182. package/tests/router/router-normalization.test.ts +106 -0
  183. package/tests/router/router.test.ts +133 -0
  184. package/tests/security/access-decision-manager.test.ts +84 -0
  185. package/tests/security/authentication-manager.test.ts +81 -0
  186. package/tests/security/context.test.ts +302 -0
  187. package/tests/security/filter.test.ts +225 -0
  188. package/tests/security/jwt-provider.test.ts +106 -0
  189. package/tests/security/oauth2-provider.test.ts +269 -0
  190. package/tests/security/security-module.test.ts +143 -0
  191. package/tests/session/session-module.test.ts +307 -0
  192. package/tests/stress/di-stress.test.ts +30 -0
  193. package/tests/swagger/decorators.test.ts +153 -0
  194. package/tests/swagger/generator.test.ts +202 -0
  195. package/tests/swagger/swagger-extension.test.ts +72 -0
  196. package/tests/swagger/swagger-module.test.ts +79 -0
  197. package/tests/utils/test-port.ts +10 -0
  198. package/tests/validation/controller-validation.test.ts +64 -0
  199. package/tests/validation/validation.test.ts +42 -0
  200. package/tests/websocket/gateway.test.ts +68 -0
@@ -0,0 +1,243 @@
1
+ import { Container } from '../../di/container';
2
+ import { TRANSACTION_SERVICE_TOKEN } from './transaction-types';
3
+ import { TransactionManager } from './transaction-manager';
4
+ import { getTransactionMetadata } from './transaction-decorator';
5
+ import { Propagation, TransactionStatus } from './transaction-types';
6
+
7
+ /**
8
+ * 事务拦截器
9
+ * 在方法调用时检查 @Transactional() 装饰器并执行事务逻辑
10
+ */
11
+ export class TransactionInterceptor {
12
+ /**
13
+ * 执行带事务的方法
14
+ */
15
+ public static async executeWithTransaction<T>(
16
+ target: unknown,
17
+ propertyKey: string | symbol,
18
+ originalMethod: (...args: unknown[]) => T | Promise<T>,
19
+ args: unknown[],
20
+ container: Container,
21
+ ): Promise<T> {
22
+ const transactionMetadata = getTransactionMetadata(target, propertyKey);
23
+
24
+ // 如果没有事务元数据,直接执行原方法
25
+ if (!transactionMetadata) {
26
+ return await Promise.resolve(originalMethod.apply(target, args));
27
+ }
28
+
29
+ // 获取事务管理器
30
+ let transactionManager: TransactionManager;
31
+ try {
32
+ transactionManager = container.resolve<TransactionManager>(
33
+ TRANSACTION_SERVICE_TOKEN,
34
+ );
35
+ } catch (error) {
36
+ // 如果没有注册事务管理器,直接执行原方法
37
+ console.warn('TransactionManager not found, executing without transaction');
38
+ return await Promise.resolve(originalMethod.apply(target, args));
39
+ }
40
+
41
+ const propagation = transactionMetadata.propagation ?? Propagation.REQUIRED;
42
+ const currentTransaction = transactionManager.getCurrentTransaction();
43
+
44
+ // 根据传播行为决定事务策略
45
+ switch (propagation) {
46
+ case Propagation.REQUIRED:
47
+ if (currentTransaction) {
48
+ // 加入现有事务
49
+ return await this.executeInExistingTransaction(
50
+ originalMethod,
51
+ target,
52
+ args,
53
+ currentTransaction.id,
54
+ transactionManager,
55
+ );
56
+ } else {
57
+ // 创建新事务
58
+ return await this.executeInNewTransaction(
59
+ originalMethod,
60
+ target,
61
+ args,
62
+ transactionMetadata,
63
+ transactionManager,
64
+ );
65
+ }
66
+
67
+ case Propagation.REQUIRES_NEW:
68
+ // 总是创建新事务
69
+ return await this.executeInNewTransaction(
70
+ originalMethod,
71
+ target,
72
+ args,
73
+ transactionMetadata,
74
+ transactionManager,
75
+ );
76
+
77
+ case Propagation.SUPPORTS:
78
+ if (currentTransaction) {
79
+ // 加入现有事务
80
+ return await this.executeInExistingTransaction(
81
+ originalMethod,
82
+ target,
83
+ args,
84
+ currentTransaction.id,
85
+ transactionManager,
86
+ );
87
+ } else {
88
+ // 非事务执行
89
+ return await Promise.resolve(originalMethod.apply(target, args));
90
+ }
91
+
92
+ case Propagation.NOT_SUPPORTED:
93
+ // 非事务执行
94
+ return await Promise.resolve(originalMethod.apply(target, args));
95
+
96
+ case Propagation.NEVER:
97
+ if (currentTransaction) {
98
+ throw new Error(
99
+ 'Transaction propagation NEVER requires no existing transaction',
100
+ );
101
+ }
102
+ return await Promise.resolve(originalMethod.apply(target, args));
103
+
104
+ case Propagation.NESTED:
105
+ if (currentTransaction) {
106
+ // 创建嵌套事务(保存点)
107
+ return await this.executeInNestedTransaction(
108
+ originalMethod,
109
+ target,
110
+ args,
111
+ currentTransaction.id,
112
+ transactionMetadata,
113
+ transactionManager,
114
+ );
115
+ } else {
116
+ // 创建新事务
117
+ return await this.executeInNewTransaction(
118
+ originalMethod,
119
+ target,
120
+ args,
121
+ transactionMetadata,
122
+ transactionManager,
123
+ );
124
+ }
125
+
126
+ default:
127
+ return await Promise.resolve(originalMethod.apply(target, args));
128
+ }
129
+ }
130
+
131
+ /**
132
+ * 在新事务中执行方法
133
+ */
134
+ private static async executeInNewTransaction<T>(
135
+ method: (...args: unknown[]) => T | Promise<T>,
136
+ target: unknown,
137
+ args: unknown[],
138
+ options: {
139
+ timeout?: number;
140
+ rollbackFor?: Array<new () => Error>;
141
+ noRollbackFor?: Array<new () => Error>;
142
+ },
143
+ transactionManager: TransactionManager,
144
+ ): Promise<T> {
145
+ const context = await transactionManager.beginTransaction({
146
+ timeout: options.timeout,
147
+ });
148
+
149
+ try {
150
+ const result = await Promise.resolve(method.apply(target, args));
151
+ await transactionManager.commitTransaction(context.id);
152
+ return result;
153
+ } catch (error) {
154
+ // 检查是否需要回滚
155
+ if (this.shouldRollback(error, options.rollbackFor, options.noRollbackFor)) {
156
+ await transactionManager.rollbackTransaction(context.id);
157
+ } else {
158
+ await transactionManager.commitTransaction(context.id);
159
+ }
160
+ throw error;
161
+ }
162
+ }
163
+
164
+ /**
165
+ * 在现有事务中执行方法
166
+ */
167
+ private static async executeInExistingTransaction<T>(
168
+ method: (...args: unknown[]) => T | Promise<T>,
169
+ target: unknown,
170
+ args: unknown[],
171
+ transactionId: string,
172
+ transactionManager: TransactionManager,
173
+ ): Promise<T> {
174
+ // 直接执行,不提交或回滚(由外层事务管理)
175
+ return await Promise.resolve(method.apply(target, args));
176
+ }
177
+
178
+ /**
179
+ * 在嵌套事务中执行方法
180
+ */
181
+ private static async executeInNestedTransaction<T>(
182
+ method: (...args: unknown[]) => T | Promise<T>,
183
+ target: unknown,
184
+ args: unknown[],
185
+ parentTransactionId: string,
186
+ options: {
187
+ timeout?: number;
188
+ rollbackFor?: Array<new () => Error>;
189
+ noRollbackFor?: Array<new () => Error>;
190
+ },
191
+ transactionManager: TransactionManager,
192
+ ): Promise<T> {
193
+ const savepointName = await transactionManager.createSavepoint(parentTransactionId);
194
+
195
+ try {
196
+ const result = await Promise.resolve(method.apply(target, args));
197
+ // 嵌套事务成功,不执行任何操作(保存点保留)
198
+ return result;
199
+ } catch (error) {
200
+ // 检查是否需要回滚到保存点
201
+ if (this.shouldRollback(error, options.rollbackFor, options.noRollbackFor)) {
202
+ await transactionManager.rollbackToSavepoint(parentTransactionId, savepointName);
203
+ }
204
+ throw error;
205
+ }
206
+ }
207
+
208
+ /**
209
+ * 判断是否应该回滚
210
+ */
211
+ private static shouldRollback(
212
+ error: unknown,
213
+ rollbackFor?: Array<new () => Error>,
214
+ noRollbackFor?: Array<new () => Error>,
215
+ ): boolean {
216
+ if (!error) {
217
+ return false;
218
+ }
219
+
220
+ // 如果指定了 noRollbackFor,且错误匹配,则不回滚
221
+ if (noRollbackFor && noRollbackFor.length > 0) {
222
+ for (const ErrorClass of noRollbackFor) {
223
+ if (error instanceof ErrorClass) {
224
+ return false;
225
+ }
226
+ }
227
+ }
228
+
229
+ // 如果指定了 rollbackFor,且错误匹配,则回滚
230
+ if (rollbackFor && rollbackFor.length > 0) {
231
+ for (const ErrorClass of rollbackFor) {
232
+ if (error instanceof ErrorClass) {
233
+ return true;
234
+ }
235
+ }
236
+ // 如果指定了 rollbackFor 但错误不匹配,则不回滚
237
+ return false;
238
+ }
239
+
240
+ // 默认情况下,所有错误都回滚
241
+ return true;
242
+ }
243
+ }
@@ -0,0 +1,276 @@
1
+ import { Injectable, Inject } from '../../di/decorators';
2
+ import { DATABASE_SERVICE_TOKEN } from '../types';
3
+ import type { DatabaseService } from '../service';
4
+ import {
5
+ Propagation,
6
+ IsolationLevel,
7
+ TransactionStatus,
8
+ type TransactionOptions,
9
+ type TransactionContext,
10
+ } from './transaction-types';
11
+
12
+ /**
13
+ * 事务管理器
14
+ * 管理数据库事务的生命周期
15
+ */
16
+ @Injectable()
17
+ export class TransactionManager {
18
+ private readonly transactions = new Map<string, TransactionContext>();
19
+ private readonly connectionTransactions = new Map<unknown, string>(); // connection -> transactionId
20
+
21
+ public constructor(
22
+ @Inject(DATABASE_SERVICE_TOKEN)
23
+ private readonly databaseService: DatabaseService,
24
+ ) {}
25
+
26
+ /**
27
+ * 开始事务
28
+ */
29
+ public async beginTransaction(
30
+ options: TransactionOptions = {},
31
+ ): Promise<TransactionContext> {
32
+ const transactionId = this.generateTransactionId();
33
+ const context: TransactionContext = {
34
+ id: transactionId,
35
+ status: TransactionStatus.ACTIVE,
36
+ startTime: Date.now(),
37
+ level: 0,
38
+ savepoints: [],
39
+ };
40
+
41
+ // 获取数据库连接
42
+ const connection = await this.databaseService.getConnection();
43
+ this.connectionTransactions.set(connection, transactionId);
44
+ this.transactions.set(transactionId, context);
45
+
46
+ // 开始事务(根据数据库类型)
47
+ await this.executeBegin(connection, options);
48
+
49
+ return context;
50
+ }
51
+
52
+ /**
53
+ * 提交事务
54
+ */
55
+ public async commitTransaction(transactionId: string): Promise<void> {
56
+ const context = this.transactions.get(transactionId);
57
+ if (!context) {
58
+ throw new Error(`Transaction ${transactionId} not found`);
59
+ }
60
+
61
+ if (context.status !== TransactionStatus.ACTIVE) {
62
+ throw new Error(`Transaction ${transactionId} is not active`);
63
+ }
64
+
65
+ // 查找连接
66
+ const connection = this.findConnectionByTransactionId(transactionId);
67
+ if (!connection) {
68
+ throw new Error(`Connection not found for transaction ${transactionId}`);
69
+ }
70
+
71
+ // 提交事务
72
+ await this.executeCommit(connection);
73
+
74
+ context.status = TransactionStatus.COMMITTED;
75
+ this.cleanupTransaction(transactionId);
76
+ }
77
+
78
+ /**
79
+ * 回滚事务
80
+ */
81
+ public async rollbackTransaction(transactionId: string): Promise<void> {
82
+ const context = this.transactions.get(transactionId);
83
+ if (!context) {
84
+ throw new Error(`Transaction ${transactionId} not found`);
85
+ }
86
+
87
+ // 查找连接
88
+ const connection = this.findConnectionByTransactionId(transactionId);
89
+ if (!connection) {
90
+ throw new Error(`Connection not found for transaction ${transactionId}`);
91
+ }
92
+
93
+ // 回滚事务
94
+ await this.executeRollback(connection);
95
+
96
+ context.status = TransactionStatus.ROLLED_BACK;
97
+ this.cleanupTransaction(transactionId);
98
+ }
99
+
100
+ /**
101
+ * 创建保存点(用于嵌套事务)
102
+ */
103
+ public async createSavepoint(transactionId: string): Promise<string> {
104
+ const context = this.transactions.get(transactionId);
105
+ if (!context) {
106
+ throw new Error(`Transaction ${transactionId} not found`);
107
+ }
108
+
109
+ const savepointName = `sp_${context.level}_${Date.now()}`;
110
+ context.savepoints = context.savepoints || [];
111
+ context.savepoints.push(savepointName);
112
+ context.level += 1;
113
+
114
+ const connection = this.findConnectionByTransactionId(transactionId);
115
+ if (connection) {
116
+ await this.executeSavepoint(connection, savepointName);
117
+ }
118
+
119
+ return savepointName;
120
+ }
121
+
122
+ /**
123
+ * 回滚到保存点
124
+ */
125
+ public async rollbackToSavepoint(
126
+ transactionId: string,
127
+ savepointName: string,
128
+ ): Promise<void> {
129
+ const context = this.transactions.get(transactionId);
130
+ if (!context) {
131
+ throw new Error(`Transaction ${transactionId} not found`);
132
+ }
133
+
134
+ const connection = this.findConnectionByTransactionId(transactionId);
135
+ if (connection) {
136
+ await this.executeRollbackToSavepoint(connection, savepointName);
137
+ }
138
+
139
+ // 移除该保存点之后的所有保存点
140
+ const index = context.savepoints?.indexOf(savepointName) ?? -1;
141
+ if (index >= 0 && context.savepoints) {
142
+ context.savepoints = context.savepoints.slice(0, index);
143
+ context.level = index;
144
+ }
145
+ }
146
+
147
+ /**
148
+ * 获取当前事务上下文
149
+ */
150
+ public getCurrentTransaction(): TransactionContext | null {
151
+ // 简化实现:返回最后一个活动事务
152
+ // 实际实现中应该使用 ThreadLocal 或类似机制
153
+ for (const context of this.transactions.values()) {
154
+ if (context.status === TransactionStatus.ACTIVE) {
155
+ return context;
156
+ }
157
+ }
158
+ return null;
159
+ }
160
+
161
+ /**
162
+ * 检查是否有活动事务
163
+ */
164
+ public hasActiveTransaction(): boolean {
165
+ return this.getCurrentTransaction() !== null;
166
+ }
167
+
168
+ /**
169
+ * 生成事务 ID
170
+ */
171
+ private generateTransactionId(): string {
172
+ return `tx_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
173
+ }
174
+
175
+ /**
176
+ * 查找连接对应的事务 ID
177
+ */
178
+ private findConnectionByTransactionId(transactionId: string): unknown {
179
+ for (const [connection, txId] of this.connectionTransactions.entries()) {
180
+ if (txId === transactionId) {
181
+ return connection;
182
+ }
183
+ }
184
+ return null;
185
+ }
186
+
187
+ /**
188
+ * 清理事务
189
+ */
190
+ private cleanupTransaction(transactionId: string): void {
191
+ this.transactions.delete(transactionId);
192
+ // 清理连接映射
193
+ for (const [connection, txId] of this.connectionTransactions.entries()) {
194
+ if (txId === transactionId) {
195
+ this.connectionTransactions.delete(connection);
196
+ break;
197
+ }
198
+ }
199
+ }
200
+
201
+ /**
202
+ * 执行 BEGIN 语句
203
+ */
204
+ private async executeBegin(connection: unknown, options: TransactionOptions): Promise<void> {
205
+ const dbType = this.databaseService['config'].database.type;
206
+
207
+ if (dbType === 'sqlite') {
208
+ // SQLite 默认自动提交,需要显式开始事务
209
+ await this.databaseService.query('BEGIN TRANSACTION');
210
+ } else if (dbType === 'postgres' || dbType === 'mysql') {
211
+ // PostgreSQL 和 MySQL 使用 Bun.SQL,需要设置隔离级别
212
+ let sql = 'START TRANSACTION';
213
+ if (options.isolationLevel) {
214
+ const isolation = this.getIsolationLevelSQL(options.isolationLevel);
215
+ sql += ` ${isolation}`;
216
+ }
217
+ if (options.readOnly) {
218
+ sql += ' READ ONLY';
219
+ }
220
+ await this.databaseService.query(sql);
221
+ }
222
+ }
223
+
224
+ /**
225
+ * 执行 COMMIT 语句
226
+ */
227
+ private async executeCommit(connection: unknown): Promise<void> {
228
+ await this.databaseService.query('COMMIT');
229
+ }
230
+
231
+ /**
232
+ * 执行 ROLLBACK 语句
233
+ */
234
+ private async executeRollback(connection: unknown): Promise<void> {
235
+ await this.databaseService.query('ROLLBACK');
236
+ }
237
+
238
+ /**
239
+ * 执行 SAVEPOINT 语句
240
+ */
241
+ private async executeSavepoint(connection: unknown, savepointName: string): Promise<void> {
242
+ await this.databaseService.query(`SAVEPOINT ${savepointName}`);
243
+ }
244
+
245
+ /**
246
+ * 执行 ROLLBACK TO SAVEPOINT 语句
247
+ */
248
+ private async executeRollbackToSavepoint(
249
+ connection: unknown,
250
+ savepointName: string,
251
+ ): Promise<void> {
252
+ await this.databaseService.query(`ROLLBACK TO SAVEPOINT ${savepointName}`);
253
+ }
254
+
255
+ /**
256
+ * 获取隔离级别的 SQL
257
+ */
258
+ private getIsolationLevelSQL(level: IsolationLevel): string {
259
+ const dbType = this.databaseService['config'].database.type;
260
+ const levelMap: Record<IsolationLevel, string> = {
261
+ [IsolationLevel.READ_UNCOMMITTED]: 'READ UNCOMMITTED',
262
+ [IsolationLevel.READ_COMMITTED]: 'READ COMMITTED',
263
+ [IsolationLevel.REPEATABLE_READ]: 'REPEATABLE READ',
264
+ [IsolationLevel.SERIALIZABLE]: 'SERIALIZABLE',
265
+ };
266
+
267
+ if (dbType === 'postgres') {
268
+ return `SET TRANSACTION ISOLATION LEVEL ${levelMap[level]}`;
269
+ } else if (dbType === 'mysql') {
270
+ return `SET TRANSACTION ISOLATION LEVEL ${levelMap[level]}`;
271
+ }
272
+
273
+ // SQLite 不支持隔离级别设置
274
+ return '';
275
+ }
276
+ }
@@ -0,0 +1,140 @@
1
+ /**
2
+ * 事务传播行为
3
+ */
4
+ export enum Propagation {
5
+ /**
6
+ * 如果当前存在事务,则加入该事务;如果当前不存在事务,则创建一个新的事务
7
+ */
8
+ REQUIRED = 'REQUIRED',
9
+ /**
10
+ * 创建一个新的事务,如果当前存在事务,则把当前事务挂起
11
+ */
12
+ REQUIRES_NEW = 'REQUIRES_NEW',
13
+ /**
14
+ * 如果当前存在事务,则加入该事务;如果当前不存在事务,则以非事务的方式继续运行
15
+ */
16
+ SUPPORTS = 'SUPPORTS',
17
+ /**
18
+ * 以非事务方式执行操作,如果当前存在事务,则把当前事务挂起
19
+ */
20
+ NOT_SUPPORTED = 'NOT_SUPPORTED',
21
+ /**
22
+ * 以非事务方式执行,如果当前存在事务,则抛出异常
23
+ */
24
+ NEVER = 'NEVER',
25
+ /**
26
+ * 如果当前存在事务,则在嵌套事务内执行;如果当前不存在事务,则创建一个新的事务
27
+ */
28
+ NESTED = 'NESTED',
29
+ }
30
+
31
+ /**
32
+ * 事务隔离级别
33
+ */
34
+ export enum IsolationLevel {
35
+ /**
36
+ * 读未提交(最低级别)
37
+ */
38
+ READ_UNCOMMITTED = 'READ_UNCOMMITTED',
39
+ /**
40
+ * 读已提交
41
+ */
42
+ READ_COMMITTED = 'READ_COMMITTED',
43
+ /**
44
+ * 可重复读
45
+ */
46
+ REPEATABLE_READ = 'REPEATABLE_READ',
47
+ /**
48
+ * 串行化(最高级别)
49
+ */
50
+ SERIALIZABLE = 'SERIALIZABLE',
51
+ }
52
+
53
+ /**
54
+ * 事务状态
55
+ */
56
+ export enum TransactionStatus {
57
+ /**
58
+ * 活动状态
59
+ */
60
+ ACTIVE = 'ACTIVE',
61
+ /**
62
+ * 已提交
63
+ */
64
+ COMMITTED = 'COMMITTED',
65
+ /**
66
+ * 已回滚
67
+ */
68
+ ROLLED_BACK = 'ROLLED_BACK',
69
+ /**
70
+ * 已挂起
71
+ */
72
+ SUSPENDED = 'SUSPENDED',
73
+ }
74
+
75
+ /**
76
+ * 事务配置选项
77
+ */
78
+ export interface TransactionOptions {
79
+ /**
80
+ * 事务传播行为
81
+ * @default Propagation.REQUIRED
82
+ */
83
+ propagation?: Propagation;
84
+ /**
85
+ * 事务隔离级别
86
+ */
87
+ isolationLevel?: IsolationLevel;
88
+ /**
89
+ * 超时时间(秒)
90
+ */
91
+ timeout?: number;
92
+ /**
93
+ * 是否只读
94
+ * @default false
95
+ */
96
+ readOnly?: boolean;
97
+ /**
98
+ * 回滚异常类型(遇到这些异常时回滚)
99
+ */
100
+ rollbackFor?: Array<new () => Error>;
101
+ /**
102
+ * 不回滚异常类型(遇到这些异常时不回滚)
103
+ */
104
+ noRollbackFor?: Array<new () => Error>;
105
+ }
106
+
107
+ /**
108
+ * 事务上下文
109
+ */
110
+ export interface TransactionContext {
111
+ /**
112
+ * 事务 ID
113
+ */
114
+ id: string;
115
+ /**
116
+ * 事务状态
117
+ */
118
+ status: TransactionStatus;
119
+ /**
120
+ * 事务开始时间
121
+ */
122
+ startTime: number;
123
+ /**
124
+ * 嵌套层级
125
+ */
126
+ level: number;
127
+ /**
128
+ * 父事务 ID(如果有)
129
+ */
130
+ parentId?: string;
131
+ /**
132
+ * 保存点(用于嵌套事务)
133
+ */
134
+ savepoints?: string[];
135
+ }
136
+
137
+ /**
138
+ * Transaction Service Token
139
+ */
140
+ export const TRANSACTION_SERVICE_TOKEN = Symbol('@dangao/bun-server:orm:transaction:service');