feat: 카테고리 컬럼 메뉴별 매핑 기능 구현
- category_column_mapping 테이블 생성 (마이그레이션 054) - 테이블 타입 관리에서 2레벨 메뉴 선택 기능 추가 - 카테고리 컬럼 조회 시 현재 메뉴 및 상위 메뉴 매핑 자동 조회 - 캐시 무효화 로직 개선 - 메뉴별 카테고리 설정 저장 및 불러오기 기능 구현
This commit is contained in:
@@ -1657,37 +1657,108 @@ export async function getCategoryColumnsByMenu(
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 테이블들의 카테고리 타입 컬럼 조회 (테이블 라벨 포함)
|
||||
logger.info("🔍 카테고리 컬럼 쿼리 준비", { tableNames, companyCode });
|
||||
|
||||
const columnsQuery = `
|
||||
SELECT
|
||||
ttc.table_name AS "tableName",
|
||||
COALESCE(
|
||||
tl.table_label,
|
||||
initcap(replace(ttc.table_name, '_', ' '))
|
||||
) AS "tableLabel",
|
||||
ttc.column_name AS "columnName",
|
||||
COALESCE(
|
||||
cl.column_label,
|
||||
initcap(replace(ttc.column_name, '_', ' '))
|
||||
) AS "columnLabel",
|
||||
ttc.input_type AS "inputType"
|
||||
FROM table_type_columns ttc
|
||||
LEFT JOIN column_labels cl
|
||||
ON ttc.table_name = cl.table_name
|
||||
AND ttc.column_name = cl.column_name
|
||||
LEFT JOIN table_labels tl
|
||||
ON ttc.table_name = tl.table_name
|
||||
WHERE ttc.table_name = ANY($1)
|
||||
AND ttc.company_code = $2
|
||||
AND ttc.input_type = 'category'
|
||||
ORDER BY ttc.table_name, ttc.column_name
|
||||
`;
|
||||
|
||||
logger.info("🔍 카테고리 컬럼 쿼리 실행 중...");
|
||||
const columnsResult = await pool.query(columnsQuery, [tableNames, companyCode]);
|
||||
logger.info("✅ 카테고리 컬럼 쿼리 완료", { rowCount: columnsResult.rows.length });
|
||||
// 3. category_column_mapping 테이블 존재 여부 확인
|
||||
const tableExistsResult = await pool.query(`
|
||||
SELECT EXISTS (
|
||||
SELECT FROM information_schema.tables
|
||||
WHERE table_name = 'category_column_mapping'
|
||||
) as table_exists
|
||||
`);
|
||||
const mappingTableExists = tableExistsResult.rows[0]?.table_exists === true;
|
||||
|
||||
let columnsResult;
|
||||
|
||||
if (mappingTableExists) {
|
||||
// 🆕 category_column_mapping을 사용한 필터링
|
||||
logger.info("🔍 category_column_mapping 기반 카테고리 컬럼 조회", { menuObjid, companyCode });
|
||||
|
||||
// 현재 메뉴와 모든 상위 메뉴의 objid 조회 (재귀)
|
||||
const ancestorMenuQuery = `
|
||||
WITH RECURSIVE menu_hierarchy AS (
|
||||
-- 현재 메뉴
|
||||
SELECT objid, parent_obj_id, menu_type
|
||||
FROM menu_info
|
||||
WHERE objid = $1
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- 부모 메뉴 재귀 조회
|
||||
SELECT m.objid, m.parent_obj_id, m.menu_type
|
||||
FROM menu_info m
|
||||
INNER JOIN menu_hierarchy mh ON m.objid = mh.parent_obj_id
|
||||
WHERE m.parent_obj_id != 0 -- 최상위 메뉴(parent_obj_id=0) 제외
|
||||
)
|
||||
SELECT ARRAY_AGG(objid) as menu_objids
|
||||
FROM menu_hierarchy
|
||||
`;
|
||||
|
||||
const ancestorMenuResult = await pool.query(ancestorMenuQuery, [parseInt(menuObjid)]);
|
||||
const ancestorMenuObjids = ancestorMenuResult.rows[0]?.menu_objids || [parseInt(menuObjid)];
|
||||
|
||||
|
||||
const columnsQuery = `
|
||||
SELECT DISTINCT
|
||||
ttc.table_name AS "tableName",
|
||||
COALESCE(
|
||||
tl.table_label,
|
||||
initcap(replace(ttc.table_name, '_', ' '))
|
||||
) AS "tableLabel",
|
||||
ccm.logical_column_name AS "columnName",
|
||||
COALESCE(
|
||||
cl.column_label,
|
||||
initcap(replace(ccm.logical_column_name, '_', ' '))
|
||||
) AS "columnLabel",
|
||||
ttc.input_type AS "inputType"
|
||||
FROM category_column_mapping ccm
|
||||
INNER JOIN table_type_columns ttc
|
||||
ON ccm.table_name = ttc.table_name
|
||||
AND ccm.physical_column_name = ttc.column_name
|
||||
LEFT JOIN column_labels cl
|
||||
ON ttc.table_name = cl.table_name
|
||||
AND ttc.column_name = cl.column_name
|
||||
LEFT JOIN table_labels tl
|
||||
ON ttc.table_name = tl.table_name
|
||||
WHERE ccm.table_name = ANY($1)
|
||||
AND ccm.company_code = $2
|
||||
AND ccm.menu_objid = ANY($3)
|
||||
AND ttc.input_type = 'category'
|
||||
ORDER BY ttc.table_name, ccm.logical_column_name
|
||||
`;
|
||||
|
||||
columnsResult = await pool.query(columnsQuery, [tableNames, companyCode, ancestorMenuObjids]);
|
||||
logger.info("✅ category_column_mapping 기반 조회 완료", { rowCount: columnsResult.rows.length });
|
||||
} else {
|
||||
// 🔄 기존 방식: table_type_columns에서 모든 카테고리 컬럼 조회
|
||||
logger.info("🔍 레거시 방식: table_type_columns 기반 카테고리 컬럼 조회", { tableNames, companyCode });
|
||||
|
||||
const columnsQuery = `
|
||||
SELECT
|
||||
ttc.table_name AS "tableName",
|
||||
COALESCE(
|
||||
tl.table_label,
|
||||
initcap(replace(ttc.table_name, '_', ' '))
|
||||
) AS "tableLabel",
|
||||
ttc.column_name AS "columnName",
|
||||
COALESCE(
|
||||
cl.column_label,
|
||||
initcap(replace(ttc.column_name, '_', ' '))
|
||||
) AS "columnLabel",
|
||||
ttc.input_type AS "inputType"
|
||||
FROM table_type_columns ttc
|
||||
LEFT JOIN column_labels cl
|
||||
ON ttc.table_name = cl.table_name
|
||||
AND ttc.column_name = cl.column_name
|
||||
LEFT JOIN table_labels tl
|
||||
ON ttc.table_name = tl.table_name
|
||||
WHERE ttc.table_name = ANY($1)
|
||||
AND ttc.company_code = $2
|
||||
AND ttc.input_type = 'category'
|
||||
ORDER BY ttc.table_name, ttc.column_name
|
||||
`;
|
||||
|
||||
columnsResult = await pool.query(columnsQuery, [tableNames, companyCode]);
|
||||
logger.info("✅ 레거시 방식 조회 완료", { rowCount: columnsResult.rows.length });
|
||||
}
|
||||
|
||||
logger.info("✅ 카테고리 컬럼 조회 완료", {
|
||||
columnCount: columnsResult.rows.length
|
||||
|
||||
Reference in New Issue
Block a user