feat: Add procedure and function management in flow controller
- Introduced new endpoints in FlowController for listing procedures and retrieving procedure parameters, enhancing the flow management capabilities. - Updated FlowDataMoveService to support procedure calls during data movement, ensuring seamless integration with external and internal databases. - Enhanced NodeFlowExecutionService to execute procedure call actions, allowing for dynamic execution of stored procedures within flow nodes. - Updated frontend components to support procedure selection and parameter management, improving user experience in configuring flow steps. - Added necessary types and API functions for handling procedure-related data, ensuring type safety and clarity in implementation.
This commit is contained in:
@@ -26,16 +26,20 @@ import {
|
||||
buildSelectQuery,
|
||||
} from "./dbQueryBuilder";
|
||||
import { FlowConditionParser } from "./flowConditionParser";
|
||||
import { FlowProcedureService } from "./flowProcedureService";
|
||||
import { FlowProcedureConfig } from "../types/flow";
|
||||
|
||||
export class FlowDataMoveService {
|
||||
private flowDefinitionService: FlowDefinitionService;
|
||||
private flowStepService: FlowStepService;
|
||||
private externalDbIntegrationService: FlowExternalDbIntegrationService;
|
||||
private flowProcedureService: FlowProcedureService;
|
||||
|
||||
constructor() {
|
||||
this.flowDefinitionService = new FlowDefinitionService();
|
||||
this.flowStepService = new FlowStepService();
|
||||
this.externalDbIntegrationService = new FlowExternalDbIntegrationService();
|
||||
this.flowProcedureService = new FlowProcedureService();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,6 +94,64 @@ export class FlowDataMoveService {
|
||||
let sourceTable = fromStep.tableName;
|
||||
let targetTable = toStep.tableName || fromStep.tableName;
|
||||
|
||||
// 1.5. 프로시저 호출 (스텝 이동 전 실행, 실패 시 전체 롤백)
|
||||
if (
|
||||
toStep.integrationType === "procedure" &&
|
||||
toStep.integrationConfig &&
|
||||
(toStep.integrationConfig as FlowProcedureConfig).type === "procedure"
|
||||
) {
|
||||
const procConfig = toStep.integrationConfig as FlowProcedureConfig;
|
||||
// 레코드 데이터 조회 (파라미터 매핑용)
|
||||
let recordData: Record<string, any> = {};
|
||||
try {
|
||||
const recordTable = FlowConditionParser.sanitizeTableName(
|
||||
sourceTable || flowDefinition.tableName
|
||||
);
|
||||
const recordResult = await client.query(
|
||||
`SELECT * FROM ${recordTable} WHERE id = $1 LIMIT 1`,
|
||||
[dataId]
|
||||
);
|
||||
if (recordResult.rows && recordResult.rows.length > 0) {
|
||||
recordData = recordResult.rows[0];
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.warn("프로시저 파라미터용 레코드 조회 실패:", err.message);
|
||||
}
|
||||
|
||||
console.log(`프로시저 호출 시작: ${procConfig.procedureName}`, {
|
||||
flowId,
|
||||
fromStepId,
|
||||
toStepId,
|
||||
dataId,
|
||||
dbSource: procConfig.dbSource,
|
||||
});
|
||||
|
||||
const procResult = await this.flowProcedureService.executeProcedure(
|
||||
procConfig,
|
||||
recordData,
|
||||
procConfig.dbSource === "internal" ? client : undefined
|
||||
);
|
||||
|
||||
console.log(`프로시저 호출 완료: ${procConfig.procedureName}`, {
|
||||
success: procResult.success,
|
||||
});
|
||||
|
||||
// 프로시저 실행 로그 기록
|
||||
await this.logIntegration(
|
||||
flowId,
|
||||
toStep.id,
|
||||
dataId,
|
||||
"procedure",
|
||||
procConfig.connectionId,
|
||||
procConfig,
|
||||
procResult.result,
|
||||
"success",
|
||||
undefined,
|
||||
0,
|
||||
userId
|
||||
);
|
||||
}
|
||||
|
||||
// 2. 이동 방식에 따라 처리
|
||||
switch (toStep.moveType || "status") {
|
||||
case "status":
|
||||
@@ -603,18 +665,19 @@ export class FlowDataMoveService {
|
||||
}
|
||||
break;
|
||||
|
||||
case "procedure":
|
||||
// 프로시저는 데이터 이동 전에 이미 실행됨 (step 1.5)
|
||||
break;
|
||||
|
||||
case "rest_api":
|
||||
// REST API 연동 (추후 구현)
|
||||
console.warn("REST API 연동은 아직 구현되지 않았습니다");
|
||||
break;
|
||||
|
||||
case "webhook":
|
||||
// Webhook 연동 (추후 구현)
|
||||
console.warn("Webhook 연동은 아직 구현되지 않았습니다");
|
||||
break;
|
||||
|
||||
case "hybrid":
|
||||
// 복합 연동 (추후 구현)
|
||||
console.warn("복합 연동은 아직 구현되지 않았습니다");
|
||||
break;
|
||||
|
||||
@@ -716,6 +779,40 @@ export class FlowDataMoveService {
|
||||
let sourceTable = fromStep.tableName;
|
||||
let targetTable = toStep.tableName || fromStep.tableName;
|
||||
|
||||
// 1.5. 프로시저 호출 (외부 DB 경로 - 스텝 이동 전)
|
||||
if (
|
||||
toStep.integrationType === "procedure" &&
|
||||
toStep.integrationConfig &&
|
||||
(toStep.integrationConfig as FlowProcedureConfig).type === "procedure"
|
||||
) {
|
||||
const procConfig = toStep.integrationConfig as FlowProcedureConfig;
|
||||
let recordData: Record<string, any> = {};
|
||||
try {
|
||||
const recordTable = FlowConditionParser.sanitizeTableName(
|
||||
sourceTable || ""
|
||||
);
|
||||
if (recordTable) {
|
||||
const placeholder = getPlaceholder(dbType, 1);
|
||||
const recordResult = await externalClient.query(
|
||||
`SELECT * FROM ${recordTable} WHERE id = ${placeholder}`,
|
||||
[dataId]
|
||||
);
|
||||
const rows = recordResult.rows || recordResult;
|
||||
if (Array.isArray(rows) && rows.length > 0) {
|
||||
recordData = rows[0];
|
||||
}
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.warn("프로시저 파라미터용 레코드 조회 실패 (외부):", err.message);
|
||||
}
|
||||
|
||||
await this.flowProcedureService.executeProcedure(
|
||||
procConfig,
|
||||
recordData,
|
||||
procConfig.dbSource === "external" ? undefined : undefined
|
||||
);
|
||||
}
|
||||
|
||||
// 2. 이동 방식에 따라 처리
|
||||
switch (toStep.moveType || "status") {
|
||||
case "status":
|
||||
|
||||
Reference in New Issue
Block a user