ERP-node/backend-node/src/services/flowConnectionService.ts

168 lines
4.0 KiB
TypeScript

// @ts-nocheck
/**
* 플로우 연결 서비스
*/
import db from "../database/db";
import { FlowStepConnection, CreateFlowConnectionRequest } from "../types/flow";
export class FlowConnectionService {
/**
* 플로우 단계 연결 생성
*/
async create(
request: CreateFlowConnectionRequest
): Promise<FlowStepConnection> {
// 순환 참조 체크
if (
await this.wouldCreateCycle(
request.flowDefinitionId,
request.fromStepId,
request.toStepId
)
) {
throw new Error(
"Creating this connection would create a cycle in the flow"
);
}
const query = `
INSERT INTO flow_step_connection (
flow_definition_id, from_step_id, to_step_id, label
)
VALUES ($1, $2, $3, $4)
RETURNING *
`;
const result = await db.query(query, [
request.flowDefinitionId,
request.fromStepId,
request.toStepId,
request.label || null,
]);
return this.mapToFlowConnection(result[0]);
}
/**
* 특정 플로우의 모든 연결 조회
*/
async findByFlowId(flowDefinitionId: number): Promise<FlowStepConnection[]> {
const query = `
SELECT * FROM flow_step_connection
WHERE flow_definition_id = $1
ORDER BY id ASC
`;
const result = await db.query(query, [flowDefinitionId]);
return result.map(this.mapToFlowConnection);
}
/**
* 플로우 연결 단일 조회
*/
async findById(id: number): Promise<FlowStepConnection | null> {
const query = "SELECT * FROM flow_step_connection WHERE id = $1";
const result = await db.query(query, [id]);
if (result.length === 0) {
return null;
}
return this.mapToFlowConnection(result[0]);
}
/**
* 플로우 연결 삭제
*/
async delete(id: number): Promise<boolean> {
const query = "DELETE FROM flow_step_connection WHERE id = $1 RETURNING id";
const result = await db.query(query, [id]);
return result.length > 0;
}
/**
* 특정 단계에서 나가는 연결 조회
*/
async findOutgoingConnections(stepId: number): Promise<FlowStepConnection[]> {
const query = `
SELECT * FROM flow_step_connection
WHERE from_step_id = $1
ORDER BY id ASC
`;
const result = await db.query(query, [stepId]);
return result.map(this.mapToFlowConnection);
}
/**
* 특정 단계로 들어오는 연결 조회
*/
async findIncomingConnections(stepId: number): Promise<FlowStepConnection[]> {
const query = `
SELECT * FROM flow_step_connection
WHERE to_step_id = $1
ORDER BY id ASC
`;
const result = await db.query(query, [stepId]);
return result.map(this.mapToFlowConnection);
}
/**
* 순환 참조 체크 (DFS)
*/
private async wouldCreateCycle(
flowDefinitionId: number,
fromStepId: number,
toStepId: number
): Promise<boolean> {
// toStepId에서 출발해서 fromStepId에 도달할 수 있는지 확인
const visited = new Set<number>();
const stack = [toStepId];
while (stack.length > 0) {
const current = stack.pop()!;
if (current === fromStepId) {
return true; // 순환 발견
}
if (visited.has(current)) {
continue;
}
visited.add(current);
// 현재 노드에서 나가는 모든 연결 조회
const query = `
SELECT to_step_id
FROM flow_step_connection
WHERE flow_definition_id = $1 AND from_step_id = $2
`;
const result = await db.query(query, [flowDefinitionId, current]);
for (const row of result) {
stack.push(row.to_step_id);
}
}
return false; // 순환 없음
}
/**
* DB 행을 FlowStepConnection 객체로 변환
*/
private mapToFlowConnection(row: any): FlowStepConnection {
return {
id: row.id,
flowDefinitionId: row.flow_definition_id,
fromStepId: row.from_step_id,
toStepId: row.to_step_id,
label: row.label,
createdAt: row.created_at,
};
}
}