테이블 데이터 필터링 기능 및 textarea컴포넌트 자동 매핑 삭제

This commit is contained in:
kjs
2025-11-13 17:06:41 +09:00
parent a828f54663
commit 296ee3e825
17 changed files with 941 additions and 98 deletions

View File

@@ -0,0 +1,154 @@
/**
* 데이터 필터 유틸리티
* 프론트엔드의 DataFilterConfig를 SQL WHERE 절로 변환
*/
export interface ColumnFilter {
id: string;
columnName: string;
operator: "equals" | "not_equals" | "in" | "not_in" | "contains" | "starts_with" | "ends_with" | "is_null" | "is_not_null";
value: string | string[];
valueType: "static" | "category" | "code";
}
export interface DataFilterConfig {
enabled: boolean;
filters: ColumnFilter[];
matchType: "all" | "any"; // AND / OR
}
/**
* DataFilterConfig를 SQL WHERE 조건과 파라미터로 변환
* @param dataFilter 필터 설정
* @param tableAlias 테이블 별칭 (예: "r", "t1") - 조인 쿼리에서 사용
* @param startParamIndex 시작 파라미터 인덱스 (예: 1이면 $1부터 시작)
* @returns { whereClause: string, params: any[] }
*/
export function buildDataFilterWhereClause(
dataFilter: DataFilterConfig | undefined,
tableAlias?: string,
startParamIndex: number = 1
): { whereClause: string; params: any[] } {
if (!dataFilter || !dataFilter.enabled || !dataFilter.filters || dataFilter.filters.length === 0) {
return { whereClause: "", params: [] };
}
const conditions: string[] = [];
const params: any[] = [];
let paramIndex = startParamIndex;
// 테이블 별칭이 있으면 "alias."를 붙이고, 없으면 그냥 컬럼명만
const getColumnRef = (colName: string) => {
return tableAlias ? `${tableAlias}."${colName}"` : `"${colName}"`;
};
for (const filter of dataFilter.filters) {
const { columnName, operator, value } = filter;
if (!columnName) {
continue; // 컬럼명이 없으면 스킵
}
const columnRef = getColumnRef(columnName);
switch (operator) {
case "equals":
conditions.push(`${columnRef} = $${paramIndex}`);
params.push(value);
paramIndex++;
break;
case "not_equals":
conditions.push(`${columnRef} != $${paramIndex}`);
params.push(value);
paramIndex++;
break;
case "in":
if (Array.isArray(value) && value.length > 0) {
const placeholders = value.map((_, idx) => `$${paramIndex + idx}`).join(", ");
conditions.push(`${columnRef} IN (${placeholders})`);
params.push(...value);
paramIndex += value.length;
}
break;
case "not_in":
if (Array.isArray(value) && value.length > 0) {
const placeholders = value.map((_, idx) => `$${paramIndex + idx}`).join(", ");
conditions.push(`${columnRef} NOT IN (${placeholders})`);
params.push(...value);
paramIndex += value.length;
}
break;
case "contains":
conditions.push(`${columnRef} LIKE $${paramIndex}`);
params.push(`%${value}%`);
paramIndex++;
break;
case "starts_with":
conditions.push(`${columnRef} LIKE $${paramIndex}`);
params.push(`${value}%`);
paramIndex++;
break;
case "ends_with":
conditions.push(`${columnRef} LIKE $${paramIndex}`);
params.push(`%${value}`);
paramIndex++;
break;
case "is_null":
conditions.push(`${columnRef} IS NULL`);
break;
case "is_not_null":
conditions.push(`${columnRef} IS NOT NULL`);
break;
default:
// 알 수 없는 연산자는 무시
break;
}
}
if (conditions.length === 0) {
return { whereClause: "", params: [] };
}
// matchType에 따라 AND / OR 조합
const logicalOperator = dataFilter.matchType === "any" ? " OR " : " AND ";
const whereClause = `(${conditions.join(logicalOperator)})`;
return { whereClause, params };
}
/**
* 기존 WHERE 절에 dataFilter 조건을 추가
* @param existingWhere 기존 WHERE 절 (예: "company_code = $1")
* @param existingParams 기존 파라미터 배열
* @param dataFilter 필터 설정
* @returns { whereClause: string, params: any[] }
*/
export function appendDataFilterToWhere(
existingWhere: string,
existingParams: any[],
dataFilter: DataFilterConfig | undefined
): { whereClause: string; params: any[] } {
const { whereClause: filterWhere, params: filterParams } = buildDataFilterWhereClause(
dataFilter,
existingParams.length + 1
);
if (!filterWhere) {
return { whereClause: existingWhere, params: existingParams };
}
const newWhere = existingWhere ? `${existingWhere} AND ${filterWhere}` : filterWhere;
const newParams = [...existingParams, ...filterParams];
return { whereClause: newWhere, params: newParams };
}