제어관리 외부커넥션 설정기능
This commit is contained in:
@@ -4,6 +4,90 @@
|
||||
|
||||
import { apiClient } from "./client";
|
||||
|
||||
/**
|
||||
* 데이터 타입을 웹 타입으로 매핑하는 함수
|
||||
* @param dataType - 데이터베이스 데이터 타입
|
||||
* @returns 웹 타입 문자열
|
||||
*/
|
||||
const mapDataTypeToWebType = (dataType: string | undefined | null): string => {
|
||||
if (!dataType || typeof dataType !== "string") {
|
||||
console.warn(`⚠️ 잘못된 데이터 타입: ${dataType}, 기본값 'text' 사용`);
|
||||
return "text";
|
||||
}
|
||||
|
||||
const lowerType = dataType.toLowerCase();
|
||||
|
||||
// 텍스트 타입
|
||||
if (lowerType.includes("varchar") || lowerType.includes("char") || lowerType.includes("text")) {
|
||||
return "text";
|
||||
}
|
||||
|
||||
// 숫자 타입
|
||||
if (lowerType.includes("int") || lowerType.includes("bigint") || lowerType.includes("smallint")) {
|
||||
return "number";
|
||||
}
|
||||
if (
|
||||
lowerType.includes("decimal") ||
|
||||
lowerType.includes("numeric") ||
|
||||
lowerType.includes("float") ||
|
||||
lowerType.includes("double")
|
||||
) {
|
||||
return "decimal";
|
||||
}
|
||||
|
||||
// 날짜/시간 타입
|
||||
if (lowerType.includes("timestamp") || lowerType.includes("datetime")) {
|
||||
return "datetime";
|
||||
}
|
||||
if (lowerType.includes("date")) {
|
||||
return "date";
|
||||
}
|
||||
if (lowerType.includes("time")) {
|
||||
return "time";
|
||||
}
|
||||
|
||||
// 불린 타입
|
||||
if (lowerType.includes("boolean") || lowerType.includes("bit")) {
|
||||
return "boolean";
|
||||
}
|
||||
|
||||
// 바이너리/파일 타입
|
||||
if (lowerType.includes("bytea") || lowerType.includes("blob") || lowerType.includes("binary")) {
|
||||
return "file";
|
||||
}
|
||||
|
||||
// JSON 타입
|
||||
if (lowerType.includes("json")) {
|
||||
return "text";
|
||||
}
|
||||
|
||||
// 기본값
|
||||
console.log(`🔍 알 수 없는 데이터 타입: ${dataType} → text로 매핑`);
|
||||
return "text";
|
||||
};
|
||||
|
||||
/**
|
||||
* 컬럼명으로부터 코드 카테고리를 추론
|
||||
* 실제 존재하는 카테고리만 반환하도록 개선
|
||||
*/
|
||||
const inferCodeCategory = (columnName: string): string => {
|
||||
const lowerName = columnName.toLowerCase();
|
||||
|
||||
// 실제 데이터베이스에 존재하는 것으로 확인된 카테고리만 반환
|
||||
if (lowerName.includes("status")) return "STATUS";
|
||||
|
||||
// 다른 카테고리들은 실제 존재 여부를 확인한 후 추가
|
||||
// if (lowerName.includes("type")) return "TYPE";
|
||||
// if (lowerName.includes("grade")) return "GRADE";
|
||||
// if (lowerName.includes("level")) return "LEVEL";
|
||||
// if (lowerName.includes("priority")) return "PRIORITY";
|
||||
// if (lowerName.includes("category")) return "CATEGORY";
|
||||
// if (lowerName.includes("role")) return "ROLE";
|
||||
|
||||
// 확인되지 않은 컬럼은 일단 STATUS로 매핑 (임시)
|
||||
return "STATUS";
|
||||
};
|
||||
|
||||
export interface MultiConnectionTableInfo {
|
||||
tableName: string;
|
||||
displayName?: string;
|
||||
@@ -63,12 +147,226 @@ export const getTablesFromConnection = async (connectionId: number): Promise<Mul
|
||||
return response.data.data || [];
|
||||
};
|
||||
|
||||
/**
|
||||
* 특정 커넥션의 모든 테이블 정보 배치 조회 (컬럼 수 포함)
|
||||
*/
|
||||
export const getBatchTablesWithColumns = async (
|
||||
connectionId: number,
|
||||
): Promise<{ tableName: string; displayName?: string; columnCount: number }[]> => {
|
||||
console.log(`🚀 getBatchTablesWithColumns 호출: connectionId=${connectionId}`);
|
||||
|
||||
try {
|
||||
const response = await apiClient.get(`/multi-connection/connections/${connectionId}/tables/batch`);
|
||||
console.log("✅ 배치 테이블 정보 조회 성공:", response.data);
|
||||
|
||||
const result = response.data.data || [];
|
||||
console.log(`📊 배치 조회 결과: ${result.length}개 테이블`, result);
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error("❌ 배치 테이블 정보 조회 실패:", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 특정 커넥션의 테이블 컬럼 정보 조회
|
||||
*/
|
||||
export const getColumnsFromConnection = async (connectionId: number, tableName: string): Promise<ColumnInfo[]> => {
|
||||
const response = await apiClient.get(`/multi-connection/connections/${connectionId}/tables/${tableName}/columns`);
|
||||
return response.data.data || [];
|
||||
console.log(`🔍 getColumnsFromConnection 호출: connectionId=${connectionId}, tableName=${tableName}`);
|
||||
|
||||
try {
|
||||
// 메인 데이터베이스(connectionId = 0)인 경우 기존 API 사용
|
||||
if (connectionId === 0) {
|
||||
console.log("📡 메인 DB API 호출:", `/table-management/tables/${tableName}/columns`);
|
||||
const response = await apiClient.get(`/table-management/tables/${tableName}/columns`);
|
||||
console.log("✅ 메인 DB 응답:", response.data);
|
||||
|
||||
const rawResult = response.data.data || [];
|
||||
|
||||
// 메인 DB는 페이지네이션 구조로 반환됨: {columns: [], total, page, size, totalPages}
|
||||
const columns = rawResult.columns || rawResult;
|
||||
|
||||
// 메인 DB 컬럼에도 코드 타입 감지 로직 적용
|
||||
const result = Array.isArray(columns)
|
||||
? columns.map((col: any) => {
|
||||
const columnName = col.columnName || "";
|
||||
|
||||
// 컬럼명으로 코드 타입 감지
|
||||
const isCodeColumn =
|
||||
columnName.toLowerCase().includes("code") ||
|
||||
columnName.toLowerCase().includes("status") ||
|
||||
columnName.toLowerCase().includes("type") ||
|
||||
columnName.toLowerCase().includes("grade") ||
|
||||
columnName.toLowerCase().includes("level");
|
||||
|
||||
return {
|
||||
...col,
|
||||
webType: isCodeColumn ? "code" : col.webType || mapDataTypeToWebType(col.dataType),
|
||||
codeCategory: isCodeColumn ? inferCodeCategory(columnName) : col.codeCategory,
|
||||
};
|
||||
})
|
||||
: columns;
|
||||
|
||||
console.log("📊 메인 DB 최종 결과:", {
|
||||
rawType: typeof rawResult,
|
||||
rawIsArray: Array.isArray(rawResult),
|
||||
hasColumns: rawResult && typeof rawResult === "object" && "columns" in rawResult,
|
||||
finalType: typeof result,
|
||||
finalIsArray: Array.isArray(result),
|
||||
length: Array.isArray(result) ? result.length : "N/A",
|
||||
sample: Array.isArray(result) ? result.slice(0, 1) : result,
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 외부 커넥션인 경우 external-db-connections API 사용
|
||||
console.log("📡 외부 DB API 호출:", `/external-db-connections/${connectionId}/tables/${tableName}/columns`);
|
||||
const response = await apiClient.get(`/external-db-connections/${connectionId}/tables/${tableName}/columns`);
|
||||
console.log("✅ 외부 DB 응답:", response.data);
|
||||
|
||||
const rawResult = response.data.data || [];
|
||||
|
||||
// 외부 DB 컬럼 구조를 메인 DB 형식으로 변환
|
||||
const result = Array.isArray(rawResult)
|
||||
? rawResult.map((col: any) => {
|
||||
const columnName = col.column_name || col.columnName || "";
|
||||
const dataType = col.data_type || col.dataType || "unknown";
|
||||
|
||||
// 컬럼명이 '_code'로 끝나거나 'status', 'type' 등의 이름을 가진 경우 코드 타입으로 간주
|
||||
const isCodeColumn =
|
||||
columnName.toLowerCase().includes("code") ||
|
||||
columnName.toLowerCase().includes("status") ||
|
||||
columnName.toLowerCase().includes("type") ||
|
||||
columnName.toLowerCase().includes("grade") ||
|
||||
columnName.toLowerCase().includes("level");
|
||||
|
||||
return {
|
||||
columnName: columnName,
|
||||
displayName: col.column_comment || col.displayName || columnName,
|
||||
dataType: dataType,
|
||||
dbType: dataType,
|
||||
webType: isCodeColumn ? "code" : mapDataTypeToWebType(dataType),
|
||||
isNullable: col.is_nullable === "YES" || col.isNullable === true,
|
||||
columnDefault: col.column_default || col.columnDefault,
|
||||
description: col.column_comment || col.description,
|
||||
// 코드 타입인 경우 카테고리 추론
|
||||
codeCategory: isCodeColumn ? inferCodeCategory(columnName) : undefined,
|
||||
};
|
||||
})
|
||||
: rawResult;
|
||||
|
||||
console.log("📊 외부 DB 최종 결과:", {
|
||||
rawType: typeof rawResult,
|
||||
rawIsArray: Array.isArray(rawResult),
|
||||
finalType: typeof result,
|
||||
finalIsArray: Array.isArray(result),
|
||||
length: Array.isArray(result) ? result.length : "N/A",
|
||||
sample: Array.isArray(result) ? result.slice(0, 1) : result,
|
||||
sampleOriginal: Array.isArray(rawResult) ? rawResult.slice(0, 1) : rawResult,
|
||||
});
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error("❌ 컬럼 정보 조회 실패:", error);
|
||||
|
||||
// 개발 환경에서 Mock 데이터 반환
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.warn("🔄 개발 환경: Mock 컬럼 데이터 사용");
|
||||
const mockResult = getMockColumnsForTable(tableName);
|
||||
console.log("📊 Mock 데이터 반환:", {
|
||||
type: typeof mockResult,
|
||||
isArray: Array.isArray(mockResult),
|
||||
length: mockResult.length,
|
||||
sample: mockResult.slice(0, 1),
|
||||
});
|
||||
return mockResult;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Mock 컬럼 데이터 (개발/테스트용)
|
||||
*/
|
||||
const getMockColumnsForTable = (tableName: string): ColumnInfo[] => {
|
||||
const baseColumns: ColumnInfo[] = [
|
||||
{
|
||||
columnName: "id",
|
||||
displayName: "ID",
|
||||
dataType: "NUMBER",
|
||||
webType: "number",
|
||||
isNullable: false,
|
||||
isPrimaryKey: true,
|
||||
columnComment: "고유 식별자",
|
||||
},
|
||||
{
|
||||
columnName: "name",
|
||||
displayName: "이름",
|
||||
dataType: "VARCHAR",
|
||||
webType: "text",
|
||||
isNullable: false,
|
||||
isPrimaryKey: false,
|
||||
columnComment: "이름",
|
||||
},
|
||||
{
|
||||
columnName: "status",
|
||||
displayName: "상태",
|
||||
dataType: "VARCHAR",
|
||||
webType: "code",
|
||||
isNullable: true,
|
||||
isPrimaryKey: false,
|
||||
columnComment: "상태 코드",
|
||||
codeCategory: "STATUS",
|
||||
},
|
||||
{
|
||||
columnName: "created_date",
|
||||
displayName: "생성일시",
|
||||
dataType: "TIMESTAMP",
|
||||
webType: "datetime",
|
||||
isNullable: true,
|
||||
isPrimaryKey: false,
|
||||
columnComment: "생성일시",
|
||||
},
|
||||
{
|
||||
columnName: "updated_date",
|
||||
displayName: "수정일시",
|
||||
dataType: "TIMESTAMP",
|
||||
webType: "datetime",
|
||||
isNullable: true,
|
||||
isPrimaryKey: false,
|
||||
columnComment: "수정일시",
|
||||
},
|
||||
];
|
||||
|
||||
// 테이블명에 따라 추가 컬럼 포함
|
||||
if (tableName.toLowerCase().includes("user")) {
|
||||
baseColumns.push({
|
||||
columnName: "email",
|
||||
displayName: "이메일",
|
||||
dataType: "VARCHAR",
|
||||
webType: "email",
|
||||
isNullable: true,
|
||||
isPrimaryKey: false,
|
||||
columnComment: "이메일 주소",
|
||||
});
|
||||
}
|
||||
|
||||
if (tableName.toLowerCase().includes("product")) {
|
||||
baseColumns.push({
|
||||
columnName: "price",
|
||||
displayName: "가격",
|
||||
dataType: "DECIMAL",
|
||||
webType: "decimal",
|
||||
isNullable: true,
|
||||
isPrimaryKey: false,
|
||||
columnComment: "상품 가격",
|
||||
});
|
||||
}
|
||||
|
||||
return baseColumns;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user