digramId를 사용해 제어 관계 그룹화

This commit is contained in:
2025-09-09 18:42:01 +09:00
parent 7bcd405a04
commit 5043b11149
11 changed files with 312 additions and 113 deletions

View File

@@ -5108,6 +5108,7 @@ model code_info {
// 테이블 간 관계 정의
model table_relationships {
relationship_id Int @id @default(autoincrement())
diagram_id Int // 관계도 그룹 식별자
relationship_name String @db.VarChar(200)
from_table_name String @db.VarChar(100)
from_column_name String @db.VarChar(100)
@@ -5127,8 +5128,10 @@ model table_relationships {
bridges data_relationship_bridge[]
@@index([company_code], map: "idx_table_relationships_company_code")
@@index([diagram_id], map: "idx_table_relationships_diagram_id")
@@index([from_table_name], map: "idx_table_relationships_from_table")
@@index([to_table_name], map: "idx_table_relationships_to_table")
@@index([company_code, diagram_id], map: "idx_table_relationships_company_diagram")
}
// 테이블 간 데이터 관계 중계 테이블 - 실제 데이터 연결 정보 저장

View File

@@ -15,6 +15,7 @@ export async function createTableRelationship(
logger.info("=== 테이블 관계 생성 시작 ===");
const {
diagramId,
relationshipName,
fromTableName,
fromColumnName,
@@ -52,6 +53,7 @@ export async function createTableRelationship(
const dataflowService = new DataflowService();
const relationship = await dataflowService.createTableRelationship({
diagramId: diagramId ? parseInt(diagramId) : undefined,
relationshipName,
fromTableName,
fromColumnName,
@@ -828,7 +830,62 @@ export async function deleteDiagram(
}
/**
* relationship_id로 관계도 관계 조회
* diagram_id로 관계도 관계 조회
*/
export async function getDiagramRelationshipsByDiagramId(
req: AuthenticatedRequest,
res: Response
): Promise<void> {
try {
const { diagramId } = req.params;
const companyCode = (req.user as any)?.company_code || "*";
if (!diagramId) {
const response: ApiResponse<null> = {
success: false,
message: "관계도 ID가 필요합니다.",
error: {
code: "MISSING_DIAGRAM_ID",
details: "diagramId 파라미터가 필요합니다.",
},
};
res.status(400).json(response);
return;
}
const dataflowService = new DataflowService();
const relationships =
await dataflowService.getDiagramRelationshipsByDiagramId(
companyCode,
parseInt(diagramId)
);
const response: ApiResponse<any[]> = {
success: true,
message: "관계도 관계 목록을 성공적으로 조회했습니다.",
data: relationships,
};
res.status(200).json(response);
} catch (error) {
logger.error("관계도 관계 조회 실패:", error);
const response: ApiResponse<null> = {
success: false,
message: "관계도 관계 조회에 실패했습니다.",
error: {
code: "DIAGRAM_RELATIONSHIPS_FETCH_FAILED",
details:
error instanceof Error
? error.message
: "알 수 없는 오류가 발생했습니다.",
},
};
res.status(500).json(response);
}
}
/**
* relationship_id로 관계도 관계 조회 (하위 호환성 유지)
*/
export async function getDiagramRelationshipsByRelationshipId(
req: AuthenticatedRequest,
@@ -852,10 +909,11 @@ export async function getDiagramRelationshipsByRelationshipId(
}
const dataflowService = new DataflowService();
const relationships = await dataflowService.getDiagramRelationshipsByRelationshipId(
companyCode,
parseInt(relationshipId)
);
const relationships =
await dataflowService.getDiagramRelationshipsByRelationshipId(
companyCode,
parseInt(relationshipId)
);
const response: ApiResponse<any[]> = {
success: true,
@@ -871,7 +929,10 @@ export async function getDiagramRelationshipsByRelationshipId(
message: "관계도 관계 조회에 실패했습니다.",
error: {
code: "DIAGRAM_RELATIONSHIPS_FETCH_FAILED",
details: error instanceof Error ? error.message : "알 수 없는 오류가 발생했습니다.",
details:
error instanceof Error
? error.message
: "알 수 없는 오류가 발생했습니다.",
},
};
res.status(500).json(response);

View File

@@ -12,6 +12,7 @@ import {
getTableData,
getDataFlowDiagrams,
getDiagramRelationships,
getDiagramRelationshipsByDiagramId,
getDiagramRelationshipsByRelationshipId,
copyDiagram,
deleteDiagram,
@@ -92,10 +93,22 @@ router.get("/table-data/:tableName", getTableData);
router.get("/diagrams", getDataFlowDiagrams);
/**
* 특정 관계도의 모든 관계 조회
* GET /api/dataflow/diagrams/:diagramName/relationships
* 특정 관계도의 모든 관계 조회 (diagram_id로)
* GET /api/dataflow/diagrams/:diagramId/relationships
*/
router.get("/diagrams/:diagramName/relationships", getDiagramRelationships);
router.get(
"/diagrams/:diagramId/relationships",
getDiagramRelationshipsByDiagramId
);
/**
* 특정 관계도의 모든 관계 조회 (diagramName으로 - 하위 호환성)
* GET /api/dataflow/diagrams/name/:diagramName/relationships
*/
router.get(
"/diagrams/name/:diagramName/relationships",
getDiagramRelationships
);
/**
* 관계도 복사
@@ -109,7 +122,7 @@ router.post("/diagrams/:diagramName/copy", copyDiagram);
*/
router.delete("/diagrams/:diagramName", deleteDiagram);
// relationship_id로 관계도 관계 조회
// relationship_id로 관계도 관계 조회 (하위 호환성)
router.get(
"/relationships/:relationshipId/diagram",
getDiagramRelationshipsByRelationshipId

View File

@@ -5,6 +5,7 @@ const prisma = new PrismaClient();
// 테이블 관계 생성 데이터 타입
interface CreateTableRelationshipData {
diagramId?: number; // 기존 관계도에 추가하는 경우
relationshipName: string;
fromTableName: string;
fromColumnName: string;
@@ -38,9 +39,31 @@ export class DataflowService {
try {
logger.info("DataflowService: 테이블 관계 생성 시작", data);
// 중복 관계 확인
// diagram_id 결정 로직
let diagramId = data.diagramId;
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,
},
});
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,
@@ -56,9 +79,10 @@ 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,
@@ -74,7 +98,7 @@ export class DataflowService {
});
logger.info(
`DataflowService: 테이블 관계 생성 완료 - ID: ${relationship.relationship_id}`
`DataflowService: 테이블 관계 생성 완료 - ID: ${relationship.relationship_id}, Diagram ID: ${relationship.diagram_id}`
);
return relationship;
} catch (error) {
@@ -731,7 +755,7 @@ export class DataflowService {
}
/**
* 관계도 그룹 목록 조회 (관계도 이름별로 그룹화)
* 관계도 그룹 목록 조회 (diagram_id별로 그룹화)
*/
async getDataFlowDiagrams(
companyCode: string,
@@ -744,7 +768,7 @@ export class DataflowService {
`DataflowService: 관계도 목록 조회 시작 - ${companyCode}, page: ${page}, size: ${size}, search: ${searchTerm}`
);
// 관계도 이름별로 그룹화하여 조회
// diagram_id별로 그룹화하여 조회
const whereCondition = {
company_code: companyCode,
is_active: "Y",
@@ -772,11 +796,12 @@ export class DataflowService {
}),
};
// 관계도별로 그룹화된 데이터 조회 (관계도 이름을 기준으로)
// 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,
@@ -787,19 +812,19 @@ export class DataflowService {
updated_date: true,
updated_by: true,
},
orderBy: [{ relationship_name: "asc" }, { created_date: "desc" }],
orderBy: [{ diagram_id: "asc" }, { created_date: "desc" }],
});
// 관계도 이름별로 그룹화
const diagramMap = new Map<string, any>();
// diagram_id별로 그룹화
const diagramMap = new Map<number, any>();
relationships.forEach((rel) => {
const diagramName = rel.relationship_name;
const diagramId = rel.diagram_id;
if (!diagramMap.has(diagramName)) {
diagramMap.set(diagramName, {
relationshipId: rel.relationship_id, // 첫 번째 관계의 ID를 대표 ID로 사용
diagramName: diagramName,
if (!diagramMap.has(diagramId)) {
diagramMap.set(diagramId, {
diagramId: diagramId,
diagramName: rel.relationship_name, // 첫 번째 관계의 이름을 사용
connectionType: rel.connection_type,
relationshipType: rel.relationship_type,
tableCount: new Set<string>(),
@@ -812,7 +837,7 @@ export class DataflowService {
});
}
const diagram = diagramMap.get(diagramName);
const diagram = diagramMap.get(diagramId);
diagram.tableCount.add(rel.from_table_name);
diagram.tableCount.add(rel.to_table_name);
diagram.relationshipCount++;
@@ -893,7 +918,7 @@ export class DataflowService {
}
/**
* 관계도 복사
* 관계도 복사 (diagram_id 기반)
*/
async copyDiagram(
companyCode: string,
@@ -936,11 +961,27 @@ export class DataflowService {
newDiagramName = `${originalDiagramName} (${counter})`;
}
// 새로운 diagram_id 생성
const maxDiagramId = await prisma.table_relationships.findFirst({
where: {
company_code: companyCode,
},
orderBy: {
diagram_id: "desc",
},
select: {
diagram_id: true,
},
});
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,
@@ -959,7 +1000,7 @@ export class DataflowService {
);
logger.info(
`DataflowService: 관계도 복사 완료 - ${originalDiagramName}${newDiagramName}, ${copiedRelationships.length}개 관계 복사`
`DataflowService: 관계도 복사 완료 - ${originalDiagramName}${newDiagramName} (diagram_id: ${newDiagramId}), ${copiedRelationships.length}개 관계 복사`
);
return newDiagramName;
@@ -1002,7 +1043,46 @@ export class DataflowService {
}
/**
* relationship_id로 해당 관계도의 모든 관계 조회
* diagram_id로 해당 관계도의 모든 관계 조회
*/
async getDiagramRelationshipsByDiagramId(
companyCode: string,
diagramId: number
) {
try {
logger.info(
`DataflowService: diagram_id로 관계도 관계 조회 - ${diagramId}`
);
// diagram_id로 모든 관계 조회
const relationships = await prisma.table_relationships.findMany({
where: {
diagram_id: diagramId,
company_code: companyCode,
is_active: "Y",
},
orderBy: [{ relationship_id: "asc" }],
});
logger.info(
`DataflowService: diagram_id로 관계도 관계 조회 완료 - ${relationships.length}개 관계`
);
return relationships.map((rel) => ({
...rel,
settings: rel.settings as any,
}));
} catch (error) {
logger.error(
`DataflowService: diagram_id로 관계도 관계 조회 실패 - ${diagramId}`,
error
);
throw error;
}
}
/**
* relationship_id로 해당 관계도의 모든 관계 조회 (하위 호환성 유지)
*/
async getDiagramRelationshipsByRelationshipId(
companyCode: string,
@@ -1013,7 +1093,7 @@ export class DataflowService {
`DataflowService: relationship_id로 관계도 관계 조회 - ${relationshipId}`
);
// 먼저 해당 relationship_id의 관계도명을 찾음
// 먼저 해당 relationship_id의 diagram_id를 찾음
const targetRelationship = await prisma.table_relationships.findFirst({
where: {
relationship_id: relationshipId,
@@ -1021,7 +1101,7 @@ export class DataflowService {
is_active: "Y",
},
select: {
relationship_name: true,
diagram_id: true,
},
});
@@ -1029,24 +1109,11 @@ export class DataflowService {
throw new Error("해당 관계 ID를 찾을 수 없습니다.");
}
// 같은 관계도명을 가진 모든 관계 조회
const relationships = await prisma.table_relationships.findMany({
where: {
relationship_name: targetRelationship.relationship_name,
company_code: companyCode,
is_active: "Y",
},
orderBy: [{ relationship_id: "asc" }],
});
logger.info(
`DataflowService: relationship_id로 관계도 관계 조회 완료 - ${relationships.length}개 관계`
// diagram_id로 모든 관계 조회
return this.getDiagramRelationshipsByDiagramId(
companyCode,
targetRelationship.diagram_id
);
return relationships.map((rel) => ({
...rel,
settings: rel.settings as any,
}));
} catch (error) {
logger.error(
`DataflowService: relationship_id로 관계도 관계 조회 실패 - ${relationshipId}`,