@dangao/bun-server 2.0.8 → 2.1.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 (89) hide show
  1. package/README.md +4 -0
  2. package/dist/controller/controller.d.ts.map +1 -1
  3. package/dist/core/application.d.ts +6 -1
  4. package/dist/core/application.d.ts.map +1 -1
  5. package/dist/core/server.d.ts +5 -0
  6. package/dist/core/server.d.ts.map +1 -1
  7. package/dist/database/database-context.d.ts +25 -0
  8. package/dist/database/database-context.d.ts.map +1 -0
  9. package/dist/database/database-extension.d.ts +8 -9
  10. package/dist/database/database-extension.d.ts.map +1 -1
  11. package/dist/database/database-module.d.ts +7 -1
  12. package/dist/database/database-module.d.ts.map +1 -1
  13. package/dist/database/db-proxy.d.ts +12 -0
  14. package/dist/database/db-proxy.d.ts.map +1 -0
  15. package/dist/database/index.d.ts +6 -1
  16. package/dist/database/index.d.ts.map +1 -1
  17. package/dist/database/orm/transaction-interceptor.d.ts +0 -16
  18. package/dist/database/orm/transaction-interceptor.d.ts.map +1 -1
  19. package/dist/database/orm/transaction-manager.d.ts +10 -61
  20. package/dist/database/orm/transaction-manager.d.ts.map +1 -1
  21. package/dist/database/service.d.ts.map +1 -1
  22. package/dist/database/sql-manager.d.ts +14 -0
  23. package/dist/database/sql-manager.d.ts.map +1 -0
  24. package/dist/database/sqlite-adapter.d.ts +32 -0
  25. package/dist/database/sqlite-adapter.d.ts.map +1 -0
  26. package/dist/database/strategy-decorator.d.ts +8 -0
  27. package/dist/database/strategy-decorator.d.ts.map +1 -0
  28. package/dist/database/types.d.ts +122 -1
  29. package/dist/database/types.d.ts.map +1 -1
  30. package/dist/di/module-registry.d.ts.map +1 -1
  31. package/dist/index.d.ts +3 -3
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +3115 -2586
  34. package/dist/microservice/service-registry/service-registry-module.d.ts +16 -0
  35. package/dist/microservice/service-registry/service-registry-module.d.ts.map +1 -1
  36. package/dist/router/index.d.ts +1 -0
  37. package/dist/router/index.d.ts.map +1 -1
  38. package/dist/router/registry.d.ts +1 -1
  39. package/dist/router/registry.d.ts.map +1 -1
  40. package/dist/router/route.d.ts +2 -1
  41. package/dist/router/route.d.ts.map +1 -1
  42. package/dist/router/router.d.ts +1 -1
  43. package/dist/router/router.d.ts.map +1 -1
  44. package/dist/router/timeout-decorator.d.ts +6 -0
  45. package/dist/router/timeout-decorator.d.ts.map +1 -0
  46. package/docs/database.md +48 -15
  47. package/docs/idle-timeout.md +42 -0
  48. package/docs/lifecycle.md +6 -0
  49. package/docs/microservice-nacos.md +1 -0
  50. package/docs/microservice-service-registry.md +7 -0
  51. package/docs/zh/database.md +48 -15
  52. package/docs/zh/idle-timeout.md +41 -0
  53. package/docs/zh/lifecycle.md +5 -0
  54. package/docs/zh/microservice-nacos.md +1 -0
  55. package/docs/zh/microservice-service-registry.md +6 -0
  56. package/package.json +1 -1
  57. package/src/controller/controller.ts +11 -1
  58. package/src/core/application.ts +60 -1
  59. package/src/core/server.ts +10 -0
  60. package/src/database/database-context.ts +43 -0
  61. package/src/database/database-extension.ts +12 -45
  62. package/src/database/database-module.ts +254 -11
  63. package/src/database/db-proxy.ts +75 -0
  64. package/src/database/index.ts +29 -0
  65. package/src/database/orm/transaction-interceptor.ts +12 -149
  66. package/src/database/orm/transaction-manager.ts +143 -210
  67. package/src/database/service.ts +28 -2
  68. package/src/database/sql-manager.ts +62 -0
  69. package/src/database/sqlite-adapter.ts +121 -0
  70. package/src/database/strategy-decorator.ts +42 -0
  71. package/src/database/types.ts +133 -1
  72. package/src/di/module-registry.ts +20 -4
  73. package/src/index.ts +27 -1
  74. package/src/microservice/service-registry/service-registry-module.ts +25 -1
  75. package/src/router/index.ts +1 -0
  76. package/src/router/registry.ts +10 -1
  77. package/src/router/route.ts +31 -3
  78. package/src/router/router.ts +10 -1
  79. package/src/router/timeout-decorator.ts +35 -0
  80. package/tests/core/application.test.ts +10 -0
  81. package/tests/database/database-module.test.ts +91 -430
  82. package/tests/database/db-proxy.test.ts +93 -0
  83. package/tests/database/sql-manager.test.ts +43 -0
  84. package/tests/database/sqlite-adapter.test.ts +45 -0
  85. package/tests/database/strategy-decorator.test.ts +29 -0
  86. package/tests/database/transaction.test.ts +84 -222
  87. package/tests/di/lifecycle.test.ts +37 -0
  88. package/tests/microservice/service-registry.test.ts +15 -0
  89. package/tests/router/timeout-decorator.test.ts +48 -0
@@ -3,8 +3,8 @@ import type { Context } from '../../core/context';
3
3
  import type { Interceptor } from '../../interceptor';
4
4
  import { TRANSACTION_SERVICE_TOKEN } from './transaction-types';
5
5
  import { TransactionManager } from './transaction-manager';
6
- import { getTransactionMetadata, TRANSACTION_METADATA_KEY } from './transaction-decorator';
7
- import { Propagation, TransactionStatus } from './transaction-types';
6
+ import { getTransactionMetadata } from './transaction-decorator';
7
+ import { Propagation } from './transaction-types';
8
8
 
9
9
  /**
10
10
  * 事务拦截器
@@ -51,44 +51,26 @@ export class TransactionInterceptor implements Interceptor {
51
51
  case Propagation.REQUIRED:
52
52
  if (currentTransaction) {
53
53
  // 加入现有事务
54
- return await TransactionInterceptor.executeInExistingTransaction(
55
- originalMethod,
56
- target,
57
- args,
58
- currentTransaction.id,
59
- transactionManager,
60
- );
54
+ return await Promise.resolve(originalMethod.apply(target, args));
61
55
  } else {
62
56
  // 创建新事务
63
- return await TransactionInterceptor.executeInNewTransaction(
64
- originalMethod,
65
- target,
66
- args,
57
+ return await transactionManager.runInTransaction(
58
+ async () => await Promise.resolve(originalMethod.apply(target, args)),
67
59
  transactionMetadata,
68
- transactionManager,
69
60
  );
70
61
  }
71
62
 
72
63
  case Propagation.REQUIRES_NEW:
73
64
  // 总是创建新事务
74
- return await TransactionInterceptor.executeInNewTransaction(
75
- originalMethod,
76
- target,
77
- args,
65
+ return await transactionManager.runInNewTransaction(
66
+ async () => await Promise.resolve(originalMethod.apply(target, args)),
78
67
  transactionMetadata,
79
- transactionManager,
80
68
  );
81
69
 
82
70
  case Propagation.SUPPORTS:
83
71
  if (currentTransaction) {
84
72
  // 加入现有事务
85
- return await TransactionInterceptor.executeInExistingTransaction(
86
- originalMethod,
87
- target,
88
- args,
89
- currentTransaction.id,
90
- transactionManager,
91
- );
73
+ return await Promise.resolve(originalMethod.apply(target, args));
92
74
  } else {
93
75
  // 非事务执行
94
76
  return await Promise.resolve(originalMethod.apply(target, args));
@@ -109,22 +91,15 @@ export class TransactionInterceptor implements Interceptor {
109
91
  case Propagation.NESTED:
110
92
  if (currentTransaction) {
111
93
  // 创建嵌套事务(保存点)
112
- return await TransactionInterceptor.executeInNestedTransaction(
113
- originalMethod,
114
- target,
115
- args,
116
- currentTransaction.id,
94
+ return await transactionManager.runInNestedTransaction(
95
+ async () => await Promise.resolve(originalMethod.apply(target, args)),
117
96
  transactionMetadata,
118
- transactionManager,
119
97
  );
120
98
  } else {
121
99
  // 创建新事务
122
- return await TransactionInterceptor.executeInNewTransaction(
123
- originalMethod,
124
- target,
125
- args,
100
+ return await transactionManager.runInTransaction(
101
+ async () => await Promise.resolve(originalMethod.apply(target, args)),
126
102
  transactionMetadata,
127
- transactionManager,
128
103
  );
129
104
  }
130
105
 
@@ -148,116 +123,4 @@ export class TransactionInterceptor implements Interceptor {
148
123
  return await interceptor.execute(target, propertyKey, originalMethod, args, container);
149
124
  }
150
125
 
151
- /**
152
- * 在新事务中执行方法
153
- */
154
- private static async executeInNewTransaction<T>(
155
- method: (...args: unknown[]) => T | Promise<T>,
156
- target: unknown,
157
- args: unknown[],
158
- options: {
159
- timeout?: number;
160
- rollbackFor?: Array<new () => Error>;
161
- noRollbackFor?: Array<new () => Error>;
162
- },
163
- transactionManager: TransactionManager,
164
- ): Promise<T> {
165
- const context = await transactionManager.beginTransaction({
166
- timeout: options.timeout,
167
- });
168
-
169
- try {
170
- const result = await Promise.resolve(method.apply(target, args));
171
- await transactionManager.commitTransaction(context.id);
172
- return result;
173
- } catch (error) {
174
- // 检查是否需要回滚
175
- if (this.shouldRollback(error, options.rollbackFor, options.noRollbackFor)) {
176
- await transactionManager.rollbackTransaction(context.id);
177
- } else {
178
- await transactionManager.commitTransaction(context.id);
179
- }
180
- throw error;
181
- }
182
- }
183
-
184
- /**
185
- * 在现有事务中执行方法
186
- */
187
- private static async executeInExistingTransaction<T>(
188
- method: (...args: unknown[]) => T | Promise<T>,
189
- target: unknown,
190
- args: unknown[],
191
- transactionId: string,
192
- transactionManager: TransactionManager,
193
- ): Promise<T> {
194
- // 直接执行,不提交或回滚(由外层事务管理)
195
- return await Promise.resolve(method.apply(target, args));
196
- }
197
-
198
- /**
199
- * 在嵌套事务中执行方法
200
- */
201
- private static async executeInNestedTransaction<T>(
202
- method: (...args: unknown[]) => T | Promise<T>,
203
- target: unknown,
204
- args: unknown[],
205
- parentTransactionId: string,
206
- options: {
207
- timeout?: number;
208
- rollbackFor?: Array<new () => Error>;
209
- noRollbackFor?: Array<new () => Error>;
210
- },
211
- transactionManager: TransactionManager,
212
- ): Promise<T> {
213
- const savepointName = await transactionManager.createSavepoint(parentTransactionId);
214
-
215
- try {
216
- const result = await Promise.resolve(method.apply(target, args));
217
- // 嵌套事务成功,不执行任何操作(保存点保留)
218
- return result;
219
- } catch (error) {
220
- // 检查是否需要回滚到保存点
221
- if (this.shouldRollback(error, options.rollbackFor, options.noRollbackFor)) {
222
- await transactionManager.rollbackToSavepoint(parentTransactionId, savepointName);
223
- }
224
- throw error;
225
- }
226
- }
227
-
228
- /**
229
- * 判断是否应该回滚
230
- */
231
- private static shouldRollback(
232
- error: unknown,
233
- rollbackFor?: Array<new () => Error>,
234
- noRollbackFor?: Array<new () => Error>,
235
- ): boolean {
236
- if (!error) {
237
- return false;
238
- }
239
-
240
- // 如果指定了 noRollbackFor,且错误匹配,则不回滚
241
- if (noRollbackFor && noRollbackFor.length > 0) {
242
- for (const ErrorClass of noRollbackFor) {
243
- if (error instanceof ErrorClass) {
244
- return false;
245
- }
246
- }
247
- }
248
-
249
- // 如果指定了 rollbackFor,且错误匹配,则回滚
250
- if (rollbackFor && rollbackFor.length > 0) {
251
- for (const ErrorClass of rollbackFor) {
252
- if (error instanceof ErrorClass) {
253
- return true;
254
- }
255
- }
256
- // 如果指定了 rollbackFor 但错误不匹配,则不回滚
257
- return false;
258
- }
259
-
260
- // 默认情况下,所有错误都回滚
261
- return true;
262
- }
263
126
  }
@@ -1,8 +1,8 @@
1
- import { Injectable, Inject } from '../../di/decorators';
2
- import { DATABASE_SERVICE_TOKEN } from '../types';
3
- import type { DatabaseService } from '../service';
1
+ import { Inject, Injectable } from '../../di/decorators';
2
+ import { getCurrentSession, runWithSession } from '../database-context';
3
+ import { BUN_SQL_MANAGER_TOKEN } from '../types';
4
+ import type { BunSQLManager } from '../sql-manager';
4
5
  import {
5
- Propagation,
6
6
  IsolationLevel,
7
7
  TransactionStatus,
8
8
  type TransactionOptions,
@@ -15,262 +15,195 @@ import {
15
15
  */
16
16
  @Injectable()
17
17
  export class TransactionManager {
18
- private readonly transactions = new Map<string, TransactionContext>();
19
- private readonly connectionTransactions = new Map<unknown, string>(); // connection -> transactionId
20
-
21
18
  public constructor(
22
- @Inject(DATABASE_SERVICE_TOKEN)
23
- private readonly databaseService: DatabaseService,
19
+ @Inject(BUN_SQL_MANAGER_TOKEN)
20
+ private readonly sqlManager: BunSQLManager,
24
21
  ) {}
25
22
 
26
23
  /**
27
- * 开始事务
24
+ * 在当前 session 中执行事务
28
25
  */
29
- public async beginTransaction(
26
+ public async runInTransaction<T>(
27
+ fn: () => Promise<T>,
30
28
  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`);
29
+ ): Promise<T> {
30
+ const session = getCurrentSession();
31
+ if (!session) {
32
+ throw new Error(
33
+ '[TransactionManager] No database session in current request context',
34
+ );
59
35
  }
60
36
 
61
- if (context.status !== TransactionStatus.ACTIVE) {
62
- throw new Error(`Transaction ${transactionId} is not active`);
37
+ if (session.sqlite) {
38
+ return await this.runInSqliteTransaction(fn);
63
39
  }
64
40
 
65
- // 查找连接
66
- const connection = this.findConnectionByTransactionId(transactionId);
67
- if (!connection) {
68
- throw new Error(`Connection not found for transaction ${transactionId}`);
41
+ let reserved = session.reserved;
42
+ if (!reserved && session.lazyReserve) {
43
+ reserved = await session.lazyReserve();
44
+ }
45
+ if (!reserved) {
46
+ throw new Error(
47
+ '[TransactionManager] No reserved session in current context. Add @Session() or @DbStrategy("session").',
48
+ );
69
49
  }
70
50
 
71
- // 提交事务
72
- await this.executeCommit(connection);
73
-
74
- context.status = TransactionStatus.COMMITTED;
75
- this.cleanupTransaction(transactionId);
76
- }
51
+ const transactionId = this.generateTransactionId();
52
+ session.transaction = {
53
+ id: transactionId,
54
+ status: TransactionStatus.ACTIVE,
55
+ level: 0,
56
+ savepoints: [],
57
+ };
77
58
 
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`);
59
+ if (options.isolationLevel) {
60
+ const isolationLevel = this.getIsolationLevelSQL(options.isolationLevel);
61
+ if (isolationLevel) {
62
+ await reserved`SET TRANSACTION ISOLATION LEVEL ${isolationLevel}`;
63
+ }
85
64
  }
86
65
 
87
- // 查找连接
88
- const connection = this.findConnectionByTransactionId(transactionId);
89
- if (!connection) {
90
- throw new Error(`Connection not found for transaction ${transactionId}`);
66
+ try {
67
+ const result = await reserved.begin(fn);
68
+ if (session.transaction) {
69
+ session.transaction.status = TransactionStatus.COMMITTED;
70
+ }
71
+ return result;
72
+ } catch (error) {
73
+ if (session.transaction) {
74
+ session.transaction.status = TransactionStatus.ROLLED_BACK;
75
+ }
76
+ throw error;
77
+ } finally {
78
+ session.transaction = undefined;
91
79
  }
92
-
93
- // 回滚事务
94
- await this.executeRollback(connection);
95
-
96
- context.status = TransactionStatus.ROLLED_BACK;
97
- this.cleanupTransaction(transactionId);
98
80
  }
99
81
 
100
82
  /**
101
- * 创建保存点(用于嵌套事务)
83
+ * REQUIRES_NEW:使用独立连接开启新事务
102
84
  */
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);
85
+ public async runInNewTransaction<T>(
86
+ fn: () => Promise<T>,
87
+ options: TransactionOptions = {},
88
+ ): Promise<T> {
89
+ const reserved = await this.sqlManager.getDefault().reserve();
90
+ try {
91
+ const tenantId = getCurrentSession()?.tenantId ?? 'default';
92
+ return await runWithSession(
93
+ {
94
+ tenantId,
95
+ reserved: reserved as any,
96
+ },
97
+ () => this.runInTransaction(fn, options),
98
+ );
99
+ } finally {
100
+ await reserved.release();
117
101
  }
118
-
119
- return savepointName;
120
102
  }
121
103
 
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`);
104
+ public async runInNestedTransaction<T>(
105
+ fn: () => Promise<T>,
106
+ options: TransactionOptions = {},
107
+ ): Promise<T> {
108
+ const session = getCurrentSession();
109
+ if (!session?.transaction || !session.reserved) {
110
+ throw new Error(
111
+ '[TransactionManager] NESTED propagation requires an active transaction',
112
+ );
132
113
  }
133
114
 
134
- const connection = this.findConnectionByTransactionId(transactionId);
135
- if (connection) {
136
- await this.executeRollbackToSavepoint(connection, savepointName);
137
- }
115
+ const savepointName = `sp_${session.transaction.level}_${Date.now()}`;
116
+ session.transaction.level += 1;
117
+ session.transaction.savepoints.push(savepointName);
138
118
 
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;
119
+ await session.reserved`SAVEPOINT ${savepointName}`;
120
+ try {
121
+ return await fn();
122
+ } catch (error) {
123
+ if (this.shouldRollback(error, options)) {
124
+ await session.reserved`ROLLBACK TO SAVEPOINT ${savepointName}`;
125
+ }
126
+ throw error;
127
+ } finally {
128
+ session.transaction.level = Math.max(0, session.transaction.level - 1);
129
+ session.transaction.savepoints = session.transaction.savepoints.filter(
130
+ (item) => item !== savepointName,
131
+ );
144
132
  }
145
133
  }
146
134
 
147
- /**
148
- * 获取当前事务上下文
149
- */
150
135
  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
- }
136
+ const tx = getCurrentSession()?.transaction;
137
+ if (!tx) {
138
+ return null;
157
139
  }
158
- return null;
140
+ return {
141
+ id: tx.id,
142
+ status: tx.status,
143
+ startTime: 0,
144
+ level: tx.level,
145
+ savepoints: tx.savepoints,
146
+ };
159
147
  }
160
148
 
161
- /**
162
- * 检查是否有活动事务
163
- */
164
149
  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;
150
+ const tx = this.getCurrentTransaction();
151
+ return tx?.status === TransactionStatus.ACTIVE;
185
152
  }
186
153
 
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
- }
154
+ public async runInSqliteTransaction<T>(fn: () => Promise<T>): Promise<T> {
155
+ const session = getCurrentSession();
156
+ if (!session?.sqlite) {
157
+ throw new Error(
158
+ '[TransactionManager] No sqlite adapter found in current request context',
159
+ );
198
160
  }
199
- }
200
161
 
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);
162
+ using _lock = await session.sqlite.semaphore.acquire();
163
+ await session.sqlite.execute('BEGIN TRANSACTION');
164
+ try {
165
+ const result = await fn();
166
+ await session.sqlite.execute('COMMIT');
167
+ return result;
168
+ } catch (error) {
169
+ await session.sqlite.execute('ROLLBACK');
170
+ throw error;
221
171
  }
222
172
  }
223
173
 
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}`);
174
+ private generateTransactionId(): string {
175
+ return `tx_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
253
176
  }
254
177
 
255
- /**
256
- * 获取隔离级别的 SQL
257
- */
258
178
  private getIsolationLevelSQL(level: IsolationLevel): string {
259
- const dbType = this.databaseService['config'].database.type;
260
179
  const levelMap: Record<IsolationLevel, string> = {
261
180
  [IsolationLevel.READ_UNCOMMITTED]: 'READ UNCOMMITTED',
262
181
  [IsolationLevel.READ_COMMITTED]: 'READ COMMITTED',
263
182
  [IsolationLevel.REPEATABLE_READ]: 'REPEATABLE READ',
264
183
  [IsolationLevel.SERIALIZABLE]: 'SERIALIZABLE',
265
184
  };
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]}`;
185
+ return levelMap[level];
186
+ }
187
+
188
+ private shouldRollback(
189
+ error: unknown,
190
+ options: Pick<TransactionOptions, 'rollbackFor' | 'noRollbackFor'>,
191
+ ): boolean {
192
+ if (options.noRollbackFor && options.noRollbackFor.length > 0) {
193
+ for (const ErrorClass of options.noRollbackFor) {
194
+ if (error instanceof ErrorClass) {
195
+ return false;
196
+ }
197
+ }
271
198
  }
272
-
273
- // SQLite 不支持隔离级别设置
274
- return '';
199
+ if (options.rollbackFor && options.rollbackFor.length > 0) {
200
+ for (const ErrorClass of options.rollbackFor) {
201
+ if (error instanceof ErrorClass) {
202
+ return true;
203
+ }
204
+ }
205
+ return false;
206
+ }
207
+ return true;
275
208
  }
276
209
  }
@@ -1,6 +1,7 @@
1
1
  import { Injectable } from '../di/decorators';
2
2
 
3
3
  import { DatabaseConnectionManager } from './connection-manager';
4
+ import { getCurrentSession } from './database-context';
4
5
  import type {
5
6
  ConnectionInfo,
6
7
  DatabaseConfig,
@@ -18,8 +19,27 @@ export class DatabaseService {
18
19
 
19
20
  public constructor(options: DatabaseModuleOptions) {
20
21
  this.options = options;
22
+ const databaseConfig: DatabaseConfig =
23
+ options.database ??
24
+ (options.type === 'sqlite'
25
+ ? {
26
+ type: 'sqlite',
27
+ config: {
28
+ path: options.databasePath ?? ':memory:',
29
+ },
30
+ }
31
+ : {
32
+ type: (options.type ?? 'postgres') as 'postgres' | 'mysql',
33
+ config: {
34
+ host: options.host ?? 'localhost',
35
+ port: options.port ?? 5432,
36
+ database: options.databasePath ?? 'default',
37
+ user: options.username ?? 'root',
38
+ password: options.password ?? '',
39
+ },
40
+ });
21
41
  this.connectionManager = new DatabaseConnectionManager(
22
- options.database,
42
+ databaseConfig,
23
43
  options.pool,
24
44
  );
25
45
  }
@@ -96,7 +116,13 @@ export class DatabaseService {
96
116
  * SQLite 返回同步结果,PostgreSQL/MySQL 返回异步结果
97
117
  */
98
118
  public query<T = unknown>(sql: string, params?: unknown[]): T[] | Promise<T[]> {
99
- const connection = this.getConnection();
119
+ const session = getCurrentSession();
120
+ if (session?.sqlite) {
121
+ return session.sqlite.query<T>(sql, (params ?? []) as any);
122
+ }
123
+
124
+ const perRequestConnection = session?.reserved;
125
+ const connection = perRequestConnection ?? this.getConnection();
100
126
  if (!connection) {
101
127
  throw new Error('Database connection is not established');
102
128
  }