"use client"; /** * 수식 변환 노드 (Formula Transform Node) * 산술 연산, 함수, 조건문 등을 사용해 새로운 필드를 계산합니다. * 타겟 테이블의 기존 값을 참조하여 UPSERT 시나리오를 지원합니다. */ import { memo } from "react"; import { Handle, Position, NodeProps } from "reactflow"; import { Calculator, Database, ArrowRight } from "lucide-react"; import type { FormulaTransformNodeData, FormulaType } from "@/types/node-editor"; // 수식 타입별 라벨 const FORMULA_TYPE_LABELS: Record = { arithmetic: { label: "산술", color: "bg-orange-500" }, function: { label: "함수", color: "bg-blue-500" }, condition: { label: "조건", color: "bg-yellow-500" }, static: { label: "정적", color: "bg-gray-500" }, }; // 연산자 표시 const OPERATOR_LABELS: Record = { "+": "+", "-": "-", "*": "x", "/": "/", "%": "%", }; // 피연산자를 문자열로 변환 function getOperandStr(operand: any): string { if (!operand) return "?"; if (operand.type === "static") return String(operand.value || "?"); if (operand.fieldLabel) return operand.fieldLabel; return operand.field || operand.resultField || "?"; } // 수식 요약 생성 function getFormulaSummary(transformation: FormulaTransformNodeData["transformations"][0]): string { const { formulaType, arithmetic, function: func, condition, staticValue } = transformation; switch (formulaType) { case "arithmetic": { if (!arithmetic) return "미설정"; const leftStr = getOperandStr(arithmetic.leftOperand); const rightStr = getOperandStr(arithmetic.rightOperand); let formula = `${leftStr} ${OPERATOR_LABELS[arithmetic.operator]} ${rightStr}`; // 추가 연산 표시 if (arithmetic.additionalOperations && arithmetic.additionalOperations.length > 0) { for (const addOp of arithmetic.additionalOperations) { const opStr = getOperandStr(addOp.operand); formula += ` ${OPERATOR_LABELS[addOp.operator] || addOp.operator} ${opStr}`; } } return formula; } case "function": { if (!func) return "미설정"; const args = func.arguments .map((arg) => (arg.type === "static" ? arg.value : `${arg.type}.${arg.field || arg.resultField}`)) .join(", "); return `${func.name}(${args})`; } case "condition": { if (!condition) return "미설정"; return "CASE WHEN ... THEN ... ELSE ..."; } case "static": { return staticValue !== undefined ? String(staticValue) : "미설정"; } default: return "미설정"; } } export const FormulaTransformNode = memo(({ data, selected }: NodeProps) => { const transformationCount = data.transformations?.length || 0; const hasTargetLookup = !!data.targetLookup?.tableName; return (
{/* 헤더 */}
{data.displayName || "수식 변환"}
{transformationCount}개 변환 {hasTargetLookup && "| 타겟 조회"}
{/* 본문 */}
{/* 타겟 테이블 조회 설정 */} {hasTargetLookup && (
타겟 조회
{data.targetLookup?.tableLabel || data.targetLookup?.tableName}
{data.targetLookup?.lookupKeys && data.targetLookup.lookupKeys.length > 0 && (
{data.targetLookup.lookupKeys.slice(0, 2).map((key, idx) => ( {key.sourceFieldLabel || key.sourceField} {key.targetFieldLabel || key.targetField} ))} {data.targetLookup.lookupKeys.length > 2 && ( +{data.targetLookup.lookupKeys.length - 2} )}
)}
)} {/* 변환 규칙들 */} {transformationCount > 0 ? (
{data.transformations.slice(0, 4).map((trans, idx) => { const typeInfo = FORMULA_TYPE_LABELS[trans.formulaType]; return (
{typeInfo.label} {trans.outputFieldLabel || trans.outputField}
{getFormulaSummary(trans)}
); })} {data.transformations.length > 4 && (
... 외 {data.transformations.length - 4}개
)}
) : (
변환 규칙 없음
)}
{/* 핸들 */}
); }); FormulaTransformNode.displayName = "FormulaTransformNode";