조인테이블의 컬럼 사용할 수 있도록 수정

This commit is contained in:
kjs
2025-09-16 18:02:19 +09:00
parent 1d05965a55
commit 049d8ed295
8 changed files with 523 additions and 9 deletions

View File

@@ -25,6 +25,7 @@ export class EntityJoinController {
sortBy,
sortOrder = "asc",
enableEntityJoin = true,
additionalJoinColumns, // 추가 조인 컬럼 정보 (JSON 문자열)
userLang, // userLang은 별도로 분리하여 search에 포함되지 않도록 함
...otherParams
} = req.query;
@@ -49,6 +50,21 @@ export class EntityJoinController {
}
}
// 추가 조인 컬럼 정보 처리
let parsedAdditionalJoinColumns: any[] = [];
if (additionalJoinColumns) {
try {
parsedAdditionalJoinColumns =
typeof additionalJoinColumns === "string"
? JSON.parse(additionalJoinColumns)
: additionalJoinColumns;
logger.info("추가 조인 컬럼 파싱 완료:", parsedAdditionalJoinColumns);
} catch (error) {
logger.warn("추가 조인 컬럼 파싱 오류:", error);
parsedAdditionalJoinColumns = [];
}
}
const result = await tableManagementService.getTableDataWithEntityJoins(
tableName,
{
@@ -62,6 +78,7 @@ export class EntityJoinController {
sortOrder: sortOrder as string,
enableEntityJoin:
enableEntityJoin === "true" || enableEntityJoin === true,
additionalJoinColumns: parsedAdditionalJoinColumns,
}
);
@@ -295,6 +312,124 @@ export class EntityJoinController {
}
}
/**
* Entity 조인된 테이블의 추가 컬럼 목록 조회
* GET /api/table-management/tables/:tableName/entity-join-columns
*/
async getEntityJoinColumns(req: Request, res: Response): Promise<void> {
try {
const { tableName } = req.params;
logger.info(`Entity 조인 컬럼 조회: ${tableName}`);
// 1. 현재 테이블의 Entity 조인 설정 조회
const joinConfigs = await entityJoinService.detectEntityJoins(tableName);
if (joinConfigs.length === 0) {
res.status(200).json({
success: true,
message: "Entity 조인 설정이 없습니다.",
data: {
tableName,
joinTables: [],
availableColumns: [],
},
});
return;
}
// 2. 각 조인 테이블의 컬럼 정보 조회
const joinTablesInfo = await Promise.all(
joinConfigs.map(async (config) => {
try {
const columns =
await tableManagementService.getReferenceTableColumns(
config.referenceTable
);
// 현재 display_column으로 사용 중인 컬럼 제외
const availableColumns = columns.filter(
(col) => col.columnName !== config.displayColumn
);
return {
joinConfig: config,
tableName: config.referenceTable,
currentDisplayColumn: config.displayColumn,
availableColumns: availableColumns.map((col) => ({
columnName: col.columnName,
columnLabel: col.displayName || col.columnName,
dataType: col.dataType,
isNullable: true, // 기본값으로 설정
maxLength: undefined, // 정보가 없으므로 undefined
description: col.displayName,
})),
};
} catch (error) {
logger.warn(
`참조 테이블 컬럼 조회 실패: ${config.referenceTable}`,
error
);
return {
joinConfig: config,
tableName: config.referenceTable,
currentDisplayColumn: config.displayColumn,
availableColumns: [],
error: error instanceof Error ? error.message : "Unknown error",
};
}
})
);
// 3. 사용 가능한 모든 컬럼 목록 생성 (중복 제거)
const allAvailableColumns: Array<{
tableName: string;
columnName: string;
columnLabel: string;
dataType: string;
joinAlias: string;
suggestedLabel: string;
}> = [];
joinTablesInfo.forEach((info) => {
info.availableColumns.forEach((col) => {
const joinAlias = `${info.joinConfig.sourceColumn}_${col.columnName}`;
const suggestedLabel = col.columnLabel; // 라벨명만 사용
allAvailableColumns.push({
tableName: info.tableName,
columnName: col.columnName,
columnLabel: col.columnLabel,
dataType: col.dataType,
joinAlias,
suggestedLabel,
});
});
});
res.status(200).json({
success: true,
message: "Entity 조인 컬럼 조회 성공",
data: {
tableName,
joinTables: joinTablesInfo,
availableColumns: allAvailableColumns,
summary: {
totalJoinTables: joinConfigs.length,
totalAvailableColumns: allAvailableColumns.length,
},
},
});
} catch (error) {
logger.error("Entity 조인 컬럼 조회 실패", error);
res.status(500).json({
success: false,
message: "Entity 조인 컬럼 조회 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "Unknown error",
});
}
}
/**
* 공통 참조 테이블 자동 캐싱
* POST /api/table-management/cache/preload

View File

@@ -120,6 +120,71 @@ router.put(
// 🎯 참조 테이블 정보
// ========================================
/**
* Entity 조인된 테이블의 추가 컬럼 목록 조회 (화면편집기용)
* GET /api/table-management/tables/:tableName/entity-join-columns
*
* 특정 테이블에 설정된 모든 Entity 조인의 참조 테이블들에서
* 추가로 표시할 수 있는 컬럼들의 목록을 반환합니다.
*
* Response:
* {
* success: true,
* data: {
* tableName: "companies",
* joinTables: [
* {
* joinConfig: { sourceColumn: "writer", referenceTable: "user_info", ... },
* tableName: "user_info",
* currentDisplayColumn: "user_name",
* availableColumns: [
* {
* columnName: "email",
* columnLabel: "이메일",
* dataType: "character varying",
* isNullable: true,
* description: "사용자 이메일"
* },
* {
* columnName: "dept_code",
* columnLabel: "부서코드",
* dataType: "character varying",
* isNullable: false,
* description: "소속 부서"
* }
* ]
* }
* ],
* availableColumns: [
* {
* tableName: "user_info",
* columnName: "email",
* columnLabel: "이메일",
* dataType: "character varying",
* joinAlias: "writer_email",
* suggestedLabel: "writer (이메일)"
* },
* {
* tableName: "user_info",
* columnName: "dept_code",
* columnLabel: "부서코드",
* dataType: "character varying",
* joinAlias: "writer_dept_code",
* suggestedLabel: "writer (부서코드)"
* }
* ],
* summary: {
* totalJoinTables: 1,
* totalAvailableColumns: 2
* }
* }
* }
*/
router.get(
"/tables/:tableName/entity-join-columns",
entityJoinController.getEntityJoinColumns.bind(entityJoinController)
);
/**
* 참조 테이블의 표시 가능한 컬럼 목록 조회
* GET /api/table-management/reference-tables/:tableName/columns

View File

@@ -93,11 +93,11 @@ export class EntityJoinService {
// 기본 SELECT 컬럼들
const baseColumns = selectColumns.map((col) => `main.${col}`).join(", ");
// Entity 조인 컬럼들
// Entity 조인 컬럼들 (COALESCE로 NULL을 빈 문자열로 처리)
const joinColumns = joinConfigs
.map(
(config) =>
`${config.referenceTable.substring(0, 3)}.${config.displayColumn} AS ${config.aliasColumn}`
`COALESCE(${config.referenceTable.substring(0, 3)}.${config.displayColumn}, '') AS ${config.aliasColumn}`
)
.join(", ");

View File

@@ -1412,6 +1412,11 @@ export class TableManagementService {
sortBy?: string;
sortOrder?: string;
enableEntityJoin?: boolean;
additionalJoinColumns?: Array<{
sourceTable: string;
sourceColumn: string;
joinAlias: string;
}>;
}
): Promise<EntityJoinResponse> {
const startTime = Date.now();
@@ -1432,7 +1437,41 @@ export class TableManagementService {
}
// Entity 조인 설정 감지
const joinConfigs = await entityJoinService.detectEntityJoins(tableName);
let joinConfigs = await entityJoinService.detectEntityJoins(tableName);
// 추가 조인 컬럼 정보가 있으면 조인 설정에 추가
if (
options.additionalJoinColumns &&
options.additionalJoinColumns.length > 0
) {
logger.info(
`추가 조인 컬럼 처리: ${options.additionalJoinColumns.length}`
);
for (const additionalColumn of options.additionalJoinColumns) {
// 기존 조인 설정에서 같은 참조 테이블을 사용하는 설정 찾기
const baseJoinConfig = joinConfigs.find(
(config) => config.referenceTable === additionalColumn.sourceTable
);
if (baseJoinConfig) {
// 추가 조인 컬럼 설정 생성
const additionalJoinConfig: EntityJoinConfig = {
sourceTable: tableName,
sourceColumn: baseJoinConfig.sourceColumn, // 원본 컬럼 (writer)
referenceTable: additionalColumn.sourceTable, // 참조 테이블 (user_info)
referenceColumn: baseJoinConfig.referenceColumn, // 참조 키 (user_id)
displayColumn: additionalColumn.sourceColumn, // 표시할 컬럼 (email)
aliasColumn: additionalColumn.joinAlias, // 별칭 (writer_email)
};
joinConfigs.push(additionalJoinConfig);
logger.info(
`추가 조인 컬럼 설정 추가: ${additionalJoinConfig.aliasColumn}`
);
}
}
}
if (joinConfigs.length === 0) {
logger.info(`Entity 조인 설정이 없음: ${tableName}`);
@@ -1624,7 +1663,11 @@ export class TableManagementService {
String(sourceValue)
);
enhancedRow[config.aliasColumn] = lookupValue || sourceValue;
// null이나 undefined인 경우 빈 문자열로 설정
enhancedRow[config.aliasColumn] = lookupValue || "";
} else {
// sourceValue가 없는 경우도 빈 문자열로 설정
enhancedRow[config.aliasColumn] = "";
}
}
@@ -1946,11 +1989,18 @@ export class TableManagementService {
const keyValue = row[config.sourceColumn];
if (keyValue) {
const lookupValue = cachedData.get(String(keyValue));
if (lookupValue) {
row[config.aliasColumn] = lookupValue;
}
// null이나 undefined인 경우 빈 문자열로 설정
row[config.aliasColumn] = lookupValue || "";
} else {
// sourceValue가 없는 경우도 빈 문자열로 설정
row[config.aliasColumn] = "";
}
});
} else {
// 캐시가 없는 경우 모든 행에 빈 문자열 설정
enhancedData.forEach((row) => {
row[config.aliasColumn] = "";
});
}
}