2025-09-08 16:46:53 +09:00
|
|
|
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}`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-08 18:18:47 +09:00
|
|
|
// 트랜잭션으로 관계 생성과 단순 키값 연결 처리
|
|
|
|
|
const result = await prisma.$transaction(async (tx) => {
|
|
|
|
|
// 1. 새 관계 생성
|
|
|
|
|
const relationship = await tx.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,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 2. 단순 키값 연결인 경우 data_relationship_bridge에도 기본 레코드 생성
|
|
|
|
|
if (data.connectionType === "simple-key") {
|
|
|
|
|
logger.info(
|
|
|
|
|
`단순 키값 연결이므로 data_relationship_bridge에 기본 연결 레코드 생성 - 관계ID: ${relationship.relationship_id}`
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
await tx.data_relationship_bridge.create({
|
|
|
|
|
data: {
|
|
|
|
|
relationship_id: relationship.relationship_id,
|
|
|
|
|
from_table_name: data.fromTableName,
|
|
|
|
|
from_column_name: data.fromColumnName,
|
|
|
|
|
to_table_name: data.toTableName,
|
|
|
|
|
to_column_name: data.toColumnName,
|
|
|
|
|
connection_type: data.connectionType,
|
|
|
|
|
company_code: data.companyCode,
|
|
|
|
|
bridge_data: {
|
|
|
|
|
autoCreated: true,
|
|
|
|
|
createdAt: new Date().toISOString(),
|
|
|
|
|
notes: "단순 키값 연결 - 테이블과 컬럼 관계만 정의",
|
|
|
|
|
connectionInfo: `${data.fromTableName}.${data.fromColumnName} ↔ ${data.toTableName}.${data.toColumnName}`,
|
|
|
|
|
settings: data.settings,
|
|
|
|
|
},
|
|
|
|
|
created_by: data.createdBy,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
logger.info(
|
|
|
|
|
`단순 키값 연결 기본 레코드 생성 완료 - 관계ID: ${relationship.relationship_id}`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return relationship;
|
2025-09-08 16:46:53 +09:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
logger.info(
|
2025-09-08 18:18:47 +09:00
|
|
|
`DataflowService: 테이블 관계 생성 완료 - ID: ${result.relationship_id}`
|
2025-09-08 16:46:53 +09:00
|
|
|
);
|
2025-09-08 18:18:47 +09:00
|
|
|
return result;
|
2025-09-08 16:46:53 +09:00
|
|
|
} 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;
|
|
|
|
|
toTableName: string;
|
|
|
|
|
toColumnName: 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,
|
|
|
|
|
to_table_name: linkData.toTableName,
|
|
|
|
|
to_column_name: linkData.toColumnName,
|
|
|
|
|
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",
|
|
|
|
|
};
|
|
|
|
|
|
2025-09-08 18:18:47 +09:00
|
|
|
// keyValue 파라미터는 더 이상 사용하지 않음 (key_value 필드 제거됨)
|
2025-09-08 16:46:53 +09:00
|
|
|
|
|
|
|
|
// 회사코드 필터링
|
|
|
|
|
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: {
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-08 18:18:47 +09:00
|
|
|
|
|
|
|
|
// ==================== 테이블 데이터 조회 ====================
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 테이블 실제 데이터 조회 (페이징)
|
|
|
|
|
*/
|
|
|
|
|
async getTableData(
|
|
|
|
|
tableName: string,
|
|
|
|
|
page: number = 1,
|
|
|
|
|
limit: number = 10,
|
|
|
|
|
search: string = "",
|
|
|
|
|
searchColumn: string = "",
|
|
|
|
|
companyCode: string = "*"
|
|
|
|
|
) {
|
|
|
|
|
try {
|
|
|
|
|
logger.info(`DataflowService: 테이블 데이터 조회 시작 - ${tableName}`);
|
|
|
|
|
|
|
|
|
|
// 테이블 존재 여부 확인 (정보 스키마 사용)
|
|
|
|
|
const tableExists = await prisma.$queryRaw`
|
|
|
|
|
SELECT table_name
|
|
|
|
|
FROM information_schema.tables
|
|
|
|
|
WHERE table_name = ${tableName.toLowerCase()}
|
|
|
|
|
AND table_schema = 'public'
|
|
|
|
|
`;
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
!tableExists ||
|
|
|
|
|
(Array.isArray(tableExists) && tableExists.length === 0)
|
|
|
|
|
) {
|
|
|
|
|
throw new Error(`테이블 '${tableName}'이 존재하지 않습니다.`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 전체 데이터 개수 조회
|
|
|
|
|
let totalCountQuery = `SELECT COUNT(*) as total FROM "${tableName}"`;
|
|
|
|
|
let dataQuery = `SELECT * FROM "${tableName}"`;
|
|
|
|
|
|
|
|
|
|
// 검색 조건 추가
|
|
|
|
|
if (search && searchColumn) {
|
|
|
|
|
const whereCondition = `WHERE "${searchColumn}" ILIKE '%${search}%'`;
|
|
|
|
|
totalCountQuery += ` ${whereCondition}`;
|
|
|
|
|
dataQuery += ` ${whereCondition}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 페이징 처리
|
|
|
|
|
const offset = (page - 1) * limit;
|
|
|
|
|
dataQuery += ` ORDER BY 1 LIMIT ${limit} OFFSET ${offset}`;
|
|
|
|
|
|
|
|
|
|
// 실제 쿼리 실행
|
|
|
|
|
const [totalResult, dataResult] = await Promise.all([
|
|
|
|
|
prisma.$queryRawUnsafe(totalCountQuery),
|
|
|
|
|
prisma.$queryRawUnsafe(dataQuery),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
const total =
|
|
|
|
|
Array.isArray(totalResult) && totalResult.length > 0
|
|
|
|
|
? Number((totalResult[0] as any).total)
|
|
|
|
|
: 0;
|
|
|
|
|
|
|
|
|
|
const data = Array.isArray(dataResult) ? dataResult : [];
|
|
|
|
|
|
|
|
|
|
const result = {
|
|
|
|
|
data,
|
|
|
|
|
pagination: {
|
|
|
|
|
page,
|
|
|
|
|
limit,
|
|
|
|
|
total,
|
|
|
|
|
totalPages: Math.ceil(total / limit),
|
|
|
|
|
hasNext: page < Math.ceil(total / limit),
|
|
|
|
|
hasPrev: page > 1,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
logger.info(
|
|
|
|
|
`DataflowService: 테이블 데이터 조회 완료 - ${tableName}, 총 ${total}건 중 ${data.length}건 조회`
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error(
|
|
|
|
|
`DataflowService: 테이블 데이터 조회 실패 - ${tableName}`,
|
|
|
|
|
error
|
|
|
|
|
);
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-08 16:46:53 +09:00
|
|
|
}
|