@nest-omni/core 4.1.3-11 → 4.1.3-12
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/audit/audit.module.js +17 -0
- package/audit/controllers/audit.controller.d.ts +64 -0
- package/audit/controllers/audit.controller.js +50 -0
- package/audit/decorators/audit-action.decorator.d.ts +74 -0
- package/audit/decorators/audit-action.decorator.js +42 -0
- package/audit/decorators/entity-audit.decorator.d.ts +10 -1
- package/audit/decorators/entity-audit.decorator.js +34 -16
- package/audit/decorators/index.d.ts +1 -0
- package/audit/decorators/index.js +1 -0
- package/audit/entities/audit-action-summary.entity.d.ts +23 -0
- package/audit/entities/audit-action-summary.entity.js +101 -0
- package/audit/entities/entity-audit-log.entity.d.ts +3 -0
- package/audit/entities/entity-audit-log.entity.js +25 -2
- package/audit/entities/entity-transaction.entity.d.ts +3 -4
- package/audit/entities/entity-transaction.entity.js +10 -3
- package/audit/entities/index.d.ts +1 -0
- package/audit/entities/index.js +1 -0
- package/audit/entities/manual-operation-log.entity.js +8 -1
- package/audit/enums/audit.enums.d.ts +1 -10
- package/audit/enums/audit.enums.js +7 -17
- package/audit/index.d.ts +2 -1
- package/audit/index.js +5 -1
- package/audit/interceptors/audit-action.interceptor.d.ts +38 -0
- package/audit/interceptors/audit-action.interceptor.js +215 -0
- package/audit/interceptors/index.d.ts +1 -0
- package/audit/interceptors/index.js +1 -0
- package/audit/interfaces/audit.interfaces.d.ts +10 -5
- package/audit/services/audit-action.service.d.ts +141 -0
- package/audit/services/audit-action.service.js +244 -0
- package/audit/services/audit-context.service.d.ts +82 -0
- package/audit/services/audit-context.service.js +170 -0
- package/audit/services/entity-audit.service.d.ts +104 -3
- package/audit/services/entity-audit.service.js +306 -9
- package/audit/services/index.d.ts +1 -0
- package/audit/services/index.js +1 -0
- package/audit/services/manual-audit-log.service.d.ts +24 -23
- package/audit/services/manual-audit-log.service.js +32 -53
- package/audit/services/operation-description.service.d.ts +13 -3
- package/audit/services/operation-description.service.js +161 -24
- package/audit/services/transaction-audit.service.js +3 -3
- package/audit/subscribers/entity-audit.subscriber.d.ts +4 -0
- package/audit/subscribers/entity-audit.subscriber.js +47 -0
- package/file-upload/controllers/file-access.controller.d.ts +23 -0
- package/file-upload/controllers/file-access.controller.js +128 -0
- package/file-upload/decorators/csv-data.decorator.d.ts +44 -0
- package/file-upload/decorators/csv-data.decorator.js +131 -0
- package/file-upload/decorators/excel-data.decorator.d.ts +44 -0
- package/file-upload/decorators/excel-data.decorator.js +125 -0
- package/file-upload/decorators/file-upload.decorator.d.ts +83 -0
- package/file-upload/decorators/file-upload.decorator.js +172 -0
- package/file-upload/decorators/index.d.ts +4 -0
- package/file-upload/decorators/index.js +20 -0
- package/file-upload/decorators/process.decorator.d.ts +40 -0
- package/file-upload/decorators/process.decorator.js +52 -0
- package/file-upload/dto/create-file.dto.d.ts +24 -0
- package/file-upload/dto/create-file.dto.js +112 -0
- package/file-upload/dto/find-files.dto.d.ts +15 -0
- package/file-upload/dto/find-files.dto.js +76 -0
- package/file-upload/dto/index.d.ts +4 -0
- package/file-upload/dto/index.js +20 -0
- package/file-upload/dto/pagination.dto.d.ts +7 -0
- package/file-upload/dto/pagination.dto.js +39 -0
- package/file-upload/dto/update-file.dto.d.ts +16 -0
- package/file-upload/dto/update-file.dto.js +71 -0
- package/file-upload/entities/file-metadata.entity.d.ts +22 -0
- package/file-upload/entities/file-metadata.entity.js +84 -0
- package/file-upload/entities/file.entity.d.ts +129 -0
- package/file-upload/entities/file.entity.js +384 -0
- package/file-upload/entities/index.d.ts +2 -0
- package/file-upload/entities/index.js +18 -0
- package/file-upload/enums/file-type.enum.d.ts +72 -0
- package/file-upload/enums/file-type.enum.js +212 -0
- package/file-upload/exceptions/file-upload.exception.d.ts +57 -0
- package/file-upload/exceptions/file-upload.exception.js +120 -0
- package/file-upload/exceptions/index.d.ts +1 -0
- package/file-upload/exceptions/index.js +17 -0
- package/file-upload/file-upload.module.d.ts +89 -0
- package/file-upload/file-upload.module.js +264 -0
- package/file-upload/index.d.ts +26 -0
- package/file-upload/index.js +59 -0
- package/file-upload/interceptors/file-upload.interceptor.d.ts +48 -0
- package/file-upload/interceptors/file-upload.interceptor.js +434 -0
- package/file-upload/interceptors/index.d.ts +1 -0
- package/file-upload/interceptors/index.js +17 -0
- package/file-upload/interfaces/custom-file-type.interface.d.ts +72 -0
- package/file-upload/interfaces/custom-file-type.interface.js +2 -0
- package/file-upload/interfaces/file-buffer.interface.d.ts +72 -0
- package/file-upload/interfaces/file-buffer.interface.js +2 -0
- package/file-upload/interfaces/file-entity.interface.d.ts +142 -0
- package/file-upload/interfaces/file-entity.interface.js +28 -0
- package/file-upload/interfaces/file-metadata.interface.d.ts +21 -0
- package/file-upload/interfaces/file-metadata.interface.js +2 -0
- package/file-upload/interfaces/file-upload-options.interface.d.ts +117 -0
- package/file-upload/interfaces/file-upload-options.interface.js +2 -0
- package/file-upload/interfaces/index.d.ts +7 -0
- package/file-upload/interfaces/index.js +24 -0
- package/file-upload/interfaces/storage-provider.interface.d.ts +239 -0
- package/file-upload/interfaces/storage-provider.interface.js +2 -0
- package/file-upload/interfaces/upload-options.interface.d.ts +19 -0
- package/file-upload/interfaces/upload-options.interface.js +2 -0
- package/file-upload/providers/index.d.ts +2 -0
- package/file-upload/providers/index.js +18 -0
- package/file-upload/providers/local-storage.provider.d.ts +98 -0
- package/file-upload/providers/local-storage.provider.js +484 -0
- package/file-upload/providers/s3-storage.provider.d.ts +87 -0
- package/file-upload/providers/s3-storage.provider.js +455 -0
- package/file-upload/services/file-signature-validator.service.d.ts +118 -0
- package/file-upload/services/file-signature-validator.service.js +376 -0
- package/file-upload/services/file.service.d.ts +190 -0
- package/file-upload/services/file.service.js +609 -0
- package/file-upload/services/index.d.ts +4 -0
- package/file-upload/services/index.js +20 -0
- package/file-upload/services/malicious-file-detector.service.d.ts +274 -0
- package/file-upload/services/malicious-file-detector.service.js +1035 -0
- package/file-upload/services/mime-registry.service.d.ts +47 -0
- package/file-upload/services/mime-registry.service.js +167 -0
- package/file-upload/utils/checksum.util.d.ts +28 -0
- package/file-upload/utils/checksum.util.js +65 -0
- package/file-upload/utils/dynamic-import.util.d.ts +50 -0
- package/file-upload/utils/dynamic-import.util.js +144 -0
- package/file-upload/utils/filename.util.d.ts +59 -0
- package/file-upload/utils/filename.util.js +184 -0
- package/file-upload/utils/filepath.util.d.ts +70 -0
- package/file-upload/utils/filepath.util.js +152 -0
- package/file-upload/utils/index.d.ts +4 -0
- package/file-upload/utils/index.js +20 -0
- package/index.d.ts +3 -1
- package/index.js +4 -1
- package/package.json +4 -5
- package/setup/bootstrap.setup.d.ts +1 -0
- package/setup/bootstrap.setup.js +1 -0
- package/shared/index.d.ts +1 -1
- package/shared/index.js +1 -1
- package/shared/{serviceRegistryModule.js → service-registry.module.js} +0 -12
- package/shared/services/index.d.ts +0 -1
- package/shared/services/index.js +0 -1
- package/transaction/__tests__/mocks.d.ts +9 -0
- package/transaction/__tests__/mocks.js +33 -0
- package/transaction/base-service-transaction.d.ts +99 -0
- package/transaction/base-service-transaction.js +286 -0
- package/transaction/cls-compatibility.service.d.ts +55 -0
- package/transaction/cls-compatibility.service.js +127 -0
- package/transaction/data-source-registry.d.ts +91 -0
- package/transaction/data-source-registry.js +349 -0
- package/transaction/database-adapter.d.ts +44 -0
- package/transaction/database-adapter.js +240 -0
- package/transaction/decorators/entity-datasource.decorator.d.ts +62 -0
- package/transaction/decorators/entity-datasource.decorator.js +105 -0
- package/transaction/index.d.ts +14 -0
- package/transaction/index.js +57 -0
- package/transaction/logging-transactional.interceptor.d.ts +18 -0
- package/transaction/logging-transactional.interceptor.js +163 -0
- package/transaction/transaction-context.service.d.ts +137 -0
- package/transaction/transaction-context.service.js +411 -0
- package/transaction/transaction-manager.d.ts +230 -0
- package/transaction/transaction-manager.js +1001 -0
- package/transaction/transaction-synchronization.d.ts +171 -0
- package/transaction/transaction-synchronization.js +380 -0
- package/transaction/transaction.errors.d.ts +91 -0
- package/transaction/transaction.errors.js +206 -0
- package/transaction/transaction.module.d.ts +30 -0
- package/transaction/transaction.module.js +98 -0
- package/transaction/transactional.decorator.d.ts +82 -0
- package/transaction/transactional.decorator.js +319 -0
- package/transaction/typeorm-module-wrapper.d.ts +96 -0
- package/transaction/typeorm-module-wrapper.js +197 -0
- package/validators/file-mimetype.validator.d.ts +0 -2
- package/validators/file-mimetype.validator.js +4 -6
- package/validators/is-exists.validator.d.ts +2 -5
- package/validators/is-exists.validator.js +4 -6
- package/validators/is-unique.validator.d.ts +2 -5
- package/validators/is-unique.validator.js +6 -11
- package/shared/services/validator.service.d.ts +0 -3
- package/shared/services/validator.service.js +0 -20
- /package/shared/{serviceRegistryModule.d.ts → service-registry.module.d.ts} +0 -0
|
@@ -0,0 +1,349 @@
|
|
|
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 __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
15
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
16
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
17
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
18
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
19
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
20
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
var DataSourceRegistryService_1;
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.DataSourceRegistryService = void 0;
|
|
26
|
+
const common_1 = require("@nestjs/common");
|
|
27
|
+
const typeorm_1 = require("typeorm");
|
|
28
|
+
const transaction_context_service_1 = require("./transaction-context.service");
|
|
29
|
+
const database_adapter_1 = require("./database-adapter");
|
|
30
|
+
/**
|
|
31
|
+
* 数据源注册表管理器
|
|
32
|
+
* 负责管理所有动态注册的数据源
|
|
33
|
+
*/
|
|
34
|
+
let DataSourceRegistryService = DataSourceRegistryService_1 = class DataSourceRegistryService {
|
|
35
|
+
constructor(config) {
|
|
36
|
+
this.logger = new common_1.Logger(DataSourceRegistryService_1.name);
|
|
37
|
+
this.healthCheckInterval = null;
|
|
38
|
+
this.healthStatuses = new Map();
|
|
39
|
+
this.config = {
|
|
40
|
+
enableHealthCheck: false,
|
|
41
|
+
healthCheckInterval: 30000, // 30秒
|
|
42
|
+
connectionTimeout: 5000, // 5秒
|
|
43
|
+
maxReconnectAttempts: 3,
|
|
44
|
+
logLifecycleEvents: true,
|
|
45
|
+
autoCleanup: true,
|
|
46
|
+
};
|
|
47
|
+
if (config) {
|
|
48
|
+
this.config = Object.assign(Object.assign({}, this.config), config);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
onModuleInit() {
|
|
52
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
53
|
+
if (this.config.enableHealthCheck) {
|
|
54
|
+
this.startHealthCheck();
|
|
55
|
+
}
|
|
56
|
+
if (this.config.logLifecycleEvents) {
|
|
57
|
+
this.logger.log(`Initialized with config: ${JSON.stringify(this.config)}`);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
onModuleDestroy() {
|
|
62
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
63
|
+
if (this.healthCheckInterval) {
|
|
64
|
+
clearInterval(this.healthCheckInterval);
|
|
65
|
+
this.healthCheckInterval = null;
|
|
66
|
+
}
|
|
67
|
+
// 清理所有动态注册的数据源
|
|
68
|
+
yield this.cleanupAllDataSources();
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* 注册新的数据源
|
|
73
|
+
*/
|
|
74
|
+
registerDataSource(name, options, metadata) {
|
|
75
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
76
|
+
try {
|
|
77
|
+
// 创建数据源
|
|
78
|
+
const dataSource = new typeorm_1.DataSource(options);
|
|
79
|
+
// 初始化连接
|
|
80
|
+
if (!dataSource.isInitialized) {
|
|
81
|
+
yield dataSource.initialize();
|
|
82
|
+
}
|
|
83
|
+
// 注册到事务上下文服务
|
|
84
|
+
yield transaction_context_service_1.TransactionContextService.addDataSource(name, dataSource, {
|
|
85
|
+
options,
|
|
86
|
+
metadata,
|
|
87
|
+
});
|
|
88
|
+
// 初始化健康状态
|
|
89
|
+
if (this.config.enableHealthCheck) {
|
|
90
|
+
this.healthStatuses.set(name, {
|
|
91
|
+
name,
|
|
92
|
+
isConnected: true,
|
|
93
|
+
lastChecked: new Date(),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
if (this.config.logLifecycleEvents) {
|
|
97
|
+
this.logger.log(`Registered DataSource: ${name}`);
|
|
98
|
+
}
|
|
99
|
+
return dataSource;
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
this.logger.error(`Failed to register DataSource ${name}:`, error.stack);
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* 注册已存在的数据源
|
|
109
|
+
*/
|
|
110
|
+
registerExistingDataSource(name, dataSource, metadata) {
|
|
111
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
112
|
+
yield transaction_context_service_1.TransactionContextService.addDataSource(name, dataSource, {
|
|
113
|
+
metadata,
|
|
114
|
+
});
|
|
115
|
+
if (this.config.enableHealthCheck) {
|
|
116
|
+
this.healthStatuses.set(name, {
|
|
117
|
+
name,
|
|
118
|
+
isConnected: dataSource.isInitialized,
|
|
119
|
+
lastChecked: new Date(),
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* 注销数据源
|
|
126
|
+
*/
|
|
127
|
+
unregisterDataSource(name) {
|
|
128
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
129
|
+
const config = transaction_context_service_1.TransactionContextService.getDataSourceConfig(name);
|
|
130
|
+
if (config) {
|
|
131
|
+
// 关闭数据源连接
|
|
132
|
+
if (config.dataSource.isInitialized) {
|
|
133
|
+
yield config.dataSource.destroy();
|
|
134
|
+
}
|
|
135
|
+
// 从注册表中移除
|
|
136
|
+
yield transaction_context_service_1.TransactionContextService.removeDataSource(name);
|
|
137
|
+
this.healthStatuses.delete(name);
|
|
138
|
+
if (this.config.logLifecycleEvents) {
|
|
139
|
+
this.logger.log(`Unregistered DataSource: ${name}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* 获取数据源
|
|
146
|
+
*/
|
|
147
|
+
getDataSource(name) {
|
|
148
|
+
const config = transaction_context_service_1.TransactionContextService.getDataSourceConfig(name);
|
|
149
|
+
return (config === null || config === void 0 ? void 0 : config.dataSource) || null;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* 获取所有已注册的数据源名称
|
|
153
|
+
*/
|
|
154
|
+
getRegisteredDataSources() {
|
|
155
|
+
return transaction_context_service_1.TransactionContextService.getRegisteredDataSources();
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* 批量注册数据源
|
|
159
|
+
*/
|
|
160
|
+
registerDataSources(configs, options) {
|
|
161
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
162
|
+
const dataSources = [];
|
|
163
|
+
if (options === null || options === void 0 ? void 0 : options.parallel) {
|
|
164
|
+
// 并行注册
|
|
165
|
+
const promises = configs.map((config) => __awaiter(this, void 0, void 0, function* () {
|
|
166
|
+
const ds = yield this.registerDataSource(config.name, config.options, config.metadata);
|
|
167
|
+
return ds;
|
|
168
|
+
}));
|
|
169
|
+
try {
|
|
170
|
+
const results = yield Promise.all(promises);
|
|
171
|
+
dataSources.push(...results);
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
if (!(options === null || options === void 0 ? void 0 : options.continueOnError)) {
|
|
175
|
+
// 清理已注册的数据源
|
|
176
|
+
yield this.cleanupDataSources(dataSources.map((ds) => ds.options));
|
|
177
|
+
throw error;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
// 串行注册
|
|
183
|
+
for (const config of configs) {
|
|
184
|
+
try {
|
|
185
|
+
const ds = yield this.registerDataSource(config.name, config.options, config.metadata);
|
|
186
|
+
dataSources.push(ds);
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
if (!(options === null || options === void 0 ? void 0 : options.continueOnError)) {
|
|
190
|
+
// 清理已注册的数据源
|
|
191
|
+
yield this.cleanupDataSources(dataSources.map((ds) => ds.options));
|
|
192
|
+
throw error;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return dataSources;
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* 测试数据源连接
|
|
202
|
+
*/
|
|
203
|
+
testConnection(name) {
|
|
204
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
205
|
+
const config = transaction_context_service_1.TransactionContextService.getDataSourceConfig(name);
|
|
206
|
+
if (!config) {
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
const startTime = Date.now();
|
|
210
|
+
try {
|
|
211
|
+
// 使用数据库适配器执行健康检查
|
|
212
|
+
const isHealthy = yield database_adapter_1.DatabaseAdapter.healthCheck(config.dataSource);
|
|
213
|
+
const responseTime = Date.now() - startTime;
|
|
214
|
+
if (!isHealthy) {
|
|
215
|
+
throw new Error('Health check query failed');
|
|
216
|
+
}
|
|
217
|
+
// 更新健康状态
|
|
218
|
+
if (this.config.enableHealthCheck) {
|
|
219
|
+
this.healthStatuses.set(name, {
|
|
220
|
+
name,
|
|
221
|
+
isConnected: true,
|
|
222
|
+
lastChecked: new Date(),
|
|
223
|
+
responseTime,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
// 更新健康状态
|
|
230
|
+
if (this.config.enableHealthCheck) {
|
|
231
|
+
this.healthStatuses.set(name, {
|
|
232
|
+
name,
|
|
233
|
+
isConnected: false,
|
|
234
|
+
lastChecked: new Date(),
|
|
235
|
+
error: error.message,
|
|
236
|
+
responseTime: Date.now() - startTime,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* 获取所有数据源的健康状态
|
|
245
|
+
*/
|
|
246
|
+
getHealthStatuses() {
|
|
247
|
+
return new Map(this.healthStatuses);
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* 重新连接数据源
|
|
251
|
+
*/
|
|
252
|
+
reconnectDataSource(name) {
|
|
253
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
254
|
+
const config = transaction_context_service_1.TransactionContextService.getDataSourceConfig(name);
|
|
255
|
+
if (!config || !config.options) {
|
|
256
|
+
throw new Error(`Cannot reconnect: DataSource '${name}' has no connection options`);
|
|
257
|
+
}
|
|
258
|
+
try {
|
|
259
|
+
// 关闭现有连接
|
|
260
|
+
if (config.dataSource.isInitialized) {
|
|
261
|
+
yield config.dataSource.destroy();
|
|
262
|
+
}
|
|
263
|
+
// 重新初始化
|
|
264
|
+
yield config.dataSource.initialize();
|
|
265
|
+
// 测试连接
|
|
266
|
+
const isConnected = yield this.testConnection(name);
|
|
267
|
+
if (this.config.logLifecycleEvents) {
|
|
268
|
+
this.logger.log(`Reconnected DataSource: ${name}, Success: ${isConnected}`);
|
|
269
|
+
}
|
|
270
|
+
return isConnected;
|
|
271
|
+
}
|
|
272
|
+
catch (error) {
|
|
273
|
+
this.logger.error(`Failed to reconnect DataSource ${name}:`, error.stack);
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* 开始健康检查
|
|
280
|
+
*/
|
|
281
|
+
startHealthCheck() {
|
|
282
|
+
this.healthCheckInterval = setInterval(() => __awaiter(this, void 0, void 0, function* () {
|
|
283
|
+
var _a;
|
|
284
|
+
const dataSources = this.getRegisteredDataSources();
|
|
285
|
+
for (const name of dataSources) {
|
|
286
|
+
yield this.testConnection(name);
|
|
287
|
+
// 自动重连
|
|
288
|
+
const status = this.healthStatuses.get(name);
|
|
289
|
+
if (!(status === null || status === void 0 ? void 0 : status.isConnected) && this.config.autoCleanup) {
|
|
290
|
+
this.logger.warn(`DataSource ${name} is unhealthy, attempting reconnect...`);
|
|
291
|
+
let attempts = 0;
|
|
292
|
+
const maxAttempts = this.config.maxReconnectAttempts || 3;
|
|
293
|
+
while (attempts < maxAttempts) {
|
|
294
|
+
const reconnected = yield this.reconnectDataSource(name);
|
|
295
|
+
if (reconnected) {
|
|
296
|
+
break;
|
|
297
|
+
}
|
|
298
|
+
attempts++;
|
|
299
|
+
}
|
|
300
|
+
if (!((_a = this.healthStatuses.get(name)) === null || _a === void 0 ? void 0 : _a.isConnected)) {
|
|
301
|
+
this.logger.error(`Failed to reconnect DataSource ${name} after ${maxAttempts} attempts`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}), this.config.healthCheckInterval);
|
|
306
|
+
this.logger.log('Health check started');
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* 清理指定数据源
|
|
310
|
+
*/
|
|
311
|
+
cleanupDataSources(options) {
|
|
312
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
313
|
+
// 找到对应的数据源并清理
|
|
314
|
+
for (const opt of options) {
|
|
315
|
+
// 这里需要从配置反向查找数据源名称
|
|
316
|
+
// 简化实现:遍历所有已注册的数据源
|
|
317
|
+
const names = this.getRegisteredDataSources();
|
|
318
|
+
for (const name of names) {
|
|
319
|
+
const config = transaction_context_service_1.TransactionContextService.getDataSourceConfig(name);
|
|
320
|
+
if ((config === null || config === void 0 ? void 0 : config.dataSource.options) === opt) {
|
|
321
|
+
yield this.unregisterDataSource(name);
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* 清理所有动态数据源
|
|
330
|
+
*/
|
|
331
|
+
cleanupAllDataSources() {
|
|
332
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
333
|
+
const names = this.getRegisteredDataSources();
|
|
334
|
+
for (const name of names) {
|
|
335
|
+
yield this.unregisterDataSource(name);
|
|
336
|
+
}
|
|
337
|
+
if (this.config.logLifecycleEvents) {
|
|
338
|
+
this.logger.log('All dynamic DataSources cleaned up');
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
exports.DataSourceRegistryService = DataSourceRegistryService;
|
|
344
|
+
exports.DataSourceRegistryService = DataSourceRegistryService = DataSourceRegistryService_1 = __decorate([
|
|
345
|
+
(0, common_1.Injectable)(),
|
|
346
|
+
__param(0, (0, common_1.Optional)()),
|
|
347
|
+
__param(0, (0, common_1.Inject)('DATA_SOURCE_REGISTRY_CONFIG')),
|
|
348
|
+
__metadata("design:paramtypes", [Object])
|
|
349
|
+
], DataSourceRegistryService);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { DataSource, QueryRunner } from 'typeorm';
|
|
2
|
+
/**
|
|
3
|
+
* 数据库类型
|
|
4
|
+
*/
|
|
5
|
+
export type DatabaseType = 'mysql' | 'mariadb' | 'postgres' | 'cockroachdb' | 'sqlite' | 'better-sqlite3' | 'mssql' | 'oracle' | 'mongodb' | 'cordova' | 'react-native' | 'nativescript' | 'sqljs' | 'expo' | 'capacitor';
|
|
6
|
+
/**
|
|
7
|
+
* 数据库适配器
|
|
8
|
+
* 处理不同数据库的 SQL 语法差异
|
|
9
|
+
*/
|
|
10
|
+
export declare class DatabaseAdapter {
|
|
11
|
+
/**
|
|
12
|
+
* 获取数据库类型
|
|
13
|
+
*/
|
|
14
|
+
static getDatabaseType(dataSource: DataSource): DatabaseType;
|
|
15
|
+
/**
|
|
16
|
+
* 检查数据库是否支持 SAVEPOINT
|
|
17
|
+
*/
|
|
18
|
+
static supportsSavepoint(dataSource: DataSource): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* 创建保存点
|
|
21
|
+
*/
|
|
22
|
+
static createSavepoint(queryRunner: QueryRunner, savepointName: string): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* 回滚到保存点
|
|
25
|
+
*/
|
|
26
|
+
static rollbackToSavepoint(queryRunner: QueryRunner, savepointName: string): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* 释放保存点
|
|
29
|
+
*/
|
|
30
|
+
static releaseSavepoint(queryRunner: QueryRunner, savepointName: string): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* 执行健康检查查询
|
|
33
|
+
*/
|
|
34
|
+
static healthCheck(dataSource: DataSource): Promise<boolean>;
|
|
35
|
+
/**
|
|
36
|
+
* 获取数据库特定的信息
|
|
37
|
+
*/
|
|
38
|
+
static getDatabaseInfo(dataSource: DataSource): {
|
|
39
|
+
type: DatabaseType;
|
|
40
|
+
supportsSavepoint: boolean;
|
|
41
|
+
supportsNestedTransactions: boolean;
|
|
42
|
+
requiresReleaseSavepoint: boolean;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.DatabaseAdapter = void 0;
|
|
13
|
+
/**
|
|
14
|
+
* 数据库适配器
|
|
15
|
+
* 处理不同数据库的 SQL 语法差异
|
|
16
|
+
*/
|
|
17
|
+
class DatabaseAdapter {
|
|
18
|
+
/**
|
|
19
|
+
* 获取数据库类型
|
|
20
|
+
*/
|
|
21
|
+
static getDatabaseType(dataSource) {
|
|
22
|
+
return dataSource.options.type;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 检查数据库是否支持 SAVEPOINT
|
|
26
|
+
*/
|
|
27
|
+
static supportsSavepoint(dataSource) {
|
|
28
|
+
const type = this.getDatabaseType(dataSource);
|
|
29
|
+
// MongoDB 不支持传统事务和 SAVEPOINT
|
|
30
|
+
if (type === 'mongodb') {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
// 其他关系型数据库都支持 SAVEPOINT
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 创建保存点
|
|
38
|
+
*/
|
|
39
|
+
static createSavepoint(queryRunner, savepointName) {
|
|
40
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
41
|
+
// 检查 queryRunner.connection 是否存在
|
|
42
|
+
if (!queryRunner.connection) {
|
|
43
|
+
// 如果没有 connection,使用标准 SQL 语法(最常见的情况)
|
|
44
|
+
yield queryRunner.query(`SAVEPOINT ${savepointName}`);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const type = this.getDatabaseType(queryRunner.connection);
|
|
48
|
+
switch (type) {
|
|
49
|
+
case 'mysql':
|
|
50
|
+
case 'mariadb':
|
|
51
|
+
case 'postgres':
|
|
52
|
+
case 'cockroachdb':
|
|
53
|
+
case 'sqlite':
|
|
54
|
+
case 'better-sqlite3':
|
|
55
|
+
case 'sqljs':
|
|
56
|
+
case 'cordova':
|
|
57
|
+
case 'react-native':
|
|
58
|
+
case 'nativescript':
|
|
59
|
+
case 'expo':
|
|
60
|
+
case 'capacitor':
|
|
61
|
+
// 标准 SQL 语法
|
|
62
|
+
yield queryRunner.query(`SAVEPOINT ${savepointName}`);
|
|
63
|
+
break;
|
|
64
|
+
case 'mssql':
|
|
65
|
+
// SQL Server 使用 SAVE TRANSACTION
|
|
66
|
+
yield queryRunner.query(`SAVE TRANSACTION ${savepointName}`);
|
|
67
|
+
break;
|
|
68
|
+
case 'oracle':
|
|
69
|
+
// Oracle 使用标准 SAVEPOINT 语法
|
|
70
|
+
yield queryRunner.query(`SAVEPOINT ${savepointName}`);
|
|
71
|
+
break;
|
|
72
|
+
case 'mongodb':
|
|
73
|
+
throw new Error('MongoDB does not support SAVEPOINT. Use transactions instead.');
|
|
74
|
+
default:
|
|
75
|
+
// 对于未知的数据库类型,尝试使用标准 SQL 语法
|
|
76
|
+
yield queryRunner.query(`SAVEPOINT ${savepointName}`);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* 回滚到保存点
|
|
82
|
+
*/
|
|
83
|
+
static rollbackToSavepoint(queryRunner, savepointName) {
|
|
84
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
85
|
+
// 检查 queryRunner.connection 是否存在
|
|
86
|
+
if (!queryRunner.connection) {
|
|
87
|
+
// 如果没有 connection,使用标准 SQL 语法(最常见的情况)
|
|
88
|
+
yield queryRunner.query(`ROLLBACK TO SAVEPOINT ${savepointName}`);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const type = this.getDatabaseType(queryRunner.connection);
|
|
92
|
+
switch (type) {
|
|
93
|
+
case 'mysql':
|
|
94
|
+
case 'mariadb':
|
|
95
|
+
case 'postgres':
|
|
96
|
+
case 'cockroachdb':
|
|
97
|
+
case 'sqlite':
|
|
98
|
+
case 'better-sqlite3':
|
|
99
|
+
case 'sqljs':
|
|
100
|
+
case 'cordova':
|
|
101
|
+
case 'react-native':
|
|
102
|
+
case 'nativescript':
|
|
103
|
+
case 'expo':
|
|
104
|
+
case 'capacitor':
|
|
105
|
+
case 'oracle':
|
|
106
|
+
// 标准 SQL 语法
|
|
107
|
+
yield queryRunner.query(`ROLLBACK TO SAVEPOINT ${savepointName}`);
|
|
108
|
+
break;
|
|
109
|
+
case 'mssql':
|
|
110
|
+
// SQL Server 使用 ROLLBACK TRANSACTION
|
|
111
|
+
yield queryRunner.query(`ROLLBACK TRANSACTION ${savepointName}`);
|
|
112
|
+
break;
|
|
113
|
+
case 'mongodb':
|
|
114
|
+
throw new Error('MongoDB does not support SAVEPOINT. Use transactions instead.');
|
|
115
|
+
default:
|
|
116
|
+
// 对于未知的数据库类型,尝试使用标准 SQL 语法
|
|
117
|
+
yield queryRunner.query(`ROLLBACK TO SAVEPOINT ${savepointName}`);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* 释放保存点
|
|
123
|
+
*/
|
|
124
|
+
static releaseSavepoint(queryRunner, savepointName) {
|
|
125
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
126
|
+
// 检查 queryRunner.connection 是否存在
|
|
127
|
+
if (!queryRunner.connection) {
|
|
128
|
+
// 如果没有 connection,尝试使用标准 SQL 语法
|
|
129
|
+
try {
|
|
130
|
+
yield queryRunner.query(`RELEASE SAVEPOINT ${savepointName}`);
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
// 静默失败,因为某些数据库不支持 RELEASE
|
|
134
|
+
}
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const type = this.getDatabaseType(queryRunner.connection);
|
|
138
|
+
switch (type) {
|
|
139
|
+
case 'mysql':
|
|
140
|
+
case 'mariadb':
|
|
141
|
+
case 'postgres':
|
|
142
|
+
case 'cockroachdb':
|
|
143
|
+
case 'sqlite':
|
|
144
|
+
case 'better-sqlite3':
|
|
145
|
+
case 'sqljs':
|
|
146
|
+
case 'cordova':
|
|
147
|
+
case 'react-native':
|
|
148
|
+
case 'nativescript':
|
|
149
|
+
case 'expo':
|
|
150
|
+
case 'capacitor':
|
|
151
|
+
// 标准 SQL 语法
|
|
152
|
+
yield queryRunner.query(`RELEASE SAVEPOINT ${savepointName}`);
|
|
153
|
+
break;
|
|
154
|
+
case 'oracle':
|
|
155
|
+
// Oracle 不支持 RELEASE SAVEPOINT,保存点会在提交时自动释放
|
|
156
|
+
// 不执行任何操作
|
|
157
|
+
break;
|
|
158
|
+
case 'mssql':
|
|
159
|
+
// SQL Server 不支持 RELEASE,保存点会在提交或回滚时自动清理
|
|
160
|
+
// 不执行任何操作
|
|
161
|
+
break;
|
|
162
|
+
case 'mongodb':
|
|
163
|
+
// MongoDB 不支持
|
|
164
|
+
break;
|
|
165
|
+
default:
|
|
166
|
+
// 对于未知的数据库类型,尝试使用标准 SQL 语法
|
|
167
|
+
// 如果失败也不抛出错误,因为某些数据库不需要显式释放
|
|
168
|
+
try {
|
|
169
|
+
yield queryRunner.query(`RELEASE SAVEPOINT ${savepointName}`);
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
// 静默失败,因为某些数据库不支持 RELEASE
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* 执行健康检查查询
|
|
179
|
+
*/
|
|
180
|
+
static healthCheck(dataSource) {
|
|
181
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
182
|
+
const type = this.getDatabaseType(dataSource);
|
|
183
|
+
try {
|
|
184
|
+
switch (type) {
|
|
185
|
+
case 'mysql':
|
|
186
|
+
case 'mariadb':
|
|
187
|
+
yield dataSource.query('SELECT 1');
|
|
188
|
+
break;
|
|
189
|
+
case 'postgres':
|
|
190
|
+
case 'cockroachdb':
|
|
191
|
+
yield dataSource.query('SELECT 1');
|
|
192
|
+
break;
|
|
193
|
+
case 'mssql':
|
|
194
|
+
yield dataSource.query('SELECT 1');
|
|
195
|
+
break;
|
|
196
|
+
case 'oracle':
|
|
197
|
+
yield dataSource.query('SELECT 1 FROM DUAL');
|
|
198
|
+
break;
|
|
199
|
+
case 'sqlite':
|
|
200
|
+
case 'better-sqlite3':
|
|
201
|
+
case 'sqljs':
|
|
202
|
+
case 'cordova':
|
|
203
|
+
case 'react-native':
|
|
204
|
+
case 'nativescript':
|
|
205
|
+
case 'expo':
|
|
206
|
+
case 'capacitor':
|
|
207
|
+
yield dataSource.query('SELECT 1');
|
|
208
|
+
break;
|
|
209
|
+
case 'mongodb':
|
|
210
|
+
// MongoDB 使用不同的健康检查方式
|
|
211
|
+
yield dataSource.query('{ ping: 1 }');
|
|
212
|
+
break;
|
|
213
|
+
default:
|
|
214
|
+
// 默认使用 SELECT 1
|
|
215
|
+
yield dataSource.query('SELECT 1');
|
|
216
|
+
}
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* 获取数据库特定的信息
|
|
226
|
+
*/
|
|
227
|
+
static getDatabaseInfo(dataSource) {
|
|
228
|
+
const type = this.getDatabaseType(dataSource);
|
|
229
|
+
const supportsSavepoint = this.supportsSavepoint(dataSource);
|
|
230
|
+
// 检查是否需要显式释放 SAVEPOINT
|
|
231
|
+
const requiresReleaseSavepoint = !['oracle', 'mssql', 'mongodb'].includes(type);
|
|
232
|
+
return {
|
|
233
|
+
type,
|
|
234
|
+
supportsSavepoint,
|
|
235
|
+
supportsNestedTransactions: supportsSavepoint,
|
|
236
|
+
requiresReleaseSavepoint,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
exports.DatabaseAdapter = DatabaseAdapter;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
/**
|
|
3
|
+
* Entity 数据源装饰器
|
|
4
|
+
* 用于指定 Entity 应该使用哪个数据源
|
|
5
|
+
*/
|
|
6
|
+
export declare const ENTITY_DATASOURCE_METADATA_KEY = "entity:datasource";
|
|
7
|
+
/**
|
|
8
|
+
* 数据源装饰器 - 为 Entity 指定数据源
|
|
9
|
+
*
|
|
10
|
+
* @param dataSourceName 数据源名称
|
|
11
|
+
*
|
|
12
|
+
* 使用示例:
|
|
13
|
+
* ```typescript
|
|
14
|
+
* @Entity('users')
|
|
15
|
+
* @DataSource('user_db')
|
|
16
|
+
* export class User {
|
|
17
|
+
* @PrimaryGeneratedColumn()
|
|
18
|
+
* id: number;
|
|
19
|
+
*
|
|
20
|
+
* @Column()
|
|
21
|
+
* name: string;
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function DataSource(dataSourceName: string): ClassDecorator;
|
|
26
|
+
/**
|
|
27
|
+
* 获取 Entity 的数据源名称
|
|
28
|
+
* @param entityClass Entity 类或构造函数
|
|
29
|
+
* @returns 数据源名称,如果未指定则返回 null
|
|
30
|
+
*/
|
|
31
|
+
export declare function getEntityDataSource(entityClass: any): string | null;
|
|
32
|
+
/**
|
|
33
|
+
* 检查 Entity 是否指定了数据源
|
|
34
|
+
* @param entityClass Entity 类或构造函数
|
|
35
|
+
* @returns 是否指定了数据源
|
|
36
|
+
*/
|
|
37
|
+
export declare function hasEntityDataSource(entityClass: any): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* 带数据源的 Entity 基类
|
|
40
|
+
* 继承这个基类的 Entity 可以通过实现 useDataSource 方法动态指定数据源
|
|
41
|
+
*/
|
|
42
|
+
export declare abstract class BaseEntityWithDataSource {
|
|
43
|
+
/**
|
|
44
|
+
* 子类可以重写此方法来动态指定数据源
|
|
45
|
+
* @returns 数据源名称
|
|
46
|
+
*/
|
|
47
|
+
static useDataSource?(): string;
|
|
48
|
+
/**
|
|
49
|
+
* 实例方法版本,用于动态获取数据源
|
|
50
|
+
* @returns 数据源名称
|
|
51
|
+
*/
|
|
52
|
+
getDataSource?(): string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 动态数据源装饰器
|
|
56
|
+
* 标记 Entity 使用动态数据源(通过 useDataSource 方法指定)
|
|
57
|
+
*/
|
|
58
|
+
export declare function DynamicDataSource(): ClassDecorator;
|
|
59
|
+
/**
|
|
60
|
+
* 检查 Entity 是否使用动态数据源
|
|
61
|
+
*/
|
|
62
|
+
export declare function isDynamicDataSourceEntity(entityClass: any): boolean;
|