phase2.4 전환 완료

This commit is contained in:
kjs
2025-10-01 10:03:41 +09:00
parent 3c06d35374
commit 57f1d8274e
4 changed files with 622 additions and 501 deletions

View File

@@ -1,8 +1,6 @@
import { PrismaClient } from "@prisma/client";
import { query, queryOne, transaction } from "../database/db";
import { logger } from "../utils/logger";
const prisma = new PrismaClient();
// 테이블 관계 생성 데이터 타입
interface CreateTableRelationshipData {
diagramId?: number; // 기존 관계도에 추가하는 경우
@@ -45,33 +43,36 @@ export class DataflowService {
if (!diagramId) {
// 새로운 관계도인 경우, 새로운 diagram_id 생성
// 현재 최대 diagram_id + 1
const maxDiagramId = await prisma.table_relationships.findFirst({
where: {
company_code: data.companyCode,
},
orderBy: {
diagram_id: "desc",
},
select: {
diagram_id: true,
},
});
const maxDiagramId = await queryOne<{ diagram_id: number }>(
`SELECT diagram_id FROM table_relationships
WHERE company_code = $1
ORDER BY diagram_id DESC
LIMIT 1`,
[data.companyCode]
);
diagramId = (maxDiagramId?.diagram_id || 0) + 1;
}
// 중복 관계 확인 (같은 diagram_id 내에서)
const existingRelationship = await prisma.table_relationships.findFirst({
where: {
diagram_id: diagramId,
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",
},
});
const existingRelationship = await queryOne(
`SELECT * FROM table_relationships
WHERE diagram_id = $1
AND from_table_name = $2
AND from_column_name = $3
AND to_table_name = $4
AND to_column_name = $5
AND company_code = $6
AND is_active = 'Y'`,
[
diagramId,
data.fromTableName,
data.fromColumnName,
data.toTableName,
data.toColumnName,
data.companyCode,
]
);
if (existingRelationship) {
throw new Error(
@@ -80,22 +81,28 @@ export class DataflowService {
}
// 새 관계 생성
const relationship = await prisma.table_relationships.create({
data: {
diagram_id: diagramId,
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,
},
});
const relationship = await queryOne(
`INSERT INTO table_relationships (
diagram_id, relationship_name, from_table_name, from_column_name,
to_table_name, to_column_name, relationship_type, connection_type,
company_code, settings, created_by, updated_by, created_at, updated_at
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, now(), now())
RETURNING *`,
[
diagramId,
data.relationshipName,
data.fromTableName,
data.fromColumnName,
data.toTableName,
data.toColumnName,
data.relationshipType,
data.connectionType,
data.companyCode,
JSON.stringify(data.settings),
data.createdBy,
data.createdBy,
]
);
logger.info(
`DataflowService: 테이블 관계 생성 완료 - ID: ${relationship.relationship_id}, Diagram ID: ${relationship.diagram_id}`
@@ -117,20 +124,16 @@ export class DataflowService {
);
// 관리자는 모든 회사의 관계를 볼 수 있음
const whereCondition: any = {
is_active: "Y",
};
let queryText = `SELECT * FROM table_relationships WHERE is_active = 'Y'`;
const params: any[] = [];
if (companyCode !== "*") {
whereCondition.company_code = companyCode;
queryText += ` AND company_code = $1`;
params.push(companyCode);
}
const relationships = await prisma.table_relationships.findMany({
where: whereCondition,
orderBy: {
created_date: "desc",
},
});
queryText += ` ORDER BY created_date DESC`;
const relationships = await query(queryText, params);
logger.info(
`DataflowService: 테이블 관계 목록 조회 완료 - ${relationships.length}`
@@ -151,19 +154,16 @@ export class DataflowService {
`DataflowService: 테이블 관계 조회 시작 - ID: ${relationshipId}, 회사코드: ${companyCode}`
);
const whereCondition: any = {
relationship_id: relationshipId,
is_active: "Y",
};
let queryText = `SELECT * FROM table_relationships WHERE relationship_id = $1 AND is_active = 'Y'`;
const params: any[] = [relationshipId];
// 관리자가 아닌 경우 회사코드 제한
if (companyCode !== "*") {
whereCondition.company_code = companyCode;
queryText += ` AND company_code = $2`;
params.push(companyCode);
}
const relationship = await prisma.table_relationships.findFirst({
where: whereCondition,
});
const relationship = await queryOne(queryText, params);
if (relationship) {
logger.info(
@@ -206,15 +206,55 @@ export class DataflowService {
}
// 관계 수정
const relationship = await prisma.table_relationships.update({
where: {
relationship_id: relationshipId,
},
data: {
...updateData,
updated_date: new Date(),
},
});
const updates: string[] = [];
const params: any[] = [];
let paramIndex = 1;
if (updateData.relationshipName !== undefined) {
updates.push(`relationship_name = $${paramIndex++}`);
params.push(updateData.relationshipName);
}
if (updateData.fromTableName !== undefined) {
updates.push(`from_table_name = $${paramIndex++}`);
params.push(updateData.fromTableName);
}
if (updateData.fromColumnName !== undefined) {
updates.push(`from_column_name = $${paramIndex++}`);
params.push(updateData.fromColumnName);
}
if (updateData.toTableName !== undefined) {
updates.push(`to_table_name = $${paramIndex++}`);
params.push(updateData.toTableName);
}
if (updateData.toColumnName !== undefined) {
updates.push(`to_column_name = $${paramIndex++}`);
params.push(updateData.toColumnName);
}
if (updateData.relationshipType !== undefined) {
updates.push(`relationship_type = $${paramIndex++}`);
params.push(updateData.relationshipType);
}
if (updateData.connectionType !== undefined) {
updates.push(`connection_type = $${paramIndex++}`);
params.push(updateData.connectionType);
}
if (updateData.settings !== undefined) {
updates.push(`settings = $${paramIndex++}`);
params.push(JSON.stringify(updateData.settings));
}
updates.push(`updated_by = $${paramIndex++}`);
params.push(updateData.updatedBy);
updates.push(`updated_date = now()`);
params.push(relationshipId);
const relationship = await queryOne(
`UPDATE table_relationships
SET ${updates.join(", ")}
WHERE relationship_id = $${paramIndex}
RETURNING *`,
params
);
logger.info(
`DataflowService: 테이블 관계 수정 완료 - ID: ${relationshipId}`
@@ -245,15 +285,12 @@ export class DataflowService {
}
// 소프트 삭제 (is_active = 'N')
await prisma.table_relationships.update({
where: {
relationship_id: relationshipId,
},
data: {
is_active: "N",
updated_date: new Date(),
},
});
await query(
`UPDATE table_relationships
SET is_active = 'N', updated_date = now()
WHERE relationship_id = $1`,
[relationshipId]
);
logger.info(
`DataflowService: 테이블 관계 삭제 완료 - ID: ${relationshipId}`
@@ -274,22 +311,21 @@ export class DataflowService {
`DataflowService: 테이블별 관계 조회 시작 - 테이블: ${tableName}, 회사코드: ${companyCode}`
);
const whereCondition: any = {
OR: [{ from_table_name: tableName }, { to_table_name: tableName }],
is_active: "Y",
};
let queryText = `
SELECT * FROM table_relationships
WHERE (from_table_name = $1 OR to_table_name = $1)
AND is_active = 'Y'
`;
const params: any[] = [tableName];
// 관리자가 아닌 경우 회사코드 제한
if (companyCode !== "*") {
whereCondition.company_code = companyCode;
queryText += ` AND company_code = $2`;
params.push(companyCode);
}
const relationships = await prisma.table_relationships.findMany({
where: whereCondition,
orderBy: {
created_date: "desc",
},
});
queryText += ` ORDER BY created_date DESC`;
const relationships = await query(queryText, params);
logger.info(
`DataflowService: 테이블별 관계 조회 완료 - ${relationships.length}`
@@ -313,22 +349,20 @@ export class DataflowService {
`DataflowService: 연결타입별 관계 조회 시작 - 타입: ${connectionType}, 회사코드: ${companyCode}`
);
const whereCondition: any = {
connection_type: connectionType,
is_active: "Y",
};
let queryText = `
SELECT * FROM table_relationships
WHERE connection_type = $1 AND is_active = 'Y'
`;
const params: any[] = [connectionType];
// 관리자가 아닌 경우 회사코드 제한
if (companyCode !== "*") {
whereCondition.company_code = companyCode;
queryText += ` AND company_code = $2`;
params.push(companyCode);
}
const relationships = await prisma.table_relationships.findMany({
where: whereCondition,
orderBy: {
created_date: "desc",
},
});
queryText += ` ORDER BY created_date DESC`;
const relationships = await query(queryText, params);
logger.info(
`DataflowService: 연결타입별 관계 조회 완료 - ${relationships.length}`
@@ -349,47 +383,53 @@ export class DataflowService {
`DataflowService: 관계 통계 조회 시작 - 회사코드: ${companyCode}`
);
const whereCondition: any = {
is_active: "Y",
};
let whereClause = `WHERE is_active = 'Y'`;
const params: any[] = [];
// 관리자가 아닌 경우 회사코드 제한
if (companyCode !== "*") {
whereCondition.company_code = companyCode;
whereClause += ` AND company_code = $1`;
params.push(companyCode);
}
// 전체 관계 수
const totalCount = await prisma.table_relationships.count({
where: whereCondition,
});
const totalCountResult = await queryOne<{ count: string }>(
`SELECT COUNT(*) as count FROM table_relationships ${whereClause}`,
params
);
const totalCount = parseInt(totalCountResult?.count || "0", 10);
// 관계 타입별 통계
const relationshipTypeStats = await prisma.table_relationships.groupBy({
by: ["relationship_type"],
where: whereCondition,
_count: {
relationship_id: true,
},
});
const relationshipTypeStats = await query<{
relationship_type: string;
count: string;
}>(
`SELECT relationship_type, COUNT(*) as count
FROM table_relationships ${whereClause}
GROUP BY relationship_type`,
params
);
// 연결 타입별 통계
const connectionTypeStats = await prisma.table_relationships.groupBy({
by: ["connection_type"],
where: whereCondition,
_count: {
relationship_id: true,
},
});
const connectionTypeStats = await query<{
connection_type: string;
count: string;
}>(
`SELECT connection_type, COUNT(*) as count
FROM table_relationships ${whereClause}
GROUP BY connection_type`,
params
);
const stats = {
totalCount,
relationshipTypeStats: relationshipTypeStats.map((stat) => ({
type: stat.relationship_type,
count: stat._count.relationship_id,
count: parseInt(stat.count, 10),
})),
connectionTypeStats: connectionTypeStats.map((stat) => ({
type: stat.connection_type,
count: stat._count.relationship_id,
count: parseInt(stat.count, 10),
})),
};
@@ -422,19 +462,25 @@ export class DataflowService {
`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,
},
});
const bridge = await queryOne(
`INSERT INTO data_relationship_bridge (
relationship_id, from_table_name, from_column_name, to_table_name,
to_column_name, connection_type, company_code, bridge_data,
created_by, created_at
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, now())
RETURNING *`,
[
linkData.relationshipId,
linkData.fromTableName,
linkData.fromColumnName,
linkData.toTableName,
linkData.toColumnName,
linkData.connectionType,
linkData.companyCode,
JSON.stringify(linkData.bridgeData || {}),
linkData.createdBy,
]
);
logger.info(
`DataflowService: 데이터 연결 생성 완료 - Bridge ID: ${bridge.bridge_id}`
@@ -458,21 +504,20 @@ export class DataflowService {
`DataflowService: 관계별 연결 데이터 조회 시작 - 관계ID: ${relationshipId}`
);
const whereCondition: any = {
relationship_id: relationshipId,
is_active: "Y",
};
let queryText = `
SELECT * FROM data_relationship_bridge
WHERE relationship_id = $1 AND is_active = 'Y'
`;
const params: any[] = [relationshipId];
// 관리자가 아닌 경우 회사코드 제한
if (companyCode !== "*") {
whereCondition.company_code = companyCode;
queryText += ` AND company_code = $2`;
params.push(companyCode);
}
const linkedData = await prisma.data_relationship_bridge.findMany({
where: whereCondition,
orderBy: { created_at: "desc" },
// include 제거 - relationship 관계가 스키마에 정의되지 않음
});
queryText += ` ORDER BY created_at DESC`;
const linkedData = await query(queryText, params);
logger.info(
`DataflowService: 관계별 연결 데이터 조회 완료 - ${linkedData.length}`
@@ -497,23 +542,22 @@ export class DataflowService {
`DataflowService: 테이블별 연결 데이터 조회 시작 - 테이블: ${tableName}`
);
const whereCondition: any = {
OR: [{ from_table_name: tableName }, { to_table_name: tableName }],
is_active: "Y",
};
let queryText = `
SELECT * FROM data_relationship_bridge
WHERE (from_table_name = $1 OR to_table_name = $1) AND is_active = 'Y'
`;
const params: any[] = [tableName];
// keyValue 파라미터는 더 이상 사용하지 않음 (key_value 필드 제거됨)
// 회사코드 필터링
if (companyCode && companyCode !== "*") {
whereCondition.company_code = companyCode;
queryText += ` AND company_code = $2`;
params.push(companyCode);
}
const linkedData = await prisma.data_relationship_bridge.findMany({
where: whereCondition,
orderBy: { created_at: "desc" },
// include 제거 - relationship 관계가 스키마에 정의되지 않음
});
queryText += ` ORDER BY created_at DESC`;
const linkedData = await query(queryText, params);
logger.info(
`DataflowService: 테이블별 연결 데이터 조회 완료 - ${linkedData.length}`
@@ -541,23 +585,25 @@ export class DataflowService {
`DataflowService: 데이터 연결 수정 시작 - Bridge ID: ${bridgeId}`
);
const whereCondition: any = {
bridge_id: bridgeId,
is_active: "Y",
};
let queryText = `
UPDATE data_relationship_bridge
SET bridge_data = $1, updated_by = $2, updated_at = now()
WHERE bridge_id = $3 AND is_active = 'Y'
`;
const params: any[] = [
JSON.stringify(updateData.bridgeData),
updateData.updatedBy,
bridgeId,
];
// 관리자가 아닌 경우 회사코드 제한
if (companyCode !== "*") {
whereCondition.company_code = companyCode;
queryText += ` AND company_code = $4`;
params.push(companyCode);
}
const updatedBridge = await prisma.data_relationship_bridge.update({
where: whereCondition,
data: {
...updateData,
updated_at: new Date(),
},
});
queryText += ` RETURNING *`;
const updatedBridge = await queryOne(queryText, params);
logger.info(
`DataflowService: 데이터 연결 수정 완료 - Bridge ID: ${bridgeId}`
@@ -582,24 +628,20 @@ export class DataflowService {
`DataflowService: 데이터 연결 삭제 시작 - Bridge ID: ${bridgeId}`
);
const whereCondition: any = {
bridge_id: bridgeId,
is_active: "Y",
};
let queryText = `
UPDATE data_relationship_bridge
SET is_active = 'N', updated_at = now(), updated_by = $1
WHERE bridge_id = $2 AND is_active = 'Y'
`;
const params: any[] = [deletedBy, bridgeId];
// 관리자가 아닌 경우 회사코드 제한
if (companyCode !== "*") {
whereCondition.company_code = companyCode;
queryText += ` AND company_code = $3`;
params.push(companyCode);
}
await prisma.data_relationship_bridge.update({
where: whereCondition,
data: {
is_active: "N",
updated_at: new Date(),
updated_by: deletedBy,
},
});
await query(queryText, params);
logger.info(
`DataflowService: 데이터 연결 삭제 완료 - Bridge ID: ${bridgeId}`
@@ -624,29 +666,25 @@ export class DataflowService {
`DataflowService: 관계별 모든 데이터 연결 삭제 시작 - 관계ID: ${relationshipId}`
);
const whereCondition: any = {
relationship_id: relationshipId,
is_active: "Y",
};
let queryText = `
UPDATE data_relationship_bridge
SET is_active = 'N', updated_at = now(), updated_by = $1
WHERE relationship_id = $2 AND is_active = 'Y'
`;
const params: any[] = [deletedBy, relationshipId];
// 관리자가 아닌 경우 회사코드 제한
if (companyCode !== "*") {
whereCondition.company_code = companyCode;
queryText += ` AND company_code = $3`;
params.push(companyCode);
}
const result = await prisma.data_relationship_bridge.updateMany({
where: whereCondition,
data: {
is_active: "N",
updated_at: new Date(),
updated_by: deletedBy,
},
});
const result = await query(queryText, params);
logger.info(
`DataflowService: 관계별 모든 데이터 연결 삭제 완료 - ${result.count}`
`DataflowService: 관계별 모든 데이터 연결 삭제 완료 - ${result.length}`
);
return result.count;
return result.length;
} catch (error) {
logger.error("DataflowService: 관계별 모든 데이터 연결 삭제 실패", error);
throw error;
@@ -670,47 +708,51 @@ export class DataflowService {
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'
`;
const tableExists = await query(
`SELECT table_name
FROM information_schema.tables
WHERE table_name = $1 AND table_schema = 'public'`,
[tableName.toLowerCase()]
);
if (
!tableExists ||
(Array.isArray(tableExists) && tableExists.length === 0)
) {
if (!tableExists || tableExists.length === 0) {
throw new Error(`테이블 '${tableName}'이 존재하지 않습니다.`);
}
// 전체 데이터 개수 조회
// 전체 데이터 개수 조회 및 데이터 조회
let totalCountQuery = `SELECT COUNT(*) as total FROM "${tableName}"`;
let dataQuery = `SELECT * FROM "${tableName}"`;
const queryParams: any[] = [];
// 검색 조건 추가
// 검색 조건 추가 (SQL Injection 방지를 위해 파라미터 바인딩 사용)
if (search && searchColumn) {
const whereCondition = `WHERE "${searchColumn}" ILIKE '%${search}%'`;
const paramIndex = queryParams.length + 1;
const whereCondition = `WHERE "${searchColumn}" ILIKE $${paramIndex}`;
totalCountQuery += ` ${whereCondition}`;
dataQuery += ` ${whereCondition}`;
queryParams.push(`%${search}%`);
}
// 페이징 처리
const offset = (page - 1) * limit;
dataQuery += ` ORDER BY 1 LIMIT ${limit} OFFSET ${offset}`;
const limitIndex = queryParams.length + 1;
const offsetIndex = queryParams.length + 2;
dataQuery += ` ORDER BY 1 LIMIT $${limitIndex} OFFSET $${offsetIndex}`;
const dataQueryParams = [...queryParams, limit, offset];
// 실제 쿼리 실행
const [totalResult, dataResult] = await Promise.all([
prisma.$queryRawUnsafe(totalCountQuery),
prisma.$queryRawUnsafe(dataQuery),
query(totalCountQuery, queryParams.length > 0 ? queryParams : []),
query(dataQuery, dataQueryParams),
]);
const total =
Array.isArray(totalResult) && totalResult.length > 0
totalResult && totalResult.length > 0
? Number((totalResult[0] as any).total)
: 0;
const data = Array.isArray(dataResult) ? dataResult : [];
const data = dataResult || [];
const result = {
data,
@@ -752,52 +794,43 @@ export class DataflowService {
`DataflowService: 관계도 목록 조회 시작 - ${companyCode}, page: ${page}, size: ${size}, search: ${searchTerm}`
);
// diagram_id별로 그룹화하여 조회
const whereCondition = {
company_code: companyCode,
is_active: "Y",
...(searchTerm && {
OR: [
{
relationship_name: {
contains: searchTerm,
mode: "insensitive" as any,
},
},
{
from_table_name: {
contains: searchTerm,
mode: "insensitive" as any,
},
},
{
to_table_name: {
contains: searchTerm,
mode: "insensitive" as any,
},
},
],
}),
};
// WHERE 조건 구성
const params: any[] = [companyCode];
let whereClause = `WHERE company_code = $1 AND is_active = 'Y'`;
if (searchTerm) {
whereClause += ` AND (
relationship_name ILIKE $2 OR
from_table_name ILIKE $2 OR
to_table_name ILIKE $2
)`;
params.push(`%${searchTerm}%`);
}
// diagram_id별로 그룹화된 데이터 조회
const relationships = await prisma.table_relationships.findMany({
where: whereCondition,
select: {
relationship_id: true,
diagram_id: true,
relationship_name: true,
from_table_name: true,
to_table_name: true,
connection_type: true,
relationship_type: true,
created_date: true,
created_by: true,
updated_date: true,
updated_by: true,
},
orderBy: [{ diagram_id: "asc" }, { created_date: "desc" }],
});
const relationships = await query<{
relationship_id: number;
diagram_id: number;
relationship_name: string;
from_table_name: string;
to_table_name: string;
connection_type: string;
relationship_type: string;
created_date: Date;
created_by: string;
updated_date: Date;
updated_by: string;
}>(
`SELECT
relationship_id, diagram_id, relationship_name,
from_table_name, to_table_name, connection_type,
relationship_type, created_date, created_by,
updated_date, updated_by
FROM table_relationships
${whereClause}
ORDER BY diagram_id ASC, created_date DESC`,
params
);
// diagram_id별로 그룹화
const diagramMap = new Map<number, any>();
@@ -880,16 +913,14 @@ export class DataflowService {
`DataflowService: 관계도 관계 조회 시작 - ${companyCode}, diagram: ${diagramName}`
);
const relationships = await prisma.table_relationships.findMany({
where: {
company_code: companyCode,
relationship_name: diagramName,
is_active: "Y",
},
orderBy: {
created_date: "asc",
},
});
const relationships = await query(
`SELECT * FROM table_relationships
WHERE company_code = $1
AND relationship_name = $2
AND is_active = 'Y'
ORDER BY created_date ASC`,
[companyCode, diagramName]
);
logger.info(
`DataflowService: 관계도 관계 조회 완료 - ${diagramName}, ${relationships.length}개 관계`
@@ -916,13 +947,27 @@ export class DataflowService {
logger.info(`DataflowService: 관계도 복사 시작 - ${originalDiagramName}`);
// 원본 관계도의 모든 관계 조회
const originalRelationships = await prisma.table_relationships.findMany({
where: {
company_code: companyCode,
relationship_name: originalDiagramName,
is_active: "Y",
},
});
const originalRelationships = await query<{
relationship_id: number;
diagram_id: number;
relationship_name: string;
from_table_name: string;
from_column_name: string;
to_table_name: string;
to_column_name: string;
relationship_type: string;
connection_type: string;
settings: any;
company_code: string;
created_by: string;
updated_by: string;
}>(
`SELECT * FROM table_relationships
WHERE company_code = $1
AND relationship_name = $2
AND is_active = 'Y'`,
[companyCode, originalDiagramName]
);
if (originalRelationships.length === 0) {
throw new Error("복사할 관계도를 찾을 수 없습니다.");
@@ -933,13 +978,14 @@ export class DataflowService {
let counter = 1;
while (true) {
const existingDiagram = await prisma.table_relationships.findFirst({
where: {
company_code: companyCode,
relationship_name: newDiagramName,
is_active: "Y",
},
});
const existingDiagram = await queryOne(
`SELECT relationship_id FROM table_relationships
WHERE company_code = $1
AND relationship_name = $2
AND is_active = 'Y'
LIMIT 1`,
[companyCode, newDiagramName]
);
if (!existingDiagram) {
break;
@@ -950,42 +996,51 @@ export class DataflowService {
}
// 새로운 diagram_id 생성
const maxDiagramId = await prisma.table_relationships.findFirst({
where: {
company_code: companyCode,
},
orderBy: {
diagram_id: "desc",
},
select: {
diagram_id: true,
},
});
const maxDiagramId = await queryOne<{ diagram_id: number }>(
`SELECT diagram_id FROM table_relationships
WHERE company_code = $1
ORDER BY diagram_id DESC
LIMIT 1`,
[companyCode]
);
const newDiagramId = (maxDiagramId?.diagram_id || 0) + 1;
// 트랜잭션으로 모든 관계 복사
const copiedRelationships = await prisma.$transaction(
originalRelationships.map((rel) =>
prisma.table_relationships.create({
data: {
diagram_id: newDiagramId,
relationship_name: newDiagramName,
from_table_name: rel.from_table_name,
from_column_name: rel.from_column_name,
to_table_name: rel.to_table_name,
to_column_name: rel.to_column_name,
relationship_type: rel.relationship_type,
connection_type: rel.connection_type,
settings: rel.settings as any,
company_code: rel.company_code,
is_active: "Y",
created_by: rel.created_by,
updated_by: rel.updated_by,
},
})
)
);
const copiedRelationships = await transaction(async (client) => {
const results: any[] = [];
for (const rel of originalRelationships) {
const result = await client.query(
`INSERT INTO table_relationships (
diagram_id, relationship_name, from_table_name, from_column_name,
to_table_name, to_column_name, relationship_type, connection_type,
settings, company_code, is_active, created_by, updated_by, created_at, updated_at
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, 'Y', $11, $12, now(), now())
RETURNING *`,
[
newDiagramId,
newDiagramName,
rel.from_table_name,
rel.from_column_name,
rel.to_table_name,
rel.to_column_name,
rel.relationship_type,
rel.connection_type,
rel.settings,
rel.company_code,
rel.created_by,
rel.updated_by,
]
);
if (result.rows && result.rows.length > 0) {
results.push(result.rows[0]);
}
}
return results;
});
logger.info(
`DataflowService: 관계도 복사 완료 - ${originalDiagramName}${newDiagramName} (diagram_id: ${newDiagramId}), ${copiedRelationships.length}개 관계 복사`
@@ -1012,18 +1067,20 @@ export class DataflowService {
logger.info(`DataflowService: 관계도 삭제 시작 - ${diagramName}`);
// 관계도의 모든 관계 삭제 (하드 삭제)
const deleteResult = await prisma.table_relationships.deleteMany({
where: {
company_code: companyCode,
relationship_name: diagramName,
},
});
logger.info(
`DataflowService: 관계도 삭제 완료 - ${diagramName}, ${deleteResult.count}개 관계 삭제`
const deleteResult = await query<{ count: number }>(
`DELETE FROM table_relationships
WHERE company_code = $1 AND relationship_name = $2
RETURNING relationship_id`,
[companyCode, diagramName]
);
return deleteResult.count;
const count = deleteResult.length;
logger.info(
`DataflowService: 관계도 삭제 완료 - ${diagramName}, ${count}개 관계 삭제`
);
return count;
} catch (error) {
logger.error(`DataflowService: 관계도 삭제 실패 - ${diagramName}`, error);
throw error;
@@ -1043,20 +1100,20 @@ export class DataflowService {
);
// diagram_id로 모든 관계 조회
const relationships = await prisma.table_relationships.findMany({
where: {
diagram_id: diagramId,
company_code: companyCode,
is_active: "Y",
},
orderBy: [{ relationship_id: "asc" }],
});
const relationships = await query(
`SELECT * FROM table_relationships
WHERE diagram_id = $1
AND company_code = $2
AND is_active = 'Y'
ORDER BY relationship_id ASC`,
[diagramId, companyCode]
);
logger.info(
`DataflowService: diagram_id로 관계도 관계 조회 완료 - ${relationships.length}개 관계`
);
return relationships.map((rel) => ({
return relationships.map((rel: any) => ({
...rel,
settings: rel.settings as any,
}));
@@ -1082,16 +1139,14 @@ export class DataflowService {
);
// 먼저 해당 relationship_id의 diagram_id를 찾음
const targetRelationship = await prisma.table_relationships.findFirst({
where: {
relationship_id: relationshipId,
company_code: companyCode,
is_active: "Y",
},
select: {
diagram_id: true,
},
});
const targetRelationship = await queryOne<{ diagram_id: number }>(
`SELECT diagram_id FROM table_relationships
WHERE relationship_id = $1
AND company_code = $2
AND is_active = 'Y'
LIMIT 1`,
[relationshipId, companyCode]
);
if (!targetRelationship) {
throw new Error("해당 관계 ID를 찾을 수 없습니다.");