@nest-omni/core 4.1.3-10 → 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 +42 -2
- 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/audit-controller.decorator.d.ts +1 -1
- package/audit/decorators/audit-controller.decorator.js +2 -2
- package/audit/decorators/entity-audit.decorator.d.ts +78 -2
- package/audit/decorators/entity-audit.decorator.js +145 -4
- package/audit/decorators/index.d.ts +2 -0
- package/audit/decorators/index.js +2 -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 +8 -0
- package/audit/entities/entity-audit-log.entity.js +54 -2
- package/audit/entities/entity-transaction.entity.d.ts +8 -2
- package/audit/entities/entity-transaction.entity.js +39 -3
- package/audit/entities/index.d.ts +3 -0
- package/audit/entities/index.js +3 -0
- package/audit/entities/manual-operation-log.entity.js +8 -1
- package/audit/enums/audit.enums.d.ts +22 -6
- package/audit/enums/audit.enums.js +27 -9
- package/audit/index.d.ts +4 -1
- package/audit/index.js +25 -2
- 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 +145 -2
- 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 +174 -4
- package/audit/services/entity-audit.service.js +515 -14
- package/audit/services/index.d.ts +3 -0
- package/audit/services/index.js +3 -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/http-client/http-client.module.js +1 -5
- package/index.d.ts +3 -1
- package/index.js +4 -1
- package/package.json +4 -5
- package/redis-lock/lock-heartbeat.service.d.ts +2 -2
- package/redis-lock/lock-heartbeat.service.js +4 -4
- package/redis-lock/redis-lock.service.d.ts +18 -0
- package/redis-lock/redis-lock.service.js +38 -8
- package/setup/bootstrap.setup.d.ts +1 -0
- package/setup/bootstrap.setup.js +1 -0
- package/setup/schedule.decorator.js +18 -8
- package/shared/index.d.ts +1 -1
- package/shared/index.js +1 -1
- package/shared/{serviceRegistryModule.js → service-registry.module.js} +9 -16
- 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,137 @@
|
|
|
1
|
+
import { OnModuleInit } from '@nestjs/common';
|
|
2
|
+
import { DataSource, EntityManager, DataSourceOptions } from 'typeorm';
|
|
3
|
+
import { ModuleRef } from '@nestjs/core';
|
|
4
|
+
/**
|
|
5
|
+
* 事务上下文信息
|
|
6
|
+
*/
|
|
7
|
+
interface TransactionContext {
|
|
8
|
+
dataSourceName: string;
|
|
9
|
+
entityManager: EntityManager;
|
|
10
|
+
dataSource: DataSource;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 动态注册的数据源配置
|
|
14
|
+
*/
|
|
15
|
+
export interface DynamicDataSourceConfig {
|
|
16
|
+
name: string;
|
|
17
|
+
dataSource: DataSource;
|
|
18
|
+
options?: DataSourceOptions;
|
|
19
|
+
metadata?: Record<string, any>;
|
|
20
|
+
createdAt: Date;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 事务上下文管理器
|
|
24
|
+
* 使用 RequestScope 确保每个请求都有独立的事务上下文
|
|
25
|
+
*/
|
|
26
|
+
export declare class TransactionContextService implements OnModuleInit {
|
|
27
|
+
private readonly moduleRef;
|
|
28
|
+
private readonly config?;
|
|
29
|
+
private static readonly logger;
|
|
30
|
+
private readonly contextMap;
|
|
31
|
+
constructor(moduleRef: ModuleRef, config?: {
|
|
32
|
+
defaultDataSource?: string;
|
|
33
|
+
enableDynamicRegistration?: boolean;
|
|
34
|
+
logDataSourceRegistration?: boolean;
|
|
35
|
+
});
|
|
36
|
+
onModuleInit(): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* 获取当前请求的事务上下文服务
|
|
39
|
+
*/
|
|
40
|
+
static getCurrent(): TransactionContextService | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* 获取当前请求的数据源
|
|
43
|
+
* 方便其他模块快速访问数据源
|
|
44
|
+
* @param dataSourceName 数据源名称,默认为 'default'
|
|
45
|
+
* @returns DataSource 实例
|
|
46
|
+
*/
|
|
47
|
+
static getDataSource(dataSourceName?: string): DataSource;
|
|
48
|
+
/**
|
|
49
|
+
* 设置事务上下文
|
|
50
|
+
*/
|
|
51
|
+
setContext(dataSourceName: string, entityManager: EntityManager): void;
|
|
52
|
+
/**
|
|
53
|
+
* 获取事务上下文中的 EntityManager
|
|
54
|
+
*/
|
|
55
|
+
getEntityManager(dataSourceName?: string): EntityManager | null;
|
|
56
|
+
/**
|
|
57
|
+
* 获取事务上下文中的 DataSource
|
|
58
|
+
* 如果上下文中没有,则尝试从 TypeORM 模块或全局注册表获取
|
|
59
|
+
*/
|
|
60
|
+
getDataSource(dataSourceName?: string): DataSource | null;
|
|
61
|
+
/**
|
|
62
|
+
* 检查是否在事务中
|
|
63
|
+
*/
|
|
64
|
+
isInTransaction(dataSourceName?: string): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* 获取所有活跃的事务上下文
|
|
67
|
+
*/
|
|
68
|
+
getAllActiveContexts(): Map<string, TransactionContext>;
|
|
69
|
+
/**
|
|
70
|
+
* 清理所有事务上下文
|
|
71
|
+
*/
|
|
72
|
+
clearContext(): void;
|
|
73
|
+
/**
|
|
74
|
+
* 清理指定数据源的事务上下文
|
|
75
|
+
*/
|
|
76
|
+
clearContextForDataSource(dataSourceName: string): void;
|
|
77
|
+
/**
|
|
78
|
+
* 执行带事务的操作
|
|
79
|
+
* 如果已在事务中,使用现有的事务管理器
|
|
80
|
+
* 否则创建新事务
|
|
81
|
+
*/
|
|
82
|
+
executeInTransaction<T>(dataSourceName: string, operation: (entityManager: EntityManager) => Promise<T>, isolationLevel?: any): Promise<T>;
|
|
83
|
+
/**
|
|
84
|
+
* 获取 DataSource 实例
|
|
85
|
+
*/
|
|
86
|
+
private getDataSourceInstance;
|
|
87
|
+
/**
|
|
88
|
+
* 动态注册数据源
|
|
89
|
+
*/
|
|
90
|
+
static addDataSource(name: string, dataSource: DataSource, options?: {
|
|
91
|
+
options?: DataSourceOptions;
|
|
92
|
+
metadata?: Record<string, any>;
|
|
93
|
+
replaceExisting?: boolean;
|
|
94
|
+
}): Promise<void>;
|
|
95
|
+
/**
|
|
96
|
+
* 移除动态注册的数据源
|
|
97
|
+
*/
|
|
98
|
+
static removeDataSource(name: string): Promise<void>;
|
|
99
|
+
/**
|
|
100
|
+
* 获取所有已注册的数据源名称
|
|
101
|
+
*/
|
|
102
|
+
static getRegisteredDataSources(): string[];
|
|
103
|
+
/**
|
|
104
|
+
* 获取动态数据源的配置
|
|
105
|
+
*/
|
|
106
|
+
static getDataSourceConfig(name: string): DynamicDataSourceConfig | undefined;
|
|
107
|
+
/**
|
|
108
|
+
* 检查数据源是否已注册
|
|
109
|
+
*/
|
|
110
|
+
static isDataSourceRegistered(name: string): boolean;
|
|
111
|
+
/**
|
|
112
|
+
* 批量注册数据源
|
|
113
|
+
*/
|
|
114
|
+
static addDataSources(dataSources: Array<{
|
|
115
|
+
name: string;
|
|
116
|
+
dataSource: DataSource;
|
|
117
|
+
options?: DataSourceOptions;
|
|
118
|
+
metadata?: Record<string, any>;
|
|
119
|
+
}>, options?: {
|
|
120
|
+
replaceExisting?: boolean;
|
|
121
|
+
continueOnError?: boolean;
|
|
122
|
+
}): Promise<void>;
|
|
123
|
+
/**
|
|
124
|
+
* 清理全局注册表(用于测试)
|
|
125
|
+
*/
|
|
126
|
+
static clearGlobalRegistry(): void;
|
|
127
|
+
/**
|
|
128
|
+
* 获取默认数据源名称
|
|
129
|
+
*/
|
|
130
|
+
getDefaultDataSourceName(): string;
|
|
131
|
+
/**
|
|
132
|
+
* 跨多个数据源执行分布式事务
|
|
133
|
+
* 使用两阶段提交模式
|
|
134
|
+
*/
|
|
135
|
+
executeDistributedTransaction<T>(dataSourceNames: string[], operation: (entityManagers: Map<string, EntityManager>) => Promise<T>): Promise<T>;
|
|
136
|
+
}
|
|
137
|
+
export {};
|
|
@@ -0,0 +1,411 @@
|
|
|
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 TransactionContextService_1;
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
exports.TransactionContextService = void 0;
|
|
26
|
+
const common_1 = require("@nestjs/common");
|
|
27
|
+
const core_1 = require("@nestjs/core");
|
|
28
|
+
const typeorm_1 = require("@nestjs/typeorm");
|
|
29
|
+
const async_hooks_1 = require("async_hooks");
|
|
30
|
+
/**
|
|
31
|
+
* 全局数据源注册表
|
|
32
|
+
* 在模块初始化时设置,跨请求共享
|
|
33
|
+
*/
|
|
34
|
+
class GlobalDataSourceRegistry {
|
|
35
|
+
static setConfig(config) {
|
|
36
|
+
GlobalDataSourceRegistry.config = config;
|
|
37
|
+
}
|
|
38
|
+
static getConfig() {
|
|
39
|
+
return GlobalDataSourceRegistry.config;
|
|
40
|
+
}
|
|
41
|
+
static addDataSource(name, config) {
|
|
42
|
+
GlobalDataSourceRegistry.dataSources.set(name, config);
|
|
43
|
+
}
|
|
44
|
+
static removeDataSource(name) {
|
|
45
|
+
GlobalDataSourceRegistry.dataSources.delete(name);
|
|
46
|
+
}
|
|
47
|
+
static getDataSource(name) {
|
|
48
|
+
return GlobalDataSourceRegistry.dataSources.get(name);
|
|
49
|
+
}
|
|
50
|
+
static getAllDataSources() {
|
|
51
|
+
return Array.from(GlobalDataSourceRegistry.dataSources.keys());
|
|
52
|
+
}
|
|
53
|
+
static hasDataSource(name) {
|
|
54
|
+
return GlobalDataSourceRegistry.dataSources.has(name);
|
|
55
|
+
}
|
|
56
|
+
static clear() {
|
|
57
|
+
GlobalDataSourceRegistry.dataSources.clear();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
GlobalDataSourceRegistry.dataSources = new Map();
|
|
61
|
+
GlobalDataSourceRegistry.config = {};
|
|
62
|
+
/**
|
|
63
|
+
* AsyncLocalStorage 实例
|
|
64
|
+
* 用于在每个请求上下文中存储 TransactionContextService
|
|
65
|
+
*/
|
|
66
|
+
const asyncLocalStorage = new async_hooks_1.AsyncLocalStorage();
|
|
67
|
+
/**
|
|
68
|
+
* 事务上下文管理器
|
|
69
|
+
* 使用 RequestScope 确保每个请求都有独立的事务上下文
|
|
70
|
+
*/
|
|
71
|
+
let TransactionContextService = TransactionContextService_1 = class TransactionContextService {
|
|
72
|
+
constructor(moduleRef, config) {
|
|
73
|
+
this.moduleRef = moduleRef;
|
|
74
|
+
this.config = config;
|
|
75
|
+
this.contextMap = new Map();
|
|
76
|
+
}
|
|
77
|
+
onModuleInit() {
|
|
78
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
79
|
+
// 将配置存储到全局注册表
|
|
80
|
+
GlobalDataSourceRegistry.setConfig(this.config);
|
|
81
|
+
// 将当前实例存储到 AsyncLocalStorage
|
|
82
|
+
asyncLocalStorage.enterWith(this);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* 获取当前请求的事务上下文服务
|
|
87
|
+
*/
|
|
88
|
+
static getCurrent() {
|
|
89
|
+
return asyncLocalStorage.getStore();
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 获取当前请求的数据源
|
|
93
|
+
* 方便其他模块快速访问数据源
|
|
94
|
+
* @param dataSourceName 数据源名称,默认为 'default'
|
|
95
|
+
* @returns DataSource 实例
|
|
96
|
+
*/
|
|
97
|
+
static getDataSource(dataSourceName = 'default') {
|
|
98
|
+
const currentService = this.getCurrent();
|
|
99
|
+
if (currentService) {
|
|
100
|
+
// 从当前服务获取数据源
|
|
101
|
+
const dataSource = currentService.getDataSource(dataSourceName);
|
|
102
|
+
if (dataSource) {
|
|
103
|
+
return dataSource;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// 如果当前服务中没有,尝试从全局注册表获取
|
|
107
|
+
const globalDataSource = GlobalDataSourceRegistry.getDataSource(dataSourceName);
|
|
108
|
+
if (globalDataSource) {
|
|
109
|
+
return globalDataSource.dataSource;
|
|
110
|
+
}
|
|
111
|
+
throw new Error(`DataSource '${dataSourceName}' not found. Please ensure it is registered ` +
|
|
112
|
+
`either through TypeOrmModule or addDataSource(), and that the method is ` +
|
|
113
|
+
`called within a request context.`);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* 设置事务上下文
|
|
117
|
+
*/
|
|
118
|
+
setContext(dataSourceName, entityManager) {
|
|
119
|
+
const dataSource = this.moduleRef.get((0, typeorm_1.getDataSourceToken)(dataSourceName), {
|
|
120
|
+
strict: false,
|
|
121
|
+
});
|
|
122
|
+
this.contextMap.set(dataSourceName, {
|
|
123
|
+
dataSourceName,
|
|
124
|
+
entityManager,
|
|
125
|
+
dataSource,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* 获取事务上下文中的 EntityManager
|
|
130
|
+
*/
|
|
131
|
+
getEntityManager(dataSourceName = 'default') {
|
|
132
|
+
const context = this.contextMap.get(dataSourceName);
|
|
133
|
+
return (context === null || context === void 0 ? void 0 : context.entityManager) || null;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* 获取事务上下文中的 DataSource
|
|
137
|
+
* 如果上下文中没有,则尝试从 TypeORM 模块或全局注册表获取
|
|
138
|
+
*/
|
|
139
|
+
getDataSource(dataSourceName = 'default') {
|
|
140
|
+
// 1. 首先检查事务上下文
|
|
141
|
+
const context = this.contextMap.get(dataSourceName);
|
|
142
|
+
if (context === null || context === void 0 ? void 0 : context.dataSource) {
|
|
143
|
+
return context.dataSource;
|
|
144
|
+
}
|
|
145
|
+
// 2. 检查全局注册表中的动态数据源
|
|
146
|
+
const dynamicDataSource = GlobalDataSourceRegistry.getDataSource(dataSourceName);
|
|
147
|
+
if (dynamicDataSource) {
|
|
148
|
+
return dynamicDataSource.dataSource;
|
|
149
|
+
}
|
|
150
|
+
// 3. 尝试从 TypeORM 模块获取
|
|
151
|
+
try {
|
|
152
|
+
const dataSource = this.moduleRef.get((0, typeorm_1.getDataSourceToken)(dataSourceName), {
|
|
153
|
+
strict: false,
|
|
154
|
+
});
|
|
155
|
+
if (dataSource) {
|
|
156
|
+
return dataSource;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
// 忽略未找到数据源的错误
|
|
161
|
+
}
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* 检查是否在事务中
|
|
166
|
+
*/
|
|
167
|
+
isInTransaction(dataSourceName = 'default') {
|
|
168
|
+
var _a, _b;
|
|
169
|
+
const context = this.contextMap.get(dataSourceName);
|
|
170
|
+
return ((_b = (_a = context === null || context === void 0 ? void 0 : context.entityManager) === null || _a === void 0 ? void 0 : _a.queryRunner) === null || _b === void 0 ? void 0 : _b.isTransactionActive) || false;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* 获取所有活跃的事务上下文
|
|
174
|
+
*/
|
|
175
|
+
getAllActiveContexts() {
|
|
176
|
+
var _a, _b;
|
|
177
|
+
const activeContexts = new Map();
|
|
178
|
+
for (const [name, context] of this.contextMap) {
|
|
179
|
+
if ((_b = (_a = context.entityManager) === null || _a === void 0 ? void 0 : _a.queryRunner) === null || _b === void 0 ? void 0 : _b.isTransactionActive) {
|
|
180
|
+
activeContexts.set(name, context);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return activeContexts;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* 清理所有事务上下文
|
|
187
|
+
*/
|
|
188
|
+
clearContext() {
|
|
189
|
+
this.contextMap.clear();
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* 清理指定数据源的事务上下文
|
|
193
|
+
*/
|
|
194
|
+
clearContextForDataSource(dataSourceName) {
|
|
195
|
+
this.contextMap.delete(dataSourceName);
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* 执行带事务的操作
|
|
199
|
+
* 如果已在事务中,使用现有的事务管理器
|
|
200
|
+
* 否则创建新事务
|
|
201
|
+
*/
|
|
202
|
+
executeInTransaction(dataSourceName, operation, isolationLevel) {
|
|
203
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
204
|
+
var _a;
|
|
205
|
+
const existingEntityManager = this.getEntityManager(dataSourceName);
|
|
206
|
+
if (existingEntityManager && ((_a = existingEntityManager.queryRunner) === null || _a === void 0 ? void 0 : _a.isTransactionActive)) {
|
|
207
|
+
// 已在事务中,直接使用现有的 EntityManager
|
|
208
|
+
return operation(existingEntityManager);
|
|
209
|
+
}
|
|
210
|
+
// 不在事务中,创建新事务
|
|
211
|
+
const dataSource = yield this.getDataSourceInstance(dataSourceName);
|
|
212
|
+
return yield dataSource.transaction((entityManager) => __awaiter(this, void 0, void 0, function* () {
|
|
213
|
+
this.setContext(dataSourceName, entityManager);
|
|
214
|
+
try {
|
|
215
|
+
const result = yield operation(entityManager);
|
|
216
|
+
return result;
|
|
217
|
+
}
|
|
218
|
+
finally {
|
|
219
|
+
this.clearContextForDataSource(dataSourceName);
|
|
220
|
+
}
|
|
221
|
+
}));
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* 获取 DataSource 实例
|
|
226
|
+
*/
|
|
227
|
+
getDataSourceInstance(dataSourceName) {
|
|
228
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
229
|
+
// 首先检查全局注册表中的动态数据源
|
|
230
|
+
const dynamicDataSource = GlobalDataSourceRegistry.getDataSource(dataSourceName);
|
|
231
|
+
if (dynamicDataSource) {
|
|
232
|
+
return dynamicDataSource.dataSource;
|
|
233
|
+
}
|
|
234
|
+
// 然后检查 TypeORM 模块注册的数据源
|
|
235
|
+
try {
|
|
236
|
+
const dataSource = this.moduleRef.get((0, typeorm_1.getDataSourceToken)(dataSourceName), {
|
|
237
|
+
strict: false,
|
|
238
|
+
});
|
|
239
|
+
if (dataSource) {
|
|
240
|
+
return dataSource;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
catch (error) {
|
|
244
|
+
// 忽略未找到数据源的错误,继续检查其他地方
|
|
245
|
+
}
|
|
246
|
+
throw new Error(`DataSource '${dataSourceName}' not found. Please ensure it is registered either through TypeOrmModule or addDataSource()`);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* 动态注册数据源
|
|
251
|
+
*/
|
|
252
|
+
static addDataSource(name, dataSource, options) {
|
|
253
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
254
|
+
const config = GlobalDataSourceRegistry.getConfig();
|
|
255
|
+
// 检查是否允许动态注册
|
|
256
|
+
if ((config === null || config === void 0 ? void 0 : config.enableDynamicRegistration) === false) {
|
|
257
|
+
throw new Error('Dynamic data source registration is disabled');
|
|
258
|
+
}
|
|
259
|
+
// 检查是否已存在
|
|
260
|
+
if (GlobalDataSourceRegistry.hasDataSource(name) && !(options === null || options === void 0 ? void 0 : options.replaceExisting)) {
|
|
261
|
+
throw new Error(`DataSource '${name}' already registered. Use replaceExisting: true to replace.`);
|
|
262
|
+
}
|
|
263
|
+
// 验证数据源
|
|
264
|
+
if (!dataSource || !dataSource.isInitialized) {
|
|
265
|
+
throw new Error(`DataSource '${name}' must be initialized before registration`);
|
|
266
|
+
}
|
|
267
|
+
// 注册数据源
|
|
268
|
+
const dsConfig = {
|
|
269
|
+
name,
|
|
270
|
+
dataSource,
|
|
271
|
+
options: options === null || options === void 0 ? void 0 : options.options,
|
|
272
|
+
metadata: options === null || options === void 0 ? void 0 : options.metadata,
|
|
273
|
+
createdAt: new Date(),
|
|
274
|
+
};
|
|
275
|
+
GlobalDataSourceRegistry.addDataSource(name, dsConfig);
|
|
276
|
+
// 记录日志
|
|
277
|
+
if ((config === null || config === void 0 ? void 0 : config.logDataSourceRegistration) !== false) {
|
|
278
|
+
TransactionContextService_1.logger.log(`Registered dynamic DataSource: ${name}`);
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* 移除动态注册的数据源
|
|
284
|
+
*/
|
|
285
|
+
static removeDataSource(name) {
|
|
286
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
287
|
+
const removed = GlobalDataSourceRegistry.hasDataSource(name);
|
|
288
|
+
if (removed) {
|
|
289
|
+
GlobalDataSourceRegistry.removeDataSource(name);
|
|
290
|
+
// 清理当前请求中该数据源的事务上下文
|
|
291
|
+
const currentService = asyncLocalStorage.getStore();
|
|
292
|
+
if (currentService) {
|
|
293
|
+
currentService.clearContextForDataSource(name);
|
|
294
|
+
}
|
|
295
|
+
TransactionContextService_1.logger.log(`Removed dynamic DataSource: ${name}`);
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* 获取所有已注册的数据源名称
|
|
301
|
+
*/
|
|
302
|
+
static getRegisteredDataSources() {
|
|
303
|
+
return GlobalDataSourceRegistry.getAllDataSources();
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* 获取动态数据源的配置
|
|
307
|
+
*/
|
|
308
|
+
static getDataSourceConfig(name) {
|
|
309
|
+
return GlobalDataSourceRegistry.getDataSource(name);
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* 检查数据源是否已注册
|
|
313
|
+
*/
|
|
314
|
+
static isDataSourceRegistered(name) {
|
|
315
|
+
return GlobalDataSourceRegistry.hasDataSource(name);
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* 批量注册数据源
|
|
319
|
+
*/
|
|
320
|
+
static addDataSources(dataSources, options) {
|
|
321
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
322
|
+
const errors = [];
|
|
323
|
+
for (const ds of dataSources) {
|
|
324
|
+
try {
|
|
325
|
+
yield TransactionContextService_1.addDataSource(ds.name, ds.dataSource, {
|
|
326
|
+
options: ds.options,
|
|
327
|
+
metadata: ds.metadata,
|
|
328
|
+
replaceExisting: options === null || options === void 0 ? void 0 : options.replaceExisting,
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
catch (error) {
|
|
332
|
+
if (options === null || options === void 0 ? void 0 : options.continueOnError) {
|
|
333
|
+
errors.push(error);
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
throw error;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
if (errors.length > 0) {
|
|
341
|
+
throw new Error(`Failed to register some DataSources: ${errors.map(e => e.message).join(', ')}`);
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* 清理全局注册表(用于测试)
|
|
347
|
+
*/
|
|
348
|
+
static clearGlobalRegistry() {
|
|
349
|
+
GlobalDataSourceRegistry.clear();
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* 获取默认数据源名称
|
|
353
|
+
*/
|
|
354
|
+
getDefaultDataSourceName() {
|
|
355
|
+
var _a;
|
|
356
|
+
return ((_a = this.config) === null || _a === void 0 ? void 0 : _a.defaultDataSource) || 'default';
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* 跨多个数据源执行分布式事务
|
|
360
|
+
* 使用两阶段提交模式
|
|
361
|
+
*/
|
|
362
|
+
executeDistributedTransaction(dataSourceNames, operation) {
|
|
363
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
364
|
+
const entityManagers = new Map();
|
|
365
|
+
const dataSources = [];
|
|
366
|
+
try {
|
|
367
|
+
// 获取所有数据源
|
|
368
|
+
for (const dataSourceName of dataSourceNames) {
|
|
369
|
+
const dataSource = yield this.getDataSourceInstance(dataSourceName);
|
|
370
|
+
dataSources.push(dataSource);
|
|
371
|
+
}
|
|
372
|
+
// 开始分布式事务
|
|
373
|
+
const results = yield Promise.all(dataSources.map((dataSource) => __awaiter(this, void 0, void 0, function* () {
|
|
374
|
+
return dataSource.transaction((entityManager) => __awaiter(this, void 0, void 0, function* () {
|
|
375
|
+
const index = dataSources.indexOf(dataSource);
|
|
376
|
+
const dataSourceName = dataSourceNames[index];
|
|
377
|
+
entityManagers.set(dataSourceName, entityManager);
|
|
378
|
+
this.setContext(dataSourceName, entityManager);
|
|
379
|
+
// 第一阶段:准备
|
|
380
|
+
// 这里只是执行操作,实际的提交将在所有操作成功后进行
|
|
381
|
+
return { dataSourceName, entityManager };
|
|
382
|
+
}));
|
|
383
|
+
})));
|
|
384
|
+
// 执行业务操作
|
|
385
|
+
const result = yield operation(entityManagers);
|
|
386
|
+
return result;
|
|
387
|
+
}
|
|
388
|
+
catch (error) {
|
|
389
|
+
// 发生错误时清理上下文
|
|
390
|
+
for (const dataSourceName of dataSourceNames) {
|
|
391
|
+
this.clearContextForDataSource(dataSourceName);
|
|
392
|
+
}
|
|
393
|
+
throw error;
|
|
394
|
+
}
|
|
395
|
+
finally {
|
|
396
|
+
// 清理上下文
|
|
397
|
+
for (const dataSourceName of dataSourceNames) {
|
|
398
|
+
this.clearContextForDataSource(dataSourceName);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
exports.TransactionContextService = TransactionContextService;
|
|
405
|
+
TransactionContextService.logger = new common_1.Logger(TransactionContextService_1.name);
|
|
406
|
+
exports.TransactionContextService = TransactionContextService = TransactionContextService_1 = __decorate([
|
|
407
|
+
(0, common_1.Injectable)({ scope: common_1.Scope.REQUEST }),
|
|
408
|
+
__param(1, (0, common_1.Optional)()),
|
|
409
|
+
__param(1, (0, common_1.Inject)('TRANSACTION_CONFIG')),
|
|
410
|
+
__metadata("design:paramtypes", [core_1.ModuleRef, Object])
|
|
411
|
+
], TransactionContextService);
|