feat: enhance data mapping and entity join handling in components

- Updated ButtonPrimaryComponent to utilize entity join metadata for improved data mapping.
- Introduced getEntityJoinColumns method in TableListComponent to retrieve entity join column metadata.
- Enhanced applyMappingRules function to support optional entity join columns, allowing for more flexible data resolution.
- Added utility functions to build join alias maps and resolve values from entity joins, improving data handling capabilities.

These enhancements aim to provide a more robust and dynamic data mapping experience, facilitating better integration of entity relationships in the application.
This commit is contained in:
kjs
2026-03-17 23:27:39 +09:00
parent 2772c2296c
commit a6aa57fece
4 changed files with 104 additions and 8 deletions
+69 -7
View File
@@ -8,21 +8,27 @@ import type {
Condition,
TransformFunction,
} from "@/types/screen-embedding";
import type { EntityJoinColumnMeta } from "@/types/data-transfer";
import { logger } from "./logger";
/**
* 매핑 규칙 적용
* @param data 배열 또는 단일 객체
* @param rules 매핑 규칙 배열
* @param entityJoinColumns 엔티티 조인 메타데이터 (선택적) - sourceField 값이 비었을 때 조인 alias에서 해결
* @returns 매핑된 배열
*/
export function applyMappingRules(data: any[] | any, rules: MappingRule[]): any[] {
export function applyMappingRules(
data: any[] | any,
rules: MappingRule[],
entityJoinColumns?: EntityJoinColumnMeta[],
): any[] {
// 빈 데이터 처리
if (!data) {
return [];
}
// 🆕 배열이 아닌 경우 배열로 변환
// 배열이 아닌 경우 배열로 변환
const dataArray = Array.isArray(data) ? data : [data];
if (dataArray.length === 0) {
@@ -42,22 +48,34 @@ export function applyMappingRules(data: any[] | any, rules: MappingRule[]): any[
return [applyTransformRules(dataArray, rules)];
}
// 엔티티 조인 alias 역방향 맵 구성: { referenceColumn → joinAlias }
// ex) joinAlias "part_code_item_name" → sourceColumn "part_code", referenceColumn "item_name"
const joinAliasMap = buildJoinAliasMap(entityJoinColumns);
// 일반 매핑 (각 행에 대해 매핑)
// 🆕 원본 데이터를 복사한 후 매핑 규칙 적용 (매핑되지 않은 필드도 유지)
// 원본 데이터를 복사한 후 매핑 규칙 적용 (매핑되지 않은 필드도 유지)
return dataArray.map((row) => {
// 원본 데이터 복사
const mappedRow: any = { ...row };
for (const rule of rules) {
// sourceField와 targetField가 모두 있어야 매핑 적용
if (!rule.sourceField || !rule.targetField) {
continue;
}
const sourceValue = getNestedValue(row, rule.sourceField);
let sourceValue = getNestedValue(row, rule.sourceField);
// sourceField 값이 비어있으면 엔티티 조인 alias에서 해결 시도
if (isEmptyValue(sourceValue) && joinAliasMap.size > 0) {
sourceValue = resolveFromEntityJoin(row, rule.targetField, joinAliasMap);
if (sourceValue !== undefined) {
logger.info(
`[dataMapping] 엔티티 조인 해결: ${rule.sourceField}(비어있음) → targetField "${rule.targetField}" → alias에서 값 획득`,
);
}
}
const targetValue = sourceValue ?? rule.defaultValue;
// 소스 필드와 타겟 필드가 다르면 소스 필드 제거 후 타겟 필드에 설정
if (rule.sourceField !== rule.targetField) {
delete mappedRow[rule.sourceField];
}
@@ -69,6 +87,50 @@ export function applyMappingRules(data: any[] | any, rules: MappingRule[]): any[
});
}
/**
* 엔티티 조인 alias에서 역방향 참조 맵 구성
* joinAlias 네이밍 규칙: {sourceColumn}_{referenceColumn}
* 예: "part_code_item_name" → sourceColumn="part_code", referenceColumn="item_name"
*
* 반환 Map: referenceColumn → joinAlias
* 예: "item_name" → "part_code_item_name"
*/
function buildJoinAliasMap(
entityJoinColumns?: EntityJoinColumnMeta[],
): Map<string, string> {
const map = new Map<string, string>();
if (!entityJoinColumns || entityJoinColumns.length === 0) return map;
for (const meta of entityJoinColumns) {
const prefix = `${meta.sourceColumn}_`;
if (meta.joinAlias.startsWith(prefix)) {
const referenceColumn = meta.joinAlias.slice(prefix.length);
map.set(referenceColumn, meta.joinAlias);
}
}
return map;
}
/**
* 엔티티 조인 alias에서 targetField에 해당하는 값 해결
* targetField 이름으로 조인 alias를 찾아 row에서 값을 가져옴
*/
function resolveFromEntityJoin(
row: any,
targetField: string,
joinAliasMap: Map<string, string>,
): any {
const joinAlias = joinAliasMap.get(targetField);
if (!joinAlias) return undefined;
const value = row[joinAlias];
return isEmptyValue(value) ? undefined : value;
}
function isEmptyValue(value: any): boolean {
return value === null || value === undefined || value === "";
}
/**
* 변환 함수 적용
*/