코드병합기능 개선
This commit is contained in:
parent
a3c83c834e
commit
3f81c449ad
|
|
@ -282,3 +282,175 @@ export async function previewCodeMerge(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 값 기반 코드 병합 - 모든 테이블의 모든 컬럼에서 해당 값을 찾아 변경
|
||||||
|
* 컬럼명에 상관없이 oldValue를 가진 모든 곳을 newValue로 변경
|
||||||
|
*/
|
||||||
|
export async function mergeCodeByValue(
|
||||||
|
req: AuthenticatedRequest,
|
||||||
|
res: Response
|
||||||
|
): Promise<void> {
|
||||||
|
const { oldValue, newValue } = req.body;
|
||||||
|
const companyCode = req.user?.companyCode;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 입력값 검증
|
||||||
|
if (!oldValue || !newValue) {
|
||||||
|
res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
message: "필수 필드가 누락되었습니다. (oldValue, newValue)",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!companyCode) {
|
||||||
|
res.status(401).json({
|
||||||
|
success: false,
|
||||||
|
message: "인증 정보가 없습니다.",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 같은 값으로 병합 시도 방지
|
||||||
|
if (oldValue === newValue) {
|
||||||
|
res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
message: "기존 값과 새 값이 동일합니다.",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("값 기반 코드 병합 시작", {
|
||||||
|
oldValue,
|
||||||
|
newValue,
|
||||||
|
companyCode,
|
||||||
|
userId: req.user?.userId,
|
||||||
|
});
|
||||||
|
|
||||||
|
// PostgreSQL 함수 호출
|
||||||
|
const result = await pool.query(
|
||||||
|
"SELECT * FROM merge_code_by_value($1, $2, $3)",
|
||||||
|
[oldValue, newValue, companyCode]
|
||||||
|
);
|
||||||
|
|
||||||
|
// 결과 처리
|
||||||
|
const affectedData = Array.isArray(result) ? result : ((result as any).rows || []);
|
||||||
|
const totalRows = affectedData.reduce(
|
||||||
|
(sum: number, row: any) => sum + parseInt(row.out_rows_updated || 0),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
logger.info("값 기반 코드 병합 완료", {
|
||||||
|
oldValue,
|
||||||
|
newValue,
|
||||||
|
affectedTablesCount: affectedData.length,
|
||||||
|
totalRowsUpdated: totalRows,
|
||||||
|
});
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
message: `코드 병합 완료: ${oldValue} → ${newValue}`,
|
||||||
|
data: {
|
||||||
|
oldValue,
|
||||||
|
newValue,
|
||||||
|
affectedData: affectedData.map((row: any) => ({
|
||||||
|
tableName: row.out_table_name,
|
||||||
|
columnName: row.out_column_name,
|
||||||
|
rowsUpdated: parseInt(row.out_rows_updated),
|
||||||
|
})),
|
||||||
|
totalRowsUpdated: totalRows,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (error: any) {
|
||||||
|
logger.error("값 기반 코드 병합 실패:", {
|
||||||
|
error: error.message,
|
||||||
|
stack: error.stack,
|
||||||
|
oldValue,
|
||||||
|
newValue,
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: "코드 병합 중 오류가 발생했습니다.",
|
||||||
|
error: {
|
||||||
|
code: "CODE_MERGE_BY_VALUE_ERROR",
|
||||||
|
details: error.message,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 값 기반 코드 병합 미리보기
|
||||||
|
* 컬럼명에 상관없이 해당 값을 가진 모든 테이블/컬럼 조회
|
||||||
|
*/
|
||||||
|
export async function previewMergeCodeByValue(
|
||||||
|
req: AuthenticatedRequest,
|
||||||
|
res: Response
|
||||||
|
): Promise<void> {
|
||||||
|
const { oldValue } = req.body;
|
||||||
|
const companyCode = req.user?.companyCode;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!oldValue) {
|
||||||
|
res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
message: "필수 필드가 누락되었습니다. (oldValue)",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!companyCode) {
|
||||||
|
res.status(401).json({
|
||||||
|
success: false,
|
||||||
|
message: "인증 정보가 없습니다.",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("값 기반 코드 병합 미리보기", { oldValue, companyCode });
|
||||||
|
|
||||||
|
// PostgreSQL 함수 호출
|
||||||
|
const result = await pool.query(
|
||||||
|
"SELECT * FROM preview_merge_code_by_value($1, $2)",
|
||||||
|
[oldValue, companyCode]
|
||||||
|
);
|
||||||
|
|
||||||
|
const preview = Array.isArray(result) ? result : ((result as any).rows || []);
|
||||||
|
const totalRows = preview.reduce(
|
||||||
|
(sum: number, row: any) => sum + parseInt(row.out_affected_rows || 0),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
logger.info("값 기반 코드 병합 미리보기 완료", {
|
||||||
|
tablesCount: preview.length,
|
||||||
|
totalRows,
|
||||||
|
});
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
message: "코드 병합 미리보기 완료",
|
||||||
|
data: {
|
||||||
|
oldValue,
|
||||||
|
preview: preview.map((row: any) => ({
|
||||||
|
tableName: row.out_table_name,
|
||||||
|
columnName: row.out_column_name,
|
||||||
|
affectedRows: parseInt(row.out_affected_rows),
|
||||||
|
})),
|
||||||
|
totalAffectedRows: totalRows,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (error: any) {
|
||||||
|
logger.error("값 기반 코드 병합 미리보기 실패:", error);
|
||||||
|
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
message: "코드 병합 미리보기 중 오류가 발생했습니다.",
|
||||||
|
error: {
|
||||||
|
code: "PREVIEW_BY_VALUE_ERROR",
|
||||||
|
details: error.message,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ import {
|
||||||
mergeCodeAllTables,
|
mergeCodeAllTables,
|
||||||
getTablesWithColumn,
|
getTablesWithColumn,
|
||||||
previewCodeMerge,
|
previewCodeMerge,
|
||||||
|
mergeCodeByValue,
|
||||||
|
previewMergeCodeByValue,
|
||||||
} from "../controllers/codeMergeController";
|
} from "../controllers/codeMergeController";
|
||||||
import { authenticateToken } from "../middleware/authMiddleware";
|
import { authenticateToken } from "../middleware/authMiddleware";
|
||||||
|
|
||||||
|
|
@ -13,7 +15,7 @@ router.use(authenticateToken);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* POST /api/code-merge/merge-all-tables
|
* POST /api/code-merge/merge-all-tables
|
||||||
* 코드 병합 실행 (모든 관련 테이블에 적용)
|
* 코드 병합 실행 (모든 관련 테이블에 적용 - 같은 컬럼명만)
|
||||||
* Body: { columnName, oldValue, newValue }
|
* Body: { columnName, oldValue, newValue }
|
||||||
*/
|
*/
|
||||||
router.post("/merge-all-tables", mergeCodeAllTables);
|
router.post("/merge-all-tables", mergeCodeAllTables);
|
||||||
|
|
@ -26,10 +28,24 @@ router.get("/tables-with-column/:columnName", getTablesWithColumn);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* POST /api/code-merge/preview
|
* POST /api/code-merge/preview
|
||||||
* 코드 병합 미리보기 (실제 실행 없이 영향받을 데이터 확인)
|
* 코드 병합 미리보기 (같은 컬럼명 기준)
|
||||||
* Body: { columnName, oldValue }
|
* Body: { columnName, oldValue }
|
||||||
*/
|
*/
|
||||||
router.post("/preview", previewCodeMerge);
|
router.post("/preview", previewCodeMerge);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST /api/code-merge/merge-by-value
|
||||||
|
* 값 기반 코드 병합 (모든 테이블의 모든 컬럼에서 해당 값을 찾아 변경)
|
||||||
|
* Body: { oldValue, newValue }
|
||||||
|
*/
|
||||||
|
router.post("/merge-by-value", mergeCodeByValue);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST /api/code-merge/preview-by-value
|
||||||
|
* 값 기반 코드 병합 미리보기 (컬럼명 상관없이 값으로 검색)
|
||||||
|
* Body: { oldValue }
|
||||||
|
*/
|
||||||
|
router.post("/preview-by-value", previewMergeCodeByValue);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4920,26 +4920,35 @@ export class ButtonActionExecutor {
|
||||||
|
|
||||||
const { oldValue, newValue } = confirmed;
|
const { oldValue, newValue } = confirmed;
|
||||||
|
|
||||||
// 미리보기 표시 (옵션)
|
// 미리보기 표시 (값 기반 검색 - 모든 테이블의 모든 컬럼에서 검색)
|
||||||
if (config.mergeShowPreview !== false) {
|
if (config.mergeShowPreview !== false) {
|
||||||
const { apiClient } = await import("@/lib/api/client");
|
const { apiClient } = await import("@/lib/api/client");
|
||||||
|
|
||||||
const previewResponse = await apiClient.post("/code-merge/preview", {
|
toast.loading("영향받는 데이터 검색 중...", { duration: Infinity });
|
||||||
columnName,
|
|
||||||
|
const previewResponse = await apiClient.post("/code-merge/preview-by-value", {
|
||||||
oldValue,
|
oldValue,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
toast.dismiss();
|
||||||
|
|
||||||
if (previewResponse.data.success) {
|
if (previewResponse.data.success) {
|
||||||
const preview = previewResponse.data.data;
|
const preview = previewResponse.data.data;
|
||||||
const totalRows = preview.totalAffectedRows;
|
const totalRows = preview.totalAffectedRows;
|
||||||
|
|
||||||
|
// 상세 정보 생성
|
||||||
|
const detailList = preview.preview
|
||||||
|
.map((p: any) => ` - ${p.tableName}.${p.columnName}: ${p.affectedRows}건`)
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
const confirmMerge = confirm(
|
const confirmMerge = confirm(
|
||||||
"⚠️ 코드 병합 확인\n\n" +
|
"코드 병합 확인\n\n" +
|
||||||
`${oldValue} → ${newValue}\n\n` +
|
`${oldValue} → ${newValue}\n\n` +
|
||||||
"영향받는 데이터:\n" +
|
"영향받는 데이터:\n" +
|
||||||
`- 테이블 수: ${preview.preview.length}개\n` +
|
`- 테이블/컬럼 수: ${preview.preview.length}개\n` +
|
||||||
`- 총 행 수: ${totalRows}개\n\n` +
|
`- 총 행 수: ${totalRows}개\n\n` +
|
||||||
`데이터는 삭제되지 않고, "${columnName}" 컬럼 값만 변경됩니다.\n\n` +
|
(preview.preview.length <= 10 ? `상세:\n${detailList}\n\n` : "") +
|
||||||
|
"모든 테이블에서 해당 값이 변경됩니다.\n\n" +
|
||||||
"계속하시겠습니까?",
|
"계속하시겠습니까?",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -4949,13 +4958,12 @@ export class ButtonActionExecutor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 병합 실행
|
// 병합 실행 (값 기반 - 모든 테이블의 모든 컬럼)
|
||||||
toast.loading("코드 병합 중...", { duration: Infinity });
|
toast.loading("코드 병합 중...", { duration: Infinity });
|
||||||
|
|
||||||
const { apiClient } = await import("@/lib/api/client");
|
const { apiClient } = await import("@/lib/api/client");
|
||||||
|
|
||||||
const response = await apiClient.post("/code-merge/merge-all-tables", {
|
const response = await apiClient.post("/code-merge/merge-by-value", {
|
||||||
columnName,
|
|
||||||
oldValue,
|
oldValue,
|
||||||
newValue,
|
newValue,
|
||||||
});
|
});
|
||||||
|
|
@ -4964,10 +4972,18 @@ export class ButtonActionExecutor {
|
||||||
|
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
const data = response.data.data;
|
const data = response.data.data;
|
||||||
|
|
||||||
|
// 변경된 테이블/컬럼 목록 생성
|
||||||
|
const changedList = data.affectedData
|
||||||
|
.map((d: any) => `${d.tableName}.${d.columnName}: ${d.rowsUpdated}건`)
|
||||||
|
.join(", ");
|
||||||
|
|
||||||
toast.success(
|
toast.success(
|
||||||
"코드 병합 완료!\n" + `${data.affectedTables.length}개 테이블, ${data.totalRowsUpdated}개 행 업데이트`,
|
`코드 병합 완료! ${data.affectedData.length}개 테이블/컬럼, ${data.totalRowsUpdated}개 행 업데이트`,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
console.log("코드 병합 결과:", data.affectedData);
|
||||||
|
|
||||||
// 화면 새로고침
|
// 화면 새로고침
|
||||||
context.onRefresh?.();
|
context.onRefresh?.();
|
||||||
context.onFlowRefresh?.();
|
context.onFlowRefresh?.();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue