데이터 관계도 삭제, 복사 구현

This commit is contained in:
2025-09-09 13:10:03 +09:00
parent 3a24fd3ebd
commit 142cfe022b
5 changed files with 393 additions and 33 deletions

View File

@@ -718,3 +718,111 @@ export async function getDiagramRelationships(
res.status(500).json(response);
}
}
/**
* 관계도 복사
*/
export async function copyDiagram(
req: AuthenticatedRequest,
res: Response
): Promise<void> {
try {
const { diagramName } = req.params;
const companyCode = (req.user as any)?.company_code || "*";
if (!diagramName) {
const response: ApiResponse<null> = {
success: false,
message: "관계도 이름이 필요합니다.",
error: {
code: "MISSING_DIAGRAM_NAME",
details: "diagramName 파라미터가 필요합니다.",
},
};
res.status(400).json(response);
return;
}
const dataflowService = new DataflowService();
const newDiagramName = await dataflowService.copyDiagram(
companyCode,
decodeURIComponent(diagramName)
);
const response: ApiResponse<{ newDiagramName: string }> = {
success: true,
message: "관계도가 성공적으로 복사되었습니다.",
data: { newDiagramName },
};
res.status(200).json(response);
} catch (error) {
logger.error("관계도 복사 실패:", error);
const response: ApiResponse<null> = {
success: false,
message: "관계도 복사에 실패했습니다.",
error: {
code: "DIAGRAM_COPY_FAILED",
details:
error instanceof Error
? error.message
: "알 수 없는 오류가 발생했습니다.",
},
};
res.status(500).json(response);
}
}
/**
* 관계도 삭제
*/
export async function deleteDiagram(
req: AuthenticatedRequest,
res: Response
): Promise<void> {
try {
const { diagramName } = req.params;
const companyCode = (req.user as any)?.company_code || "*";
if (!diagramName) {
const response: ApiResponse<null> = {
success: false,
message: "관계도 이름이 필요합니다.",
error: {
code: "MISSING_DIAGRAM_NAME",
details: "diagramName 파라미터가 필요합니다.",
},
};
res.status(400).json(response);
return;
}
const dataflowService = new DataflowService();
const deletedCount = await dataflowService.deleteDiagram(
companyCode,
decodeURIComponent(diagramName)
);
const response: ApiResponse<{ deletedCount: number }> = {
success: true,
message: "관계도가 성공적으로 삭제되었습니다.",
data: { deletedCount },
};
res.status(200).json(response);
} catch (error) {
logger.error("관계도 삭제 실패:", error);
const response: ApiResponse<null> = {
success: false,
message: "관계도 삭제에 실패했습니다.",
error: {
code: "DIAGRAM_DELETE_FAILED",
details:
error instanceof Error
? error.message
: "알 수 없는 오류가 발생했습니다.",
},
};
res.status(500).json(response);
}
}

View File

@@ -12,6 +12,8 @@ import {
getTableData,
getDataFlowDiagrams,
getDiagramRelationships,
copyDiagram,
deleteDiagram,
} from "../controllers/dataflowController";
const router = express.Router();
@@ -94,4 +96,16 @@ router.get("/diagrams", getDataFlowDiagrams);
*/
router.get("/diagrams/:diagramName/relationships", getDiagramRelationships);
/**
* 관계도 복사
* POST /api/dataflow/diagrams/:diagramName/copy
*/
router.post("/diagrams/:diagramName/copy", copyDiagram);
/**
* 관계도 삭제
* DELETE /api/dataflow/diagrams/:diagramName
*/
router.delete("/diagrams/:diagramName", deleteDiagram);
export default router;

View File

@@ -889,4 +889,113 @@ export class DataflowService {
throw error;
}
}
/**
* 관계도 복사
*/
async copyDiagram(
companyCode: string,
originalDiagramName: string
): Promise<string> {
try {
logger.info(`DataflowService: 관계도 복사 시작 - ${originalDiagramName}`);
// 원본 관계도의 모든 관계 조회
const originalRelationships = await prisma.table_relationships.findMany({
where: {
company_code: companyCode,
relationship_name: originalDiagramName,
is_active: "Y",
},
});
if (originalRelationships.length === 0) {
throw new Error("복사할 관계도를 찾을 수 없습니다.");
}
// 새로운 관계도 이름 생성 (중복 검사)
let newDiagramName = `${originalDiagramName} (1)`;
let counter = 1;
while (true) {
const existingDiagram = await prisma.table_relationships.findFirst({
where: {
company_code: companyCode,
relationship_name: newDiagramName,
is_active: "Y",
},
});
if (!existingDiagram) {
break;
}
counter++;
newDiagramName = `${originalDiagramName} (${counter})`;
}
// 트랜잭션으로 모든 관계 복사
const copiedRelationships = await prisma.$transaction(
originalRelationships.map((rel) =>
prisma.table_relationships.create({
data: {
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,
},
})
)
);
logger.info(
`DataflowService: 관계도 복사 완료 - ${originalDiagramName}${newDiagramName}, ${copiedRelationships.length}개 관계 복사`
);
return newDiagramName;
} catch (error) {
logger.error(
`DataflowService: 관계도 복사 실패 - ${originalDiagramName}`,
error
);
throw error;
}
}
/**
* 관계도 삭제
*/
async deleteDiagram(
companyCode: string,
diagramName: string
): Promise<number> {
try {
logger.info(`DataflowService: 관계도 삭제 시작 - ${diagramName}`);
// 관계도의 모든 관계 삭제 (하드 삭제)
const deleteResult = await prisma.table_relationships.deleteMany({
where: {
company_code: companyCode,
relationship_name: diagramName,
},
});
logger.info(
`DataflowService: 관계도 삭제 완료 - ${diagramName}, ${deleteResult.count}개 관계 삭제`
);
return deleteResult.count;
} catch (error) {
logger.error(`DataflowService: 관계도 삭제 실패 - ${diagramName}`, error);
throw error;
}
}
}