import { PrismaClient } from "@prisma/client"; import { logger } from "../utils/logger"; const prisma = new PrismaClient(); // 테이블 관계 생성 데이터 타입 interface CreateTableRelationshipData { relationshipName: string; fromTableName: string; fromColumnName: string; toTableName: string; toColumnName: string; relationshipType: string; connectionType: string; companyCode: string; settings: any; createdBy: string; } // 테이블 관계 수정 데이터 타입 interface UpdateTableRelationshipData { relationshipName?: string; fromTableName?: string; fromColumnName?: string; toTableName?: string; toColumnName?: string; relationshipType?: string; connectionType?: string; settings?: any; updatedBy: string; } export class DataflowService { /** * 테이블 관계 생성 */ async createTableRelationship(data: CreateTableRelationshipData) { try { logger.info("DataflowService: 테이블 관계 생성 시작", data); // 중복 관계 확인 const existingRelationship = await prisma.table_relationships.findFirst({ where: { from_table_name: data.fromTableName, from_column_name: data.fromColumnName, to_table_name: data.toTableName, to_column_name: data.toColumnName, company_code: data.companyCode, is_active: "Y", }, }); if (existingRelationship) { throw new Error( `이미 존재하는 관계입니다: ${data.fromTableName}.${data.fromColumnName} → ${data.toTableName}.${data.toColumnName}` ); } // 새 관계 생성 const relationship = await prisma.table_relationships.create({ data: { relationship_name: data.relationshipName, from_table_name: data.fromTableName, from_column_name: data.fromColumnName, to_table_name: data.toTableName, to_column_name: data.toColumnName, relationship_type: data.relationshipType, connection_type: data.connectionType, company_code: data.companyCode, settings: data.settings, created_by: data.createdBy, updated_by: data.createdBy, }, }); logger.info( `DataflowService: 테이블 관계 생성 완료 - ID: ${relationship.relationship_id}` ); return relationship; } catch (error) { logger.error("DataflowService: 테이블 관계 생성 실패", error); throw error; } } /** * 회사별 테이블 관계 목록 조회 */ async getTableRelationships(companyCode: string) { try { logger.info( `DataflowService: 테이블 관계 목록 조회 시작 - 회사코드: ${companyCode}` ); // 관리자는 모든 회사의 관계를 볼 수 있음 const whereCondition: any = { is_active: "Y", }; if (companyCode !== "*") { whereCondition.company_code = companyCode; } const relationships = await prisma.table_relationships.findMany({ where: whereCondition, orderBy: { created_date: "desc", }, }); logger.info( `DataflowService: 테이블 관계 목록 조회 완료 - ${relationships.length}개` ); return relationships; } catch (error) { logger.error("DataflowService: 테이블 관계 목록 조회 실패", error); throw error; } } /** * 특정 테이블 관계 조회 */ async getTableRelationship(relationshipId: number, companyCode: string) { try { logger.info( `DataflowService: 테이블 관계 조회 시작 - ID: ${relationshipId}, 회사코드: ${companyCode}` ); const whereCondition: any = { relationship_id: relationshipId, is_active: "Y", }; // 관리자가 아닌 경우 회사코드 제한 if (companyCode !== "*") { whereCondition.company_code = companyCode; } const relationship = await prisma.table_relationships.findFirst({ where: whereCondition, }); if (relationship) { logger.info( `DataflowService: 테이블 관계 조회 완료 - ID: ${relationshipId}` ); } else { logger.warn( `DataflowService: 테이블 관계를 찾을 수 없음 - ID: ${relationshipId}` ); } return relationship; } catch (error) { logger.error("DataflowService: 테이블 관계 조회 실패", error); throw error; } } /** * 테이블 관계 수정 */ async updateTableRelationship( relationshipId: number, updateData: UpdateTableRelationshipData, companyCode: string ) { try { logger.info( `DataflowService: 테이블 관계 수정 시작 - ID: ${relationshipId}`, updateData ); // 기존 관계 확인 const existingRelationship = await this.getTableRelationship( relationshipId, companyCode ); if (!existingRelationship) { return null; } // 관계 수정 const relationship = await prisma.table_relationships.update({ where: { relationship_id: relationshipId, }, data: { ...updateData, updated_date: new Date(), }, }); logger.info( `DataflowService: 테이블 관계 수정 완료 - ID: ${relationshipId}` ); return relationship; } catch (error) { logger.error("DataflowService: 테이블 관계 수정 실패", error); throw error; } } /** * 테이블 관계 삭제 (소프트 삭제) */ async deleteTableRelationship(relationshipId: number, companyCode: string) { try { logger.info( `DataflowService: 테이블 관계 삭제 시작 - ID: ${relationshipId}, 회사코드: ${companyCode}` ); // 기존 관계 확인 const existingRelationship = await this.getTableRelationship( relationshipId, companyCode ); if (!existingRelationship) { return false; } // 소프트 삭제 (is_active = 'N') await prisma.table_relationships.update({ where: { relationship_id: relationshipId, }, data: { is_active: "N", updated_date: new Date(), }, }); logger.info( `DataflowService: 테이블 관계 삭제 완료 - ID: ${relationshipId}` ); return true; } catch (error) { logger.error("DataflowService: 테이블 관계 삭제 실패", error); throw error; } } /** * 특정 테이블과 관련된 모든 관계 조회 */ async getRelationshipsByTable(tableName: string, companyCode: string) { try { logger.info( `DataflowService: 테이블별 관계 조회 시작 - 테이블: ${tableName}, 회사코드: ${companyCode}` ); const whereCondition: any = { OR: [{ from_table_name: tableName }, { to_table_name: tableName }], is_active: "Y", }; // 관리자가 아닌 경우 회사코드 제한 if (companyCode !== "*") { whereCondition.company_code = companyCode; } const relationships = await prisma.table_relationships.findMany({ where: whereCondition, orderBy: { created_date: "desc", }, }); logger.info( `DataflowService: 테이블별 관계 조회 완료 - ${relationships.length}개` ); return relationships; } catch (error) { logger.error("DataflowService: 테이블별 관계 조회 실패", error); throw error; } } /** * 연결 타입별 관계 조회 */ async getRelationshipsByConnectionType( connectionType: string, companyCode: string ) { try { logger.info( `DataflowService: 연결타입별 관계 조회 시작 - 타입: ${connectionType}, 회사코드: ${companyCode}` ); const whereCondition: any = { connection_type: connectionType, is_active: "Y", }; // 관리자가 아닌 경우 회사코드 제한 if (companyCode !== "*") { whereCondition.company_code = companyCode; } const relationships = await prisma.table_relationships.findMany({ where: whereCondition, orderBy: { created_date: "desc", }, }); logger.info( `DataflowService: 연결타입별 관계 조회 완료 - ${relationships.length}개` ); return relationships; } catch (error) { logger.error("DataflowService: 연결타입별 관계 조회 실패", error); throw error; } } /** * 관계 통계 조회 */ async getRelationshipStats(companyCode: string) { try { logger.info( `DataflowService: 관계 통계 조회 시작 - 회사코드: ${companyCode}` ); const whereCondition: any = { is_active: "Y", }; // 관리자가 아닌 경우 회사코드 제한 if (companyCode !== "*") { whereCondition.company_code = companyCode; } // 전체 관계 수 const totalCount = await prisma.table_relationships.count({ where: whereCondition, }); // 관계 타입별 통계 const relationshipTypeStats = await prisma.table_relationships.groupBy({ by: ["relationship_type"], where: whereCondition, _count: { relationship_id: true, }, }); // 연결 타입별 통계 const connectionTypeStats = await prisma.table_relationships.groupBy({ by: ["connection_type"], where: whereCondition, _count: { relationship_id: true, }, }); const stats = { totalCount, relationshipTypeStats: relationshipTypeStats.map((stat) => ({ type: stat.relationship_type, count: stat._count.relationship_id, })), connectionTypeStats: connectionTypeStats.map((stat) => ({ type: stat.connection_type, count: stat._count.relationship_id, })), }; logger.info(`DataflowService: 관계 통계 조회 완료`, stats); return stats; } catch (error) { logger.error("DataflowService: 관계 통계 조회 실패", error); throw error; } } // ==================== 데이터 중계 관리 ==================== /** * 데이터 관계 연결 생성 */ async createDataLink(linkData: { relationshipId: number; fromTableName: string; fromColumnName: string; fromKeyValue: string; fromRecordId?: string; toTableName: string; toColumnName: string; toKeyValue: string; toRecordId?: string; connectionType: string; companyCode: string; bridgeData?: any; createdBy: string; }) { try { logger.info( `DataflowService: 데이터 연결 생성 시작 - 관계ID: ${linkData.relationshipId}` ); const bridge = await prisma.data_relationship_bridge.create({ data: { relationship_id: linkData.relationshipId, from_table_name: linkData.fromTableName, from_column_name: linkData.fromColumnName, from_key_value: linkData.fromKeyValue, from_record_id: linkData.fromRecordId, to_table_name: linkData.toTableName, to_column_name: linkData.toColumnName, to_key_value: linkData.toKeyValue, to_record_id: linkData.toRecordId, connection_type: linkData.connectionType, company_code: linkData.companyCode, bridge_data: linkData.bridgeData || {}, created_by: linkData.createdBy, }, }); logger.info( `DataflowService: 데이터 연결 생성 완료 - Bridge ID: ${bridge.bridge_id}` ); return bridge; } catch (error) { logger.error("DataflowService: 데이터 연결 생성 실패", error); throw error; } } /** * 관계별 연결된 데이터 조회 */ async getLinkedDataByRelationship( relationshipId: number, companyCode: string ) { try { logger.info( `DataflowService: 관계별 연결 데이터 조회 시작 - 관계ID: ${relationshipId}` ); const whereCondition: any = { relationship_id: relationshipId, is_active: "Y", }; // 관리자가 아닌 경우 회사코드 제한 if (companyCode !== "*") { whereCondition.company_code = companyCode; } const linkedData = await prisma.data_relationship_bridge.findMany({ where: whereCondition, orderBy: { created_at: "desc" }, include: { relationship: { select: { relationship_name: true, relationship_type: true, connection_type: true, }, }, }, }); logger.info( `DataflowService: 관계별 연결 데이터 조회 완료 - ${linkedData.length}건` ); return linkedData; } catch (error) { logger.error("DataflowService: 관계별 연결 데이터 조회 실패", error); throw error; } } /** * 특정 테이블의 연결된 데이터 조회 */ async getLinkedDataByTable( tableName: string, keyValue?: string, companyCode?: string ) { try { logger.info( `DataflowService: 테이블별 연결 데이터 조회 시작 - 테이블: ${tableName}` ); const whereCondition: any = { OR: [{ from_table_name: tableName }, { to_table_name: tableName }], is_active: "Y", }; // 특정 키 값으로 필터링 if (keyValue) { whereCondition.OR = [ { from_table_name: tableName, from_key_value: keyValue }, { to_table_name: tableName, to_key_value: keyValue }, ]; } // 회사코드 필터링 if (companyCode && companyCode !== "*") { whereCondition.company_code = companyCode; } const linkedData = await prisma.data_relationship_bridge.findMany({ where: whereCondition, orderBy: { created_at: "desc" }, include: { relationship: { select: { relationship_name: true, relationship_type: true, connection_type: true, }, }, }, }); logger.info( `DataflowService: 테이블별 연결 데이터 조회 완료 - ${linkedData.length}건` ); return linkedData; } catch (error) { logger.error("DataflowService: 테이블별 연결 데이터 조회 실패", error); throw error; } } /** * 데이터 연결 수정 */ async updateDataLink( bridgeId: number, updateData: { fromKeyValue?: string; fromRecordId?: string; toKeyValue?: string; toRecordId?: string; bridgeData?: any; updatedBy: string; }, companyCode: string ) { try { logger.info( `DataflowService: 데이터 연결 수정 시작 - Bridge ID: ${bridgeId}` ); const whereCondition: any = { bridge_id: bridgeId, is_active: "Y", }; // 관리자가 아닌 경우 회사코드 제한 if (companyCode !== "*") { whereCondition.company_code = companyCode; } const updatedBridge = await prisma.data_relationship_bridge.update({ where: whereCondition, data: { ...updateData, updated_at: new Date(), }, }); logger.info( `DataflowService: 데이터 연결 수정 완료 - Bridge ID: ${bridgeId}` ); return updatedBridge; } catch (error) { logger.error("DataflowService: 데이터 연결 수정 실패", error); throw error; } } /** * 데이터 연결 삭제 (소프트 삭제) */ async deleteDataLink( bridgeId: number, companyCode: string, deletedBy: string ) { try { logger.info( `DataflowService: 데이터 연결 삭제 시작 - Bridge ID: ${bridgeId}` ); const whereCondition: any = { bridge_id: bridgeId, is_active: "Y", }; // 관리자가 아닌 경우 회사코드 제한 if (companyCode !== "*") { whereCondition.company_code = companyCode; } await prisma.data_relationship_bridge.update({ where: whereCondition, data: { is_active: "N", updated_at: new Date(), updated_by: deletedBy, }, }); logger.info( `DataflowService: 데이터 연결 삭제 완료 - Bridge ID: ${bridgeId}` ); return true; } catch (error) { logger.error("DataflowService: 데이터 연결 삭제 실패", error); throw error; } } /** * 관계 삭제 시 연결된 모든 데이터도 삭제 */ async deleteAllLinkedDataByRelationship( relationshipId: number, companyCode: string, deletedBy: string ) { try { logger.info( `DataflowService: 관계별 모든 데이터 연결 삭제 시작 - 관계ID: ${relationshipId}` ); const whereCondition: any = { relationship_id: relationshipId, is_active: "Y", }; // 관리자가 아닌 경우 회사코드 제한 if (companyCode !== "*") { whereCondition.company_code = companyCode; } const result = await prisma.data_relationship_bridge.updateMany({ where: whereCondition, data: { is_active: "N", updated_at: new Date(), updated_by: deletedBy, }, }); logger.info( `DataflowService: 관계별 모든 데이터 연결 삭제 완료 - ${result.count}건` ); return result.count; } catch (error) { logger.error("DataflowService: 관계별 모든 데이터 연결 삭제 실패", error); throw error; } } }