Implement Comma Value Resolution in Entity Join Service
- Added a new method `resolveCommaValues` in `EntityJoinService` to handle comma-separated values for entity joins, allowing for individual code resolution and label conversion. - Integrated the new method into `TableManagementService` to process data after executing join queries. - Enhanced the `DynamicComponentRenderer` to maintain entity label columns based on existing configurations. Made-with: Cursor
This commit is contained in:
parent
6395f4d032
commit
e305e78155
|
|
@ -823,6 +823,76 @@ export class EntityJoinService {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 콤마 구분 다중값 해결 (겸직 부서 등)
|
||||||
|
* entity join이 NULL인데 소스값에 콤마가 있으면 개별 코드를 각각 조회해서 라벨로 변환
|
||||||
|
*/
|
||||||
|
async resolveCommaValues(
|
||||||
|
data: Record<string, any>[],
|
||||||
|
joinConfigs: EntityJoinConfig[]
|
||||||
|
): Promise<Record<string, any>[]> {
|
||||||
|
if (!data.length || !joinConfigs.length) return data;
|
||||||
|
|
||||||
|
for (const config of joinConfigs) {
|
||||||
|
const sourceCol = config.sourceColumn;
|
||||||
|
const displayCol = config.displayColumns?.[0] || config.displayColumn;
|
||||||
|
if (!displayCol || displayCol === "none") continue;
|
||||||
|
|
||||||
|
const aliasCol = config.aliasColumn || `${sourceCol}_${displayCol}`;
|
||||||
|
const labelCol = `${sourceCol}_label`;
|
||||||
|
|
||||||
|
const codesSet = new Set<string>();
|
||||||
|
const rowsToResolve: number[] = [];
|
||||||
|
|
||||||
|
data.forEach((row, idx) => {
|
||||||
|
const srcVal = row[sourceCol];
|
||||||
|
if (!srcVal || typeof srcVal !== "string" || !srcVal.includes(",")) return;
|
||||||
|
|
||||||
|
const joinedVal = row[aliasCol] || row[labelCol];
|
||||||
|
if (joinedVal && joinedVal !== "") return;
|
||||||
|
|
||||||
|
rowsToResolve.push(idx);
|
||||||
|
srcVal.split(",").map((v: string) => v.trim()).filter(Boolean).forEach((code: string) => codesSet.add(code));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (codesSet.size === 0) continue;
|
||||||
|
|
||||||
|
const codes = Array.from(codesSet);
|
||||||
|
const refCol = config.referenceColumn || "id";
|
||||||
|
const placeholders = codes.map((_, i) => `$${i + 1}`).join(",");
|
||||||
|
try {
|
||||||
|
const result = await query<Record<string, any>>(
|
||||||
|
`SELECT "${refCol}"::TEXT as _key, "${displayCol}"::TEXT as _label
|
||||||
|
FROM ${config.referenceTable}
|
||||||
|
WHERE "${refCol}"::TEXT IN (${placeholders})`,
|
||||||
|
codes
|
||||||
|
);
|
||||||
|
|
||||||
|
const labelMap = new Map<string, string>();
|
||||||
|
result.forEach((r) => labelMap.set(r._key, r._label));
|
||||||
|
|
||||||
|
for (const idx of rowsToResolve) {
|
||||||
|
const srcVal = data[idx][sourceCol] as string;
|
||||||
|
const resolvedLabels = srcVal
|
||||||
|
.split(",")
|
||||||
|
.map((v: string) => v.trim())
|
||||||
|
.filter(Boolean)
|
||||||
|
.map((code: string) => labelMap.get(code) || code)
|
||||||
|
.join(", ");
|
||||||
|
|
||||||
|
data[idx][aliasCol] = resolvedLabels;
|
||||||
|
data[idx][labelCol] = resolvedLabels;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(`콤마 구분 entity 값 해결: ${sourceCol} → ${codesSet.size}개 코드, ${rowsToResolve.length}개 행`);
|
||||||
|
} catch (err) {
|
||||||
|
logger.warn(`콤마 구분 entity 값 해결 실패: ${sourceCol}`, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const entityJoinService = new EntityJoinService();
|
export const entityJoinService = new EntityJoinService();
|
||||||
|
|
|
||||||
|
|
@ -3588,12 +3588,15 @@ export class TableManagementService {
|
||||||
`✅ [executeJoinQuery] 조회 완료: ${dataResult?.length}개 행`
|
`✅ [executeJoinQuery] 조회 완료: ${dataResult?.length}개 행`
|
||||||
);
|
);
|
||||||
|
|
||||||
const data = Array.isArray(dataResult) ? dataResult : [];
|
let data = Array.isArray(dataResult) ? dataResult : [];
|
||||||
const total =
|
const total =
|
||||||
Array.isArray(countResult) && countResult.length > 0
|
Array.isArray(countResult) && countResult.length > 0
|
||||||
? Number((countResult[0] as any).total)
|
? Number((countResult[0] as any).total)
|
||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
|
// 콤마 구분 다중값 후처리 (겸직 부서 등)
|
||||||
|
data = await entityJoinService.resolveCommaValues(data, joinConfigs);
|
||||||
|
|
||||||
const queryTime = Date.now() - startTime;
|
const queryTime = Date.now() - startTime;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -1085,7 +1085,7 @@ export const V2Input = forwardRef<HTMLDivElement, V2InputProps>((props, ref) =>
|
||||||
const hasCustomRadius = !!style?.borderRadius;
|
const hasCustomRadius = !!style?.borderRadius;
|
||||||
|
|
||||||
const customTextStyle: React.CSSProperties = {};
|
const customTextStyle: React.CSSProperties = {};
|
||||||
if (style?.color) customTextStyle.color = style.color;
|
if (style?.color) customTextStyle.color = getAdaptiveLabelColor(style.color);
|
||||||
if (style?.fontSize) customTextStyle.fontSize = style.fontSize;
|
if (style?.fontSize) customTextStyle.fontSize = style.fontSize;
|
||||||
if (style?.fontWeight) customTextStyle.fontWeight = style.fontWeight;
|
if (style?.fontWeight) customTextStyle.fontWeight = style.fontWeight;
|
||||||
if (style?.textAlign) customTextStyle.textAlign = style.textAlign as React.CSSProperties["textAlign"];
|
if (style?.textAlign) customTextStyle.textAlign = style.textAlign as React.CSSProperties["textAlign"];
|
||||||
|
|
|
||||||
|
|
@ -102,12 +102,16 @@ function mergeColumnMeta(tableName: string | undefined, columnName: string | und
|
||||||
if (dbInputType === "entity") {
|
if (dbInputType === "entity") {
|
||||||
const refTable = meta.reference_table || meta.referenceTable;
|
const refTable = meta.reference_table || meta.referenceTable;
|
||||||
const refColumn = meta.reference_column || meta.referenceColumn;
|
const refColumn = meta.reference_column || meta.referenceColumn;
|
||||||
const displayCol = meta.display_column || meta.displayColumn;
|
const rawDisplayCol = meta.display_column || meta.displayColumn;
|
||||||
|
const displayCol = rawDisplayCol && rawDisplayCol !== "none" && rawDisplayCol !== "" ? rawDisplayCol : undefined;
|
||||||
if (refTable) {
|
if (refTable) {
|
||||||
merged.source = "entity";
|
merged.source = "entity";
|
||||||
merged.entityTable = refTable;
|
merged.entityTable = refTable;
|
||||||
merged.entityValueColumn = refColumn || "id";
|
merged.entityValueColumn = refColumn || "id";
|
||||||
merged.entityLabelColumn = displayCol || "name";
|
// 화면 설정에 이미 entityLabelColumn이 있으면 유지, 없으면 DB 값 또는 기본값 사용
|
||||||
|
if (!merged.entityLabelColumn) {
|
||||||
|
merged.entityLabelColumn = displayCol || "name";
|
||||||
|
}
|
||||||
merged.fieldType = "entity";
|
merged.fieldType = "entity";
|
||||||
merged.inputType = "entity";
|
merged.inputType = "entity";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue