제어관리 외부커넥션 설정기능
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
// 🔧 Prisma 클라이언트 중복 생성 방지 - 기존 인스턴스 재사용
|
||||
import prisma = require("../config/database");
|
||||
|
||||
export interface ControlCondition {
|
||||
id: string;
|
||||
@@ -33,6 +32,16 @@ export interface ControlAction {
|
||||
sourceField?: string;
|
||||
targetField?: string;
|
||||
};
|
||||
// 🆕 다중 커넥션 지원 추가
|
||||
fromConnection?: {
|
||||
id: number;
|
||||
name?: string;
|
||||
};
|
||||
toConnection?: {
|
||||
id: number;
|
||||
name?: string;
|
||||
};
|
||||
targetTable?: string;
|
||||
}
|
||||
|
||||
export interface ControlPlan {
|
||||
@@ -84,13 +93,59 @@ export class DataflowControlService {
|
||||
};
|
||||
}
|
||||
|
||||
// 제어 규칙과 실행 계획 추출
|
||||
const controlRules = Array.isArray(diagram.control)
|
||||
? (diagram.control as unknown as ControlRule[])
|
||||
: [];
|
||||
const executionPlans = Array.isArray(diagram.plan)
|
||||
? (diagram.plan as unknown as ControlPlan[])
|
||||
: [];
|
||||
// 제어 규칙과 실행 계획 추출 (기존 구조 + redesigned UI 구조 지원)
|
||||
let controlRules: ControlRule[] = [];
|
||||
let executionPlans: ControlPlan[] = [];
|
||||
|
||||
// 🆕 redesigned UI 구조 처리
|
||||
if (diagram.relationships && typeof diagram.relationships === "object") {
|
||||
const relationships = diagram.relationships as any;
|
||||
|
||||
// Case 1: redesigned UI 단일 관계 구조
|
||||
if (relationships.controlConditions && relationships.fieldMappings) {
|
||||
console.log("🔄 Redesigned UI 구조 감지, 기존 구조로 변환 중");
|
||||
|
||||
// redesigned → 기존 구조 변환
|
||||
controlRules = [
|
||||
{
|
||||
id: relationshipId,
|
||||
triggerType: triggerType,
|
||||
conditions: relationships.controlConditions || [],
|
||||
},
|
||||
];
|
||||
|
||||
executionPlans = [
|
||||
{
|
||||
id: relationshipId,
|
||||
sourceTable: relationships.fromTable || tableName,
|
||||
actions: [
|
||||
{
|
||||
id: "action_1",
|
||||
name: "액션 1",
|
||||
actionType: relationships.actionType || "insert",
|
||||
conditions: relationships.actionConditions || [],
|
||||
fieldMappings: relationships.fieldMappings || [],
|
||||
fromConnection: relationships.fromConnection,
|
||||
toConnection: relationships.toConnection,
|
||||
targetTable: relationships.toTable,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
console.log("✅ Redesigned → 기존 구조 변환 완료");
|
||||
}
|
||||
}
|
||||
|
||||
// 기존 구조 처리 (하위 호환성)
|
||||
if (controlRules.length === 0) {
|
||||
controlRules = Array.isArray(diagram.control)
|
||||
? (diagram.control as unknown as ControlRule[])
|
||||
: [];
|
||||
executionPlans = Array.isArray(diagram.plan)
|
||||
? (diagram.plan as unknown as ControlPlan[])
|
||||
: [];
|
||||
}
|
||||
|
||||
console.log(`📋 제어 규칙:`, controlRules);
|
||||
console.log(`📋 실행 계획:`, executionPlans);
|
||||
@@ -174,37 +229,29 @@ export class DataflowControlService {
|
||||
logicalOperator: action.logicalOperator,
|
||||
conditions: action.conditions,
|
||||
fieldMappings: action.fieldMappings,
|
||||
fromConnection: (action as any).fromConnection,
|
||||
toConnection: (action as any).toConnection,
|
||||
targetTable: (action as any).targetTable,
|
||||
});
|
||||
|
||||
// 액션 조건 검증 (있는 경우) - 동적 테이블 지원
|
||||
if (action.conditions && action.conditions.length > 0) {
|
||||
const actionConditionResult = await this.evaluateActionConditions(
|
||||
action,
|
||||
sourceData,
|
||||
tableName
|
||||
);
|
||||
// 🆕 다중 커넥션 지원 액션 실행
|
||||
const actionResult = await this.executeMultiConnectionAction(
|
||||
action,
|
||||
sourceData,
|
||||
targetPlan.sourceTable
|
||||
);
|
||||
|
||||
if (!actionConditionResult.satisfied) {
|
||||
console.log(
|
||||
`⚠️ 액션 조건 미충족: ${actionConditionResult.reason}`
|
||||
);
|
||||
previousActionSuccess = false;
|
||||
if (action.logicalOperator === "AND") {
|
||||
shouldSkipRemainingActions = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
const actionResult = await this.executeAction(action, sourceData);
|
||||
executedActions.push({
|
||||
actionId: action.id,
|
||||
actionName: action.name,
|
||||
actionType: action.actionType,
|
||||
result: actionResult,
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
|
||||
previousActionSuccess = true;
|
||||
shouldSkipRemainingActions = false; // 성공했으므로 다시 실행 가능
|
||||
previousActionSuccess = actionResult?.success !== false;
|
||||
|
||||
// 액션 조건 검증은 이미 위에서 처리됨 (중복 제거)
|
||||
} catch (error) {
|
||||
console.error(`❌ 액션 실행 오류: ${action.name}`, error);
|
||||
const errorMessage =
|
||||
@@ -235,6 +282,191 @@ export class DataflowControlService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🆕 다중 커넥션 액션 실행
|
||||
*/
|
||||
private async executeMultiConnectionAction(
|
||||
action: ControlAction,
|
||||
sourceData: Record<string, any>,
|
||||
sourceTable: string
|
||||
): Promise<any> {
|
||||
try {
|
||||
const extendedAction = action as any; // redesigned UI 구조 접근
|
||||
|
||||
// 연결 정보 추출
|
||||
const fromConnection = extendedAction.fromConnection || { id: 0 };
|
||||
const toConnection = extendedAction.toConnection || { id: 0 };
|
||||
const targetTable = extendedAction.targetTable || sourceTable;
|
||||
|
||||
console.log(`🔗 다중 커넥션 액션 실행:`, {
|
||||
actionType: action.actionType,
|
||||
fromConnectionId: fromConnection.id,
|
||||
toConnectionId: toConnection.id,
|
||||
sourceTable,
|
||||
targetTable,
|
||||
});
|
||||
|
||||
// MultiConnectionQueryService import 필요
|
||||
const { MultiConnectionQueryService } = await import(
|
||||
"./multiConnectionQueryService"
|
||||
);
|
||||
const multiConnService = new MultiConnectionQueryService();
|
||||
|
||||
switch (action.actionType) {
|
||||
case "insert":
|
||||
return await this.executeMultiConnectionInsert(
|
||||
action,
|
||||
sourceData,
|
||||
sourceTable,
|
||||
targetTable,
|
||||
fromConnection.id,
|
||||
toConnection.id,
|
||||
multiConnService
|
||||
);
|
||||
|
||||
case "update":
|
||||
return await this.executeMultiConnectionUpdate(
|
||||
action,
|
||||
sourceData,
|
||||
sourceTable,
|
||||
targetTable,
|
||||
fromConnection.id,
|
||||
toConnection.id,
|
||||
multiConnService
|
||||
);
|
||||
|
||||
case "delete":
|
||||
return await this.executeMultiConnectionDelete(
|
||||
action,
|
||||
sourceData,
|
||||
sourceTable,
|
||||
targetTable,
|
||||
fromConnection.id,
|
||||
toConnection.id,
|
||||
multiConnService
|
||||
);
|
||||
|
||||
default:
|
||||
throw new Error(`지원되지 않는 액션 타입: ${action.actionType}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`❌ 다중 커넥션 액션 실행 실패:`, error);
|
||||
return {
|
||||
success: false,
|
||||
message: error instanceof Error ? error.message : String(error),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🆕 다중 커넥션 INSERT 실행
|
||||
*/
|
||||
private async executeMultiConnectionInsert(
|
||||
action: ControlAction,
|
||||
sourceData: Record<string, any>,
|
||||
sourceTable: string,
|
||||
targetTable: string,
|
||||
fromConnectionId: number,
|
||||
toConnectionId: number,
|
||||
multiConnService: any
|
||||
): Promise<any> {
|
||||
try {
|
||||
// 필드 매핑 적용
|
||||
const mappedData: Record<string, any> = {};
|
||||
|
||||
for (const mapping of action.fieldMappings) {
|
||||
const sourceField = mapping.sourceField;
|
||||
const targetField = mapping.targetField;
|
||||
|
||||
if (mapping.defaultValue !== undefined) {
|
||||
// 기본값 사용
|
||||
mappedData[targetField] = mapping.defaultValue;
|
||||
} else if (sourceField && sourceData[sourceField] !== undefined) {
|
||||
// 소스 데이터에서 매핑
|
||||
mappedData[targetField] = sourceData[sourceField];
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`📋 매핑된 데이터:`, mappedData);
|
||||
|
||||
// 대상 연결에 데이터 삽입
|
||||
const result = await multiConnService.insertDataToConnection(
|
||||
toConnectionId,
|
||||
targetTable,
|
||||
mappedData
|
||||
);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: `${targetTable}에 데이터 삽입 완료`,
|
||||
insertedCount: 1,
|
||||
data: result,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(`❌ INSERT 실행 실패:`, error);
|
||||
return {
|
||||
success: false,
|
||||
message: error instanceof Error ? error.message : String(error),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🆕 다중 커넥션 UPDATE 실행
|
||||
*/
|
||||
private async executeMultiConnectionUpdate(
|
||||
action: ControlAction,
|
||||
sourceData: Record<string, any>,
|
||||
sourceTable: string,
|
||||
targetTable: string,
|
||||
fromConnectionId: number,
|
||||
toConnectionId: number,
|
||||
multiConnService: any
|
||||
): Promise<any> {
|
||||
try {
|
||||
// UPDATE 로직 구현 (향후 확장)
|
||||
console.log(`⚠️ UPDATE 액션은 향후 구현 예정`);
|
||||
return {
|
||||
success: true,
|
||||
message: "UPDATE 액션 실행됨 (향후 구현)",
|
||||
updatedCount: 0,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
message: error instanceof Error ? error.message : String(error),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 🆕 다중 커넥션 DELETE 실행
|
||||
*/
|
||||
private async executeMultiConnectionDelete(
|
||||
action: ControlAction,
|
||||
sourceData: Record<string, any>,
|
||||
sourceTable: string,
|
||||
targetTable: string,
|
||||
fromConnectionId: number,
|
||||
toConnectionId: number,
|
||||
multiConnService: any
|
||||
): Promise<any> {
|
||||
try {
|
||||
// DELETE 로직 구현 (향후 확장)
|
||||
console.log(`⚠️ DELETE 액션은 향후 구현 예정`);
|
||||
return {
|
||||
success: true,
|
||||
message: "DELETE 액션 실행됨 (향후 구현)",
|
||||
deletedCount: 0,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
message: error instanceof Error ? error.message : String(error),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 액션별 조건 평가 (동적 테이블 지원)
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user