feat: DISTINCT 값 조회 API 추가 및 라우터 설정
- 테이블 컬럼의 DISTINCT 값을 조회하는 API를 추가하였습니다. 이 API는 특정 테이블과 컬럼에서 DISTINCT 값을 반환하여 선택박스 옵션으로 사용할 수 있도록 합니다. - API 호출 시 멀티테넌시를 고려하여 회사 코드에 따라 필터링을 적용하였습니다. - 관련된 라우터 설정을 추가하여 API 접근을 가능하게 하였습니다. - 프론트엔드에서 DISTINCT 값을 조회할 수 있도록 UnifiedSelect 컴포넌트를 업데이트하였습니다.
This commit is contained in:
@@ -3,6 +3,107 @@ import { AuthenticatedRequest } from "../types/auth";
|
||||
import { getPool } from "../database/db";
|
||||
import { logger } from "../utils/logger";
|
||||
|
||||
/**
|
||||
* 테이블 컬럼의 DISTINCT 값 조회 API (inputType: select 용)
|
||||
* GET /api/entity/:tableName/distinct/:columnName
|
||||
*
|
||||
* 해당 테이블의 해당 컬럼에서 DISTINCT 값을 조회하여 선택박스 옵션으로 반환
|
||||
*/
|
||||
export async function getDistinctColumnValues(req: AuthenticatedRequest, res: Response) {
|
||||
try {
|
||||
const { tableName, columnName } = req.params;
|
||||
const { labelColumn } = req.query; // 선택적: 별도의 라벨 컬럼
|
||||
|
||||
// 유효성 검증
|
||||
if (!tableName || tableName === "undefined" || tableName === "null") {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: "테이블명이 지정되지 않았습니다.",
|
||||
});
|
||||
}
|
||||
|
||||
if (!columnName || columnName === "undefined" || columnName === "null") {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: "컬럼명이 지정되지 않았습니다.",
|
||||
});
|
||||
}
|
||||
|
||||
const companyCode = req.user!.companyCode;
|
||||
const pool = getPool();
|
||||
|
||||
// 테이블의 실제 컬럼 목록 조회
|
||||
const columnsResult = await pool.query(
|
||||
`SELECT column_name FROM information_schema.columns
|
||||
WHERE table_schema = 'public' AND table_name = $1`,
|
||||
[tableName]
|
||||
);
|
||||
const existingColumns = new Set(columnsResult.rows.map((r: any) => r.column_name));
|
||||
|
||||
// 요청된 컬럼 검증
|
||||
if (!existingColumns.has(columnName)) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: `테이블 "${tableName}"에 컬럼 "${columnName}"이 존재하지 않습니다.`,
|
||||
});
|
||||
}
|
||||
|
||||
// 라벨 컬럼 결정 (지정되지 않으면 값 컬럼과 동일)
|
||||
const effectiveLabelColumn = labelColumn && existingColumns.has(labelColumn as string)
|
||||
? labelColumn as string
|
||||
: columnName;
|
||||
|
||||
// WHERE 조건 (멀티테넌시)
|
||||
const whereConditions: string[] = [];
|
||||
const params: any[] = [];
|
||||
let paramIndex = 1;
|
||||
|
||||
if (companyCode !== "*" && existingColumns.has("company_code")) {
|
||||
whereConditions.push(`company_code = $${paramIndex}`);
|
||||
params.push(companyCode);
|
||||
paramIndex++;
|
||||
}
|
||||
|
||||
// NULL 제외
|
||||
whereConditions.push(`"${columnName}" IS NOT NULL`);
|
||||
whereConditions.push(`"${columnName}" != ''`);
|
||||
|
||||
const whereClause = whereConditions.length > 0
|
||||
? `WHERE ${whereConditions.join(" AND ")}`
|
||||
: "";
|
||||
|
||||
// DISTINCT 쿼리 실행
|
||||
const query = `
|
||||
SELECT DISTINCT "${columnName}" as value, "${effectiveLabelColumn}" as label
|
||||
FROM "${tableName}"
|
||||
${whereClause}
|
||||
ORDER BY "${effectiveLabelColumn}" ASC
|
||||
LIMIT 500
|
||||
`;
|
||||
|
||||
const result = await pool.query(query, params);
|
||||
|
||||
logger.info("컬럼 DISTINCT 값 조회 성공", {
|
||||
tableName,
|
||||
columnName,
|
||||
labelColumn: effectiveLabelColumn,
|
||||
companyCode,
|
||||
rowCount: result.rowCount,
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: result.rows,
|
||||
});
|
||||
} catch (error: any) {
|
||||
logger.error("컬럼 DISTINCT 값 조회 오류", {
|
||||
error: error.message,
|
||||
stack: error.stack,
|
||||
});
|
||||
res.status(500).json({ success: false, message: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 엔티티 옵션 조회 API (UnifiedSelect용)
|
||||
* GET /api/entity/:tableName/options
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Router } from "express";
|
||||
import { authenticateToken } from "../middleware/authMiddleware";
|
||||
import { searchEntity, getEntityOptions } from "../controllers/entitySearchController";
|
||||
import { searchEntity, getEntityOptions, getDistinctColumnValues } from "../controllers/entitySearchController";
|
||||
|
||||
const router = Router();
|
||||
|
||||
@@ -21,3 +21,9 @@ export const entityOptionsRouter = Router();
|
||||
*/
|
||||
entityOptionsRouter.get("/:tableName/options", authenticateToken, getEntityOptions);
|
||||
|
||||
/**
|
||||
* 테이블 컬럼의 DISTINCT 값 조회 API (inputType: select 용)
|
||||
* GET /api/entity/:tableName/distinct/:columnName
|
||||
*/
|
||||
entityOptionsRouter.get("/:tableName/distinct/:columnName", authenticateToken, getDistinctColumnValues);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user