플로우 구현
This commit is contained in:
202
backend-node/src/services/flowStepService.ts
Normal file
202
backend-node/src/services/flowStepService.ts
Normal file
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* 플로우 단계 서비스
|
||||
*/
|
||||
|
||||
import db from "../database/db";
|
||||
import {
|
||||
FlowStep,
|
||||
CreateFlowStepRequest,
|
||||
UpdateFlowStepRequest,
|
||||
FlowConditionGroup,
|
||||
} from "../types/flow";
|
||||
import { FlowConditionParser } from "./flowConditionParser";
|
||||
|
||||
export class FlowStepService {
|
||||
/**
|
||||
* 플로우 단계 생성
|
||||
*/
|
||||
async create(request: CreateFlowStepRequest): Promise<FlowStep> {
|
||||
// 조건 검증
|
||||
if (request.conditionJson) {
|
||||
FlowConditionParser.validateConditionGroup(request.conditionJson);
|
||||
}
|
||||
|
||||
const query = `
|
||||
INSERT INTO flow_step (
|
||||
flow_definition_id, step_name, step_order, table_name, condition_json,
|
||||
color, position_x, position_y
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
RETURNING *
|
||||
`;
|
||||
|
||||
const result = await db.query(query, [
|
||||
request.flowDefinitionId,
|
||||
request.stepName,
|
||||
request.stepOrder,
|
||||
request.tableName || null,
|
||||
request.conditionJson ? JSON.stringify(request.conditionJson) : null,
|
||||
request.color || "#3B82F6",
|
||||
request.positionX || 0,
|
||||
request.positionY || 0,
|
||||
]);
|
||||
|
||||
return this.mapToFlowStep(result[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 특정 플로우의 모든 단계 조회
|
||||
*/
|
||||
async findByFlowId(flowDefinitionId: number): Promise<FlowStep[]> {
|
||||
const query = `
|
||||
SELECT * FROM flow_step
|
||||
WHERE flow_definition_id = $1
|
||||
ORDER BY step_order ASC
|
||||
`;
|
||||
|
||||
const result = await db.query(query, [flowDefinitionId]);
|
||||
return result.map(this.mapToFlowStep);
|
||||
}
|
||||
|
||||
/**
|
||||
* 플로우 단계 단일 조회
|
||||
*/
|
||||
async findById(id: number): Promise<FlowStep | null> {
|
||||
const query = "SELECT * FROM flow_step WHERE id = $1";
|
||||
const result = await db.query(query, [id]);
|
||||
|
||||
if (result.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.mapToFlowStep(result[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 플로우 단계 수정
|
||||
*/
|
||||
async update(
|
||||
id: number,
|
||||
request: UpdateFlowStepRequest
|
||||
): Promise<FlowStep | null> {
|
||||
// 조건 검증
|
||||
if (request.conditionJson) {
|
||||
FlowConditionParser.validateConditionGroup(request.conditionJson);
|
||||
}
|
||||
|
||||
const fields: string[] = [];
|
||||
const params: any[] = [];
|
||||
let paramIndex = 1;
|
||||
|
||||
if (request.stepName !== undefined) {
|
||||
fields.push(`step_name = $${paramIndex}`);
|
||||
params.push(request.stepName);
|
||||
paramIndex++;
|
||||
}
|
||||
|
||||
if (request.stepOrder !== undefined) {
|
||||
fields.push(`step_order = $${paramIndex}`);
|
||||
params.push(request.stepOrder);
|
||||
paramIndex++;
|
||||
}
|
||||
|
||||
if (request.tableName !== undefined) {
|
||||
fields.push(`table_name = $${paramIndex}`);
|
||||
params.push(request.tableName);
|
||||
paramIndex++;
|
||||
}
|
||||
|
||||
if (request.conditionJson !== undefined) {
|
||||
fields.push(`condition_json = $${paramIndex}`);
|
||||
params.push(
|
||||
request.conditionJson ? JSON.stringify(request.conditionJson) : null
|
||||
);
|
||||
paramIndex++;
|
||||
}
|
||||
|
||||
if (request.color !== undefined) {
|
||||
fields.push(`color = $${paramIndex}`);
|
||||
params.push(request.color);
|
||||
paramIndex++;
|
||||
}
|
||||
|
||||
if (request.positionX !== undefined) {
|
||||
fields.push(`position_x = $${paramIndex}`);
|
||||
params.push(request.positionX);
|
||||
paramIndex++;
|
||||
}
|
||||
|
||||
if (request.positionY !== undefined) {
|
||||
fields.push(`position_y = $${paramIndex}`);
|
||||
params.push(request.positionY);
|
||||
paramIndex++;
|
||||
}
|
||||
|
||||
if (fields.length === 0) {
|
||||
return this.findById(id);
|
||||
}
|
||||
|
||||
fields.push(`updated_at = NOW()`);
|
||||
|
||||
const query = `
|
||||
UPDATE flow_step
|
||||
SET ${fields.join(", ")}
|
||||
WHERE id = $${paramIndex}
|
||||
RETURNING *
|
||||
`;
|
||||
params.push(id);
|
||||
|
||||
const result = await db.query(query, params);
|
||||
|
||||
if (result.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.mapToFlowStep(result[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 플로우 단계 삭제
|
||||
*/
|
||||
async delete(id: number): Promise<boolean> {
|
||||
const query = "DELETE FROM flow_step WHERE id = $1 RETURNING id";
|
||||
const result = await db.query(query, [id]);
|
||||
return result.length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 단계 순서 재정렬
|
||||
*/
|
||||
async reorder(
|
||||
flowDefinitionId: number,
|
||||
stepOrders: { id: number; order: number }[]
|
||||
): Promise<void> {
|
||||
await db.transaction(async (client) => {
|
||||
for (const { id, order } of stepOrders) {
|
||||
await client.query(
|
||||
"UPDATE flow_step SET step_order = $1, updated_at = NOW() WHERE id = $2 AND flow_definition_id = $3",
|
||||
[order, id, flowDefinitionId]
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* DB 행을 FlowStep 객체로 변환
|
||||
*/
|
||||
private mapToFlowStep(row: any): FlowStep {
|
||||
return {
|
||||
id: row.id,
|
||||
flowDefinitionId: row.flow_definition_id,
|
||||
stepName: row.step_name,
|
||||
stepOrder: row.step_order,
|
||||
tableName: row.table_name || undefined,
|
||||
conditionJson: row.condition_json as FlowConditionGroup | undefined,
|
||||
color: row.color,
|
||||
positionX: row.position_x,
|
||||
positionY: row.position_y,
|
||||
createdAt: row.created_at,
|
||||
updatedAt: row.updated_at,
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user