2025-09-21 09:53:05 +09:00
|
|
|
import { Request, Response } from "express";
|
2025-10-01 14:33:08 +09:00
|
|
|
import { query, queryOne } from "../database/db";
|
2025-09-21 09:53:05 +09:00
|
|
|
import { logger } from "../utils/logger";
|
|
|
|
|
|
|
|
|
|
export interface EntityReferenceOption {
|
|
|
|
|
value: string;
|
|
|
|
|
label: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface EntityReferenceData {
|
|
|
|
|
options: EntityReferenceOption[];
|
|
|
|
|
referenceInfo: {
|
|
|
|
|
referenceTable: string;
|
|
|
|
|
referenceColumn: string;
|
|
|
|
|
displayColumn: string | null;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CodeReferenceData {
|
|
|
|
|
options: EntityReferenceOption[];
|
|
|
|
|
codeCategory: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class EntityReferenceController {
|
|
|
|
|
/**
|
|
|
|
|
* 엔티티 참조 데이터 조회
|
|
|
|
|
* GET /api/entity-reference/:tableName/:columnName
|
|
|
|
|
*/
|
|
|
|
|
static async getEntityReferenceData(req: Request, res: Response) {
|
|
|
|
|
try {
|
|
|
|
|
const { tableName, columnName } = req.params;
|
|
|
|
|
const { limit = 100, search } = req.query;
|
|
|
|
|
|
|
|
|
|
logger.info(`엔티티 참조 데이터 조회 요청: ${tableName}.${columnName}`, {
|
|
|
|
|
limit,
|
|
|
|
|
search,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 컬럼 정보 조회
|
2025-10-01 14:33:08 +09:00
|
|
|
const columnInfo = await queryOne<any>(
|
|
|
|
|
`SELECT * FROM column_labels
|
|
|
|
|
WHERE table_name = $1 AND column_name = $2
|
|
|
|
|
LIMIT 1`,
|
|
|
|
|
[tableName, columnName]
|
|
|
|
|
);
|
2025-09-21 09:53:05 +09:00
|
|
|
|
|
|
|
|
if (!columnInfo) {
|
|
|
|
|
return res.status(404).json({
|
|
|
|
|
success: false,
|
2025-09-21 12:31:37 +09:00
|
|
|
message: `컬럼 정보를 찾을 수 없습니다: ${tableName}.${columnName}`,
|
2025-09-21 09:53:05 +09:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-21 12:31:37 +09:00
|
|
|
// webType 확인
|
|
|
|
|
if (columnInfo.web_type !== "entity") {
|
|
|
|
|
return res.status(400).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: `컬럼 '${tableName}.${columnName}'은 entity 타입이 아닙니다. webType: ${columnInfo.web_type}`,
|
|
|
|
|
});
|
2025-09-21 09:53:05 +09:00
|
|
|
}
|
|
|
|
|
|
2025-09-21 12:31:37 +09:00
|
|
|
// column_labels에서 직접 참조 정보 가져오기
|
|
|
|
|
const referenceTable = columnInfo.reference_table;
|
|
|
|
|
const referenceColumn = columnInfo.reference_column;
|
|
|
|
|
const displayColumn = columnInfo.display_column || "name";
|
2025-09-21 10:28:15 +09:00
|
|
|
|
2025-09-21 12:31:37 +09:00
|
|
|
// entity 타입인데 참조 테이블 정보가 없으면 오류
|
|
|
|
|
if (!referenceTable || !referenceColumn) {
|
2025-09-21 09:53:05 +09:00
|
|
|
return res.status(400).json({
|
|
|
|
|
success: false,
|
2025-09-21 12:31:37 +09:00
|
|
|
message: `Entity 타입 컬럼 '${tableName}.${columnName}'에 참조 테이블 정보가 설정되지 않았습니다. column_labels에서 reference_table과 reference_column을 확인해주세요.`,
|
2025-09-21 09:53:05 +09:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-21 12:31:37 +09:00
|
|
|
// 참조 테이블이 실제로 존재하는지 확인
|
|
|
|
|
try {
|
2025-10-01 14:33:08 +09:00
|
|
|
await query<any>(`SELECT 1 FROM ${referenceTable} LIMIT 1`);
|
2025-09-21 12:31:37 +09:00
|
|
|
logger.info(
|
|
|
|
|
`Entity 참조 설정: ${tableName}.${columnName} -> ${referenceTable}.${referenceColumn} (display: ${displayColumn})`
|
|
|
|
|
);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error(
|
|
|
|
|
`참조 테이블 '${referenceTable}'이 존재하지 않습니다:`,
|
|
|
|
|
error
|
|
|
|
|
);
|
|
|
|
|
return res.status(400).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: `참조 테이블 '${referenceTable}'이 존재하지 않습니다. column_labels의 reference_table 설정을 확인해주세요.`,
|
|
|
|
|
});
|
2025-09-21 10:28:15 +09:00
|
|
|
}
|
|
|
|
|
|
2025-09-21 09:53:05 +09:00
|
|
|
// 동적 쿼리로 참조 데이터 조회
|
2025-10-01 14:33:08 +09:00
|
|
|
let sqlQuery = `SELECT ${referenceColumn}, ${displayColumn} as display_name FROM ${referenceTable}`;
|
2025-09-21 09:53:05 +09:00
|
|
|
const queryParams: any[] = [];
|
|
|
|
|
|
|
|
|
|
// 검색 조건 추가
|
|
|
|
|
if (search) {
|
2025-10-01 14:33:08 +09:00
|
|
|
sqlQuery += ` WHERE ${displayColumn} ILIKE $1`;
|
2025-09-21 09:53:05 +09:00
|
|
|
queryParams.push(`%${search}%`);
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-01 14:33:08 +09:00
|
|
|
sqlQuery += ` ORDER BY ${displayColumn} LIMIT $${queryParams.length + 1}`;
|
2025-09-21 09:53:05 +09:00
|
|
|
queryParams.push(Number(limit));
|
|
|
|
|
|
2025-10-01 14:33:08 +09:00
|
|
|
logger.info(`실행할 쿼리: ${sqlQuery}`, {
|
2025-09-21 10:28:15 +09:00
|
|
|
queryParams,
|
|
|
|
|
referenceTable,
|
|
|
|
|
referenceColumn,
|
|
|
|
|
displayColumn,
|
|
|
|
|
});
|
|
|
|
|
|
2025-10-01 14:33:08 +09:00
|
|
|
const referenceData = await query<any>(sqlQuery, queryParams);
|
2025-09-21 09:53:05 +09:00
|
|
|
|
|
|
|
|
// 옵션 형태로 변환
|
|
|
|
|
const options: EntityReferenceOption[] = (referenceData as any[]).map(
|
|
|
|
|
(row) => ({
|
2025-09-21 10:28:15 +09:00
|
|
|
value: String(row[referenceColumn]),
|
|
|
|
|
label: String(row.display_name || row[referenceColumn]),
|
2025-09-21 09:53:05 +09:00
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
logger.info(`엔티티 참조 데이터 조회 완료: ${options.length}개 항목`);
|
|
|
|
|
|
|
|
|
|
return res.json({
|
|
|
|
|
success: true,
|
2025-09-21 12:31:37 +09:00
|
|
|
data: {
|
|
|
|
|
options,
|
|
|
|
|
referenceInfo: {
|
|
|
|
|
referenceTable,
|
|
|
|
|
referenceColumn,
|
|
|
|
|
displayColumn,
|
|
|
|
|
},
|
|
|
|
|
},
|
2025-09-21 09:53:05 +09:00
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("엔티티 참조 데이터 조회 실패:", error);
|
|
|
|
|
return res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "엔티티 참조 데이터 조회 중 오류가 발생했습니다.",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 공통 코드 데이터 조회
|
|
|
|
|
* GET /api/entity-reference/code/:codeCategory
|
|
|
|
|
*/
|
|
|
|
|
static async getCodeData(req: Request, res: Response) {
|
|
|
|
|
try {
|
|
|
|
|
const { codeCategory } = req.params;
|
|
|
|
|
const { limit = 100, search } = req.query;
|
|
|
|
|
|
|
|
|
|
logger.info(`공통 코드 데이터 조회 요청: ${codeCategory}`, {
|
|
|
|
|
limit,
|
|
|
|
|
search,
|
|
|
|
|
});
|
|
|
|
|
|
2025-09-21 12:31:37 +09:00
|
|
|
// code_info 테이블에서 코드 데이터 조회
|
2025-10-01 14:33:08 +09:00
|
|
|
const queryParams: any[] = [codeCategory, 'Y'];
|
|
|
|
|
let sqlQuery = `
|
|
|
|
|
SELECT code_value, code_name
|
|
|
|
|
FROM code_info
|
|
|
|
|
WHERE code_category = $1 AND is_active = $2
|
|
|
|
|
`;
|
2025-09-21 09:53:05 +09:00
|
|
|
|
|
|
|
|
if (search) {
|
2025-10-01 14:33:08 +09:00
|
|
|
sqlQuery += ` AND code_name ILIKE $3`;
|
|
|
|
|
queryParams.push(`%${search}%`);
|
2025-09-21 09:53:05 +09:00
|
|
|
}
|
|
|
|
|
|
2025-10-01 14:33:08 +09:00
|
|
|
sqlQuery += ` ORDER BY code_name ASC LIMIT $${queryParams.length + 1}`;
|
|
|
|
|
queryParams.push(Number(limit));
|
|
|
|
|
|
|
|
|
|
const codeData = await query<any>(sqlQuery, queryParams);
|
2025-09-21 09:53:05 +09:00
|
|
|
|
|
|
|
|
// 옵션 형태로 변환
|
2025-09-21 12:31:37 +09:00
|
|
|
const options: EntityReferenceOption[] = codeData.map((code) => ({
|
|
|
|
|
value: code.code_value,
|
|
|
|
|
label: code.code_name,
|
2025-09-21 09:53:05 +09:00
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
logger.info(`공통 코드 데이터 조회 완료: ${options.length}개 항목`);
|
|
|
|
|
|
|
|
|
|
return res.json({
|
|
|
|
|
success: true,
|
2025-09-21 12:31:37 +09:00
|
|
|
data: {
|
|
|
|
|
options,
|
|
|
|
|
codeCategory,
|
|
|
|
|
},
|
2025-09-21 09:53:05 +09:00
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error("공통 코드 데이터 조회 실패:", error);
|
|
|
|
|
return res.status(500).json({
|
|
|
|
|
success: false,
|
|
|
|
|
message: "공통 코드 데이터 조회 중 오류가 발생했습니다.",
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|