2026-03-10 14:47:05 +09:00
|
|
|
import { query } from "../database/db";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* PostgreSQL 에러를 사용자 친절한 메시지로 변환
|
|
|
|
|
* table_type_columns의 column_label을 조회하여 한글 라벨로 표시
|
|
|
|
|
*/
|
|
|
|
|
export async function formatPgError(
|
|
|
|
|
error: any,
|
|
|
|
|
companyCode?: string
|
|
|
|
|
): Promise<string> {
|
|
|
|
|
if (!error || !error.code) {
|
|
|
|
|
return error?.message || "데이터 처리 중 오류가 발생했습니다.";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (error.code) {
|
|
|
|
|
case "23502": {
|
|
|
|
|
// not_null_violation
|
|
|
|
|
const colName = error.column || "";
|
|
|
|
|
const tblName = error.table || "";
|
|
|
|
|
|
|
|
|
|
if (colName && tblName && companyCode) {
|
|
|
|
|
try {
|
|
|
|
|
const rows = await query(
|
|
|
|
|
`SELECT column_label FROM table_type_columns
|
|
|
|
|
WHERE table_name = $1 AND column_name = $2 AND company_code = $3
|
|
|
|
|
LIMIT 1`,
|
|
|
|
|
[tblName, colName, companyCode]
|
|
|
|
|
);
|
|
|
|
|
const label = rows[0]?.column_label;
|
|
|
|
|
if (label) {
|
|
|
|
|
return `필수 입력값이 누락되었습니다: ${label}`;
|
|
|
|
|
}
|
|
|
|
|
} catch {
|
|
|
|
|
// 라벨 조회 실패 시 컬럼명으로 폴백
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const detail = colName ? ` [${colName}]` : "";
|
|
|
|
|
return `필수 입력값이 누락되었습니다.${detail}`;
|
|
|
|
|
}
|
2026-03-10 16:15:20 +09:00
|
|
|
case "23505": {
|
|
|
|
|
// unique_violation
|
|
|
|
|
const constraint = error.constraint || "";
|
|
|
|
|
const tblName = error.table || "";
|
|
|
|
|
// constraint 이름에서 컬럼명 추출 시도 (예: item_mst_item_code_key → item_code)
|
|
|
|
|
let colName = "";
|
|
|
|
|
if (constraint && tblName) {
|
|
|
|
|
const prefix = `${tblName}_`;
|
|
|
|
|
const suffix = "_key";
|
|
|
|
|
if (constraint.startsWith(prefix) && constraint.endsWith(suffix)) {
|
|
|
|
|
colName = constraint.slice(prefix.length, -suffix.length);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (colName && tblName && companyCode) {
|
|
|
|
|
try {
|
|
|
|
|
const rows = await query(
|
|
|
|
|
`SELECT column_label FROM table_type_columns
|
|
|
|
|
WHERE table_name = $1 AND column_name = $2 AND company_code = $3
|
|
|
|
|
LIMIT 1`,
|
|
|
|
|
[tblName, colName, companyCode]
|
|
|
|
|
);
|
|
|
|
|
const label = rows[0]?.column_label;
|
|
|
|
|
if (label) {
|
|
|
|
|
return `중복된 데이터가 존재합니다: ${label}`;
|
|
|
|
|
}
|
|
|
|
|
} catch {
|
|
|
|
|
// 폴백
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const detail = colName ? ` [${colName}]` : "";
|
|
|
|
|
return `중복된 데이터가 존재합니다.${detail}`;
|
|
|
|
|
}
|
2026-03-10 14:47:05 +09:00
|
|
|
case "23503":
|
|
|
|
|
return "참조 무결성 제약 조건 위반입니다.";
|
|
|
|
|
default:
|
|
|
|
|
if (error.code.startsWith("23")) {
|
|
|
|
|
return "데이터 무결성 제약 조건 위반입니다.";
|
|
|
|
|
}
|
|
|
|
|
return error.message || "데이터 처리 중 오류가 발생했습니다.";
|
|
|
|
|
}
|
|
|
|
|
}
|