저장버튼 제어기능 (insert)

This commit is contained in:
kjs
2025-09-18 10:05:50 +09:00
parent 7b7f81d85c
commit 7cbbf45dc9
32 changed files with 8500 additions and 116 deletions

View File

@@ -1,6 +1,7 @@
import prisma from "../config/database";
import { Prisma } from "@prisma/client";
import { EventTriggerService } from "./eventTriggerService";
import { DataflowControlService } from "./dataflowControlService";
export interface FormDataResult {
id: number;
@@ -42,6 +43,71 @@ export interface TableColumn {
}
export class DynamicFormService {
private dataflowControlService = new DataflowControlService();
/**
* 값을 PostgreSQL 타입에 맞게 변환
*/
private convertValueForPostgreSQL(value: any, dataType: string): any {
if (value === null || value === undefined || value === "") {
return null;
}
const lowerDataType = dataType.toLowerCase();
// 숫자 타입 처리
if (
lowerDataType.includes("integer") ||
lowerDataType.includes("bigint") ||
lowerDataType.includes("serial")
) {
return parseInt(value) || null;
}
if (
lowerDataType.includes("numeric") ||
lowerDataType.includes("decimal") ||
lowerDataType.includes("real") ||
lowerDataType.includes("double")
) {
return parseFloat(value) || null;
}
// 불린 타입 처리
if (lowerDataType.includes("boolean")) {
if (typeof value === "boolean") return value;
if (typeof value === "string") {
return value.toLowerCase() === "true" || value === "1";
}
return Boolean(value);
}
// 기본적으로 문자열로 반환
return value;
}
/**
* 테이블의 컬럼 정보 조회 (타입 포함)
*/
private async getTableColumnInfo(
tableName: string
): Promise<Array<{ column_name: string; data_type: string }>> {
try {
const result = await prisma.$queryRaw<
Array<{ column_name: string; data_type: string }>
>`
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_name = ${tableName}
AND table_schema = 'public'
`;
return result;
} catch (error) {
console.error(`테이블 ${tableName}의 컬럼 정보 조회 실패:`, error);
return [];
}
}
/**
* 테이블의 컬럼명 목록 조회 (간단 버전)
*/
@@ -196,6 +262,32 @@ export class DynamicFormService {
dataToInsert,
});
// 테이블 컬럼 정보 조회하여 타입 변환 적용
console.log("🔍 테이블 컬럼 정보 조회 중...");
const columnInfo = await this.getTableColumnInfo(tableName);
console.log("📊 테이블 컬럼 정보:", columnInfo);
// 각 컬럼의 타입에 맞게 데이터 변환
Object.keys(dataToInsert).forEach((columnName) => {
const column = columnInfo.find((col) => col.column_name === columnName);
if (column) {
const originalValue = dataToInsert[columnName];
const convertedValue = this.convertValueForPostgreSQL(
originalValue,
column.data_type
);
if (originalValue !== convertedValue) {
console.log(
`🔄 타입 변환: ${columnName} (${column.data_type}) = "${originalValue}" -> ${convertedValue}`
);
dataToInsert[columnName] = convertedValue;
}
}
});
console.log("✅ 타입 변환 완료된 데이터:", dataToInsert);
// 동적 SQL을 사용하여 실제 테이블에 UPSERT
const columns = Object.keys(dataToInsert);
const values: any[] = Object.values(dataToInsert);
@@ -264,6 +356,19 @@ export class DynamicFormService {
// 트리거 오류는 로그만 남기고 메인 저장 프로세스는 계속 진행
}
// 🎯 제어관리 실행 (새로 추가)
try {
await this.executeDataflowControlIfConfigured(
screenId,
tableName,
insertedRecord as Record<string, any>,
"insert"
);
} catch (controlError) {
console.error("⚠️ 제어관리 실행 오류:", controlError);
// 제어관리 오류는 로그만 남기고 메인 저장 프로세스는 계속 진행
}
return {
id: insertedRecord.id || insertedRecord.objid || 0,
screenId: screenId,
@@ -674,6 +779,85 @@ export class DynamicFormService {
throw new Error(`테이블 컬럼 정보 조회 실패: ${error}`);
}
}
/**
* 제어관리 실행 (화면에 설정된 경우)
*/
private async executeDataflowControlIfConfigured(
screenId: number,
tableName: string,
savedData: Record<string, any>,
triggerType: "insert" | "update" | "delete"
): Promise<void> {
try {
console.log(`🎯 제어관리 설정 확인 중... (screenId: ${screenId})`);
// 화면의 저장 버튼에서 제어관리 설정 조회
const screenLayouts = await prisma.screen_layouts.findMany({
where: {
screen_id: screenId,
component_type: "component",
},
});
console.log(`📋 화면 컴포넌트 조회 결과:`, screenLayouts.length);
// 저장 버튼 중에서 제어관리가 활성화된 것 찾기
for (const layout of screenLayouts) {
const properties = layout.properties as any;
// 버튼 컴포넌트이고 저장 액션이며 제어관리가 활성화된 경우
if (
properties?.componentType === "button-primary" &&
properties?.componentConfig?.action?.type === "save" &&
properties?.webTypeConfig?.enableDataflowControl === true &&
properties?.webTypeConfig?.dataflowConfig?.selectedDiagramId
) {
const diagramId =
properties.webTypeConfig.dataflowConfig.selectedDiagramId;
const relationshipId =
properties.webTypeConfig.dataflowConfig.selectedRelationshipId;
console.log(`🎯 제어관리 설정 발견:`, {
componentId: layout.component_id,
diagramId,
relationshipId,
triggerType,
});
// 제어관리 실행
const controlResult =
await this.dataflowControlService.executeDataflowControl(
diagramId,
relationshipId,
triggerType,
savedData,
tableName
);
console.log(`🎯 제어관리 실행 결과:`, controlResult);
if (controlResult.success) {
console.log(`✅ 제어관리 실행 성공: ${controlResult.message}`);
if (
controlResult.executedActions &&
controlResult.executedActions.length > 0
) {
console.log(`📊 실행된 액션들:`, controlResult.executedActions);
}
} else {
console.warn(`⚠️ 제어관리 실행 실패: ${controlResult.message}`);
}
// 첫 번째 설정된 제어관리만 실행 (여러 개가 있을 경우)
break;
}
}
} catch (error) {
console.error("❌ 제어관리 설정 확인 및 실행 오류:", error);
// 에러를 다시 던지지 않음 - 메인 저장 프로세스에 영향 주지 않기 위해
}
}
}
// 싱글톤 인스턴스 생성 및 export