phase2.4 전환 완료
This commit is contained in:
@@ -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를 찾을 수 없습니다.");
|
||||
|
||||
Reference in New Issue
Block a user