2025-09-25 11:04:16 +09:00
|
|
|
// 배치관리 전용 서비스 (기존 소스와 완전 분리)
|
|
|
|
|
// 작성일: 2024-12-24
|
|
|
|
|
|
2025-10-01 13:30:20 +09:00
|
|
|
import { query, queryOne } from "../database/db";
|
2025-09-25 11:04:16 +09:00
|
|
|
import { PasswordEncryption } from "../utils/passwordEncryption";
|
|
|
|
|
import { DatabaseConnectorFactory } from "../database/DatabaseConnectorFactory";
|
|
|
|
|
|
|
|
|
|
// 배치관리 전용 타입 정의
|
|
|
|
|
export interface BatchConnectionInfo {
|
2025-10-01 14:33:08 +09:00
|
|
|
type: "internal" | "external";
|
2025-09-25 11:04:16 +09:00
|
|
|
id?: number;
|
|
|
|
|
name: string;
|
|
|
|
|
db_type?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface BatchTableInfo {
|
|
|
|
|
table_name: string;
|
|
|
|
|
columns: BatchColumnInfo[];
|
|
|
|
|
description?: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface BatchColumnInfo {
|
|
|
|
|
column_name: string;
|
|
|
|
|
data_type: string;
|
|
|
|
|
is_nullable?: string;
|
|
|
|
|
column_default?: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface BatchApiResponse<T = unknown> {
|
|
|
|
|
success: boolean;
|
|
|
|
|
data?: T;
|
|
|
|
|
message?: string;
|
|
|
|
|
error?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class BatchManagementService {
|
|
|
|
|
/**
|
2025-10-28 12:06:54 +09:00
|
|
|
* 배치관리용 연결 목록 조회 (회사별)
|
2025-09-25 11:04:16 +09:00
|
|
|
*/
|
2025-10-28 12:06:54 +09:00
|
|
|
static async getAvailableConnections(
|
|
|
|
|
userCompanyCode?: string
|
|
|
|
|
): Promise<BatchApiResponse<BatchConnectionInfo[]>> {
|
2025-09-25 11:04:16 +09:00
|
|
|
try {
|
|
|
|
|
const connections: BatchConnectionInfo[] = [];
|
|
|
|
|
|
|
|
|
|
// 내부 DB 추가
|
|
|
|
|
connections.push({
|
2025-10-01 14:33:08 +09:00
|
|
|
type: "internal",
|
|
|
|
|
name: "내부 데이터베이스 (PostgreSQL)",
|
|
|
|
|
db_type: "postgresql",
|
2025-09-25 11:04:16 +09:00
|
|
|
});
|
|
|
|
|
|
2025-10-28 12:06:54 +09:00
|
|
|
// 활성화된 외부 DB 연결 조회 (회사별 필터링)
|
|
|
|
|
let query_sql = `SELECT id, connection_name, db_type, description
|
|
|
|
|
FROM external_db_connections
|
|
|
|
|
WHERE is_active = 'Y'`;
|
|
|
|
|
|
|
|
|
|
const params: any[] = [];
|
|
|
|
|
|
|
|
|
|
// 회사별 필터링 (최고 관리자가 아닌 경우)
|
|
|
|
|
if (userCompanyCode && userCompanyCode !== "*") {
|
|
|
|
|
query_sql += ` AND company_code = $1`;
|
|
|
|
|
params.push(userCompanyCode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
query_sql += ` ORDER BY connection_name ASC`;
|
|
|
|
|
|
2025-10-01 13:30:20 +09:00
|
|
|
const externalConnections = await query<{
|
|
|
|
|
id: number;
|
|
|
|
|
connection_name: string;
|
|
|
|
|
db_type: string;
|
|
|
|
|
description: string;
|
2025-10-28 12:06:54 +09:00
|
|
|
}>(query_sql, params);
|
2025-09-25 11:04:16 +09:00
|
|
|
|
|
|
|
|
// 외부 DB 연결 추가
|
2025-10-01 14:33:08 +09:00
|
|
|
externalConnections.forEach((conn) => {
|
2025-09-25 11:04:16 +09:00
|
|
|
connections.push({
|
2025-10-01 14:33:08 +09:00
|
|
|
type: "external",
|
2025-09-25 11:04:16 +09:00
|
|
|
id: conn.id,
|
|
|
|
|
name: `${conn.connection_name} (${conn.db_type?.toUpperCase()})`,
|
2025-10-01 14:33:08 +09:00
|
|
|
db_type: conn.db_type || undefined,
|
2025-09-25 11:04:16 +09:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
data: connections,
|
2025-10-01 14:33:08 +09:00
|
|
|
message: `${connections.length}개의 연결을 조회했습니다.`,
|
2025-09-25 11:04:16 +09:00
|
|
|
};
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("배치관리 연결 목록 조회 실패:", error);
|
|
|
|
|
return {
|
|
|
|
|
success: false,
|
|
|
|
|
message: "연결 목록 조회 중 오류가 발생했습니다.",
|
2025-10-01 14:33:08 +09:00
|
|
|
error: error instanceof Error ? error.message : "알 수 없는 오류",
|
2025-09-25 11:04:16 +09:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-10-28 12:06:54 +09:00
|
|
|
* 배치관리용 테이블 목록 조회 (회사별)
|
2025-09-25 11:04:16 +09:00
|
|
|
*/
|
|
|
|
|
static async getTablesFromConnection(
|
2025-10-01 14:33:08 +09:00
|
|
|
connectionType: "internal" | "external",
|
2025-10-28 12:06:54 +09:00
|
|
|
connectionId?: number,
|
|
|
|
|
userCompanyCode?: string
|
2025-09-25 11:04:16 +09:00
|
|
|
): Promise<BatchApiResponse<BatchTableInfo[]>> {
|
|
|
|
|
try {
|
|
|
|
|
let tables: BatchTableInfo[] = [];
|
|
|
|
|
|
2025-10-01 14:33:08 +09:00
|
|
|
if (connectionType === "internal") {
|
2025-09-25 11:04:16 +09:00
|
|
|
// 내부 DB 테이블 조회
|
2025-10-01 13:30:20 +09:00
|
|
|
const result = await query<{ table_name: string }>(
|
|
|
|
|
`SELECT table_name
|
2025-09-25 11:04:16 +09:00
|
|
|
FROM information_schema.tables
|
|
|
|
|
WHERE table_schema = 'public'
|
|
|
|
|
AND table_type = 'BASE TABLE'
|
2025-10-01 13:30:20 +09:00
|
|
|
ORDER BY table_name`,
|
|
|
|
|
[]
|
|
|
|
|
);
|
2025-09-25 11:04:16 +09:00
|
|
|
|
2025-10-01 14:33:08 +09:00
|
|
|
tables = result.map((row) => ({
|
2025-09-25 11:04:16 +09:00
|
|
|
table_name: row.table_name,
|
2025-10-01 14:33:08 +09:00
|
|
|
columns: [],
|
2025-09-25 11:04:16 +09:00
|
|
|
}));
|
2025-10-01 14:33:08 +09:00
|
|
|
} else if (connectionType === "external" && connectionId) {
|
2025-10-28 12:06:54 +09:00
|
|
|
// 외부 DB 테이블 조회 (회사별 필터링)
|
|
|
|
|
const tablesResult = await this.getExternalTables(
|
|
|
|
|
connectionId,
|
|
|
|
|
userCompanyCode
|
|
|
|
|
);
|
2025-09-25 11:04:16 +09:00
|
|
|
if (tablesResult.success && tablesResult.data) {
|
|
|
|
|
tables = tablesResult.data;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
data: tables,
|
2025-10-01 14:33:08 +09:00
|
|
|
message: `${tables.length}개의 테이블을 조회했습니다.`,
|
2025-09-25 11:04:16 +09:00
|
|
|
};
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("배치관리 테이블 목록 조회 실패:", error);
|
|
|
|
|
return {
|
|
|
|
|
success: false,
|
|
|
|
|
message: "테이블 목록 조회 중 오류가 발생했습니다.",
|
2025-10-01 14:33:08 +09:00
|
|
|
error: error instanceof Error ? error.message : "알 수 없는 오류",
|
2025-09-25 11:04:16 +09:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-10-28 12:06:54 +09:00
|
|
|
* 배치관리용 테이블 컬럼 정보 조회 (회사별)
|
2025-09-25 11:04:16 +09:00
|
|
|
*/
|
|
|
|
|
static async getTableColumns(
|
2025-10-01 14:33:08 +09:00
|
|
|
connectionType: "internal" | "external",
|
2025-09-25 11:04:16 +09:00
|
|
|
connectionId: number | undefined,
|
2025-10-28 12:06:54 +09:00
|
|
|
tableName: string,
|
|
|
|
|
userCompanyCode?: string
|
2025-09-25 11:04:16 +09:00
|
|
|
): Promise<BatchApiResponse<BatchColumnInfo[]>> {
|
|
|
|
|
try {
|
|
|
|
|
console.log(`[BatchManagementService] getTableColumns 호출:`, {
|
|
|
|
|
connectionType,
|
|
|
|
|
connectionId,
|
2025-10-01 14:33:08 +09:00
|
|
|
tableName,
|
2025-09-25 11:04:16 +09:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let columns: BatchColumnInfo[] = [];
|
|
|
|
|
|
2025-10-01 14:33:08 +09:00
|
|
|
if (connectionType === "internal") {
|
2025-09-25 11:04:16 +09:00
|
|
|
// 내부 DB 컬럼 조회
|
2025-10-01 14:33:08 +09:00
|
|
|
console.log(
|
|
|
|
|
`[BatchManagementService] 내부 DB 컬럼 조회 시작: ${tableName}`
|
|
|
|
|
);
|
2025-09-25 11:04:16 +09:00
|
|
|
|
2025-10-01 14:33:08 +09:00
|
|
|
const result = await query<{
|
|
|
|
|
column_name: string;
|
|
|
|
|
data_type: string;
|
|
|
|
|
is_nullable: string;
|
|
|
|
|
column_default: string | null;
|
2025-10-01 13:30:20 +09:00
|
|
|
}>(
|
|
|
|
|
`SELECT
|
2025-09-25 11:04:16 +09:00
|
|
|
column_name,
|
|
|
|
|
data_type,
|
|
|
|
|
is_nullable,
|
|
|
|
|
column_default
|
|
|
|
|
FROM information_schema.columns
|
|
|
|
|
WHERE table_schema = 'public'
|
2025-10-01 13:30:20 +09:00
|
|
|
AND table_name = $1
|
|
|
|
|
ORDER BY ordinal_position`,
|
|
|
|
|
[tableName]
|
|
|
|
|
);
|
2025-09-25 11:04:16 +09:00
|
|
|
|
2025-09-26 17:29:20 +09:00
|
|
|
console.log(`[BatchManagementService] 쿼리 결과:`, result);
|
|
|
|
|
|
2025-09-25 11:04:16 +09:00
|
|
|
console.log(`[BatchManagementService] 내부 DB 컬럼 조회 결과:`, result);
|
|
|
|
|
|
2025-10-01 14:33:08 +09:00
|
|
|
columns = result.map((row) => ({
|
2025-09-25 11:04:16 +09:00
|
|
|
column_name: row.column_name,
|
|
|
|
|
data_type: row.data_type,
|
|
|
|
|
is_nullable: row.is_nullable,
|
|
|
|
|
column_default: row.column_default,
|
|
|
|
|
}));
|
2025-10-01 14:33:08 +09:00
|
|
|
} else if (connectionType === "external" && connectionId) {
|
2025-10-28 12:06:54 +09:00
|
|
|
// 외부 DB 컬럼 조회 (회사별 필터링)
|
2025-10-01 14:33:08 +09:00
|
|
|
console.log(
|
|
|
|
|
`[BatchManagementService] 외부 DB 컬럼 조회 시작: connectionId=${connectionId}, tableName=${tableName}`
|
|
|
|
|
);
|
2025-09-25 11:04:16 +09:00
|
|
|
|
2025-10-01 14:33:08 +09:00
|
|
|
const columnsResult = await this.getExternalTableColumns(
|
|
|
|
|
connectionId,
|
2025-10-28 12:06:54 +09:00
|
|
|
tableName,
|
|
|
|
|
userCompanyCode
|
2025-10-01 14:33:08 +09:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
console.log(
|
|
|
|
|
`[BatchManagementService] 외부 DB 컬럼 조회 결과:`,
|
|
|
|
|
columnsResult
|
|
|
|
|
);
|
2025-09-25 11:04:16 +09:00
|
|
|
|
|
|
|
|
if (columnsResult.success && columnsResult.data) {
|
|
|
|
|
columns = columnsResult.data;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.log(`[BatchManagementService] 최종 컬럼 목록:`, columns);
|
|
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
data: columns,
|
2025-10-01 14:33:08 +09:00
|
|
|
message: `${columns.length}개의 컬럼을 조회했습니다.`,
|
2025-09-25 11:04:16 +09:00
|
|
|
};
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("[BatchManagementService] 컬럼 정보 조회 오류:", error);
|
|
|
|
|
return {
|
|
|
|
|
success: false,
|
|
|
|
|
message: "컬럼 정보 조회 중 오류가 발생했습니다.",
|
2025-10-01 14:33:08 +09:00
|
|
|
error: error instanceof Error ? error.message : "알 수 없는 오류",
|
2025-09-25 11:04:16 +09:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-10-28 12:06:54 +09:00
|
|
|
* 외부 DB 테이블 목록 조회 (내부 구현, 회사별)
|
2025-09-25 11:04:16 +09:00
|
|
|
*/
|
2025-10-01 14:33:08 +09:00
|
|
|
private static async getExternalTables(
|
2025-10-28 12:06:54 +09:00
|
|
|
connectionId: number,
|
|
|
|
|
userCompanyCode?: string
|
2025-10-01 14:33:08 +09:00
|
|
|
): Promise<BatchApiResponse<BatchTableInfo[]>> {
|
2025-09-25 11:04:16 +09:00
|
|
|
try {
|
2025-10-28 12:06:54 +09:00
|
|
|
// 연결 정보 조회 (회사별 필터링)
|
|
|
|
|
let query_sql = `SELECT * FROM external_db_connections WHERE id = $1`;
|
|
|
|
|
const params: any[] = [connectionId];
|
|
|
|
|
|
|
|
|
|
// 회사별 필터링 (최고 관리자가 아닌 경우)
|
|
|
|
|
if (userCompanyCode && userCompanyCode !== "*") {
|
|
|
|
|
query_sql += ` AND company_code = $2`;
|
|
|
|
|
params.push(userCompanyCode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const connection = await queryOne<any>(query_sql, params);
|
2025-09-25 11:04:16 +09:00
|
|
|
|
|
|
|
|
if (!connection) {
|
|
|
|
|
return {
|
|
|
|
|
success: false,
|
2025-10-28 12:06:54 +09:00
|
|
|
message: "연결 정보를 찾을 수 없거나 권한이 없습니다.",
|
2025-09-25 11:04:16 +09:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 비밀번호 복호화
|
|
|
|
|
const decryptedPassword = PasswordEncryption.decrypt(connection.password);
|
|
|
|
|
if (!decryptedPassword) {
|
|
|
|
|
return {
|
|
|
|
|
success: false,
|
2025-10-01 14:33:08 +09:00
|
|
|
message: "비밀번호 복호화에 실패했습니다.",
|
2025-09-25 11:04:16 +09:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 연결 설정 준비
|
|
|
|
|
const config = {
|
|
|
|
|
host: connection.host,
|
|
|
|
|
port: connection.port,
|
|
|
|
|
database: connection.database_name,
|
|
|
|
|
user: connection.username,
|
|
|
|
|
password: decryptedPassword,
|
2025-10-01 14:33:08 +09:00
|
|
|
connectionTimeoutMillis:
|
|
|
|
|
connection.connection_timeout != null
|
|
|
|
|
? connection.connection_timeout * 1000
|
|
|
|
|
: undefined,
|
|
|
|
|
queryTimeoutMillis:
|
|
|
|
|
connection.query_timeout != null
|
|
|
|
|
? connection.query_timeout * 1000
|
|
|
|
|
: undefined,
|
|
|
|
|
ssl:
|
|
|
|
|
connection.ssl_enabled === "Y"
|
|
|
|
|
? { rejectUnauthorized: false }
|
|
|
|
|
: false,
|
2025-09-25 11:04:16 +09:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// DatabaseConnectorFactory를 통한 테이블 목록 조회
|
2025-10-01 14:33:08 +09:00
|
|
|
const connector = await DatabaseConnectorFactory.createConnector(
|
|
|
|
|
connection.db_type,
|
|
|
|
|
config,
|
|
|
|
|
connectionId
|
|
|
|
|
);
|
2025-09-25 11:04:16 +09:00
|
|
|
const tables = await connector.getTables();
|
2025-10-01 14:33:08 +09:00
|
|
|
|
2025-09-25 11:04:16 +09:00
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
message: "테이블 목록을 조회했습니다.",
|
2025-10-01 14:33:08 +09:00
|
|
|
data: tables,
|
2025-09-25 11:04:16 +09:00
|
|
|
};
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("외부 DB 테이블 목록 조회 오류:", error);
|
|
|
|
|
return {
|
|
|
|
|
success: false,
|
|
|
|
|
message: "테이블 목록 조회 중 오류가 발생했습니다.",
|
2025-10-01 14:33:08 +09:00
|
|
|
error: error instanceof Error ? error.message : "알 수 없는 오류",
|
2025-09-25 11:04:16 +09:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-10-28 12:06:54 +09:00
|
|
|
* 외부 DB 테이블 컬럼 정보 조회 (내부 구현, 회사별)
|
2025-09-25 11:04:16 +09:00
|
|
|
*/
|
2025-10-01 14:33:08 +09:00
|
|
|
private static async getExternalTableColumns(
|
|
|
|
|
connectionId: number,
|
2025-10-28 12:06:54 +09:00
|
|
|
tableName: string,
|
|
|
|
|
userCompanyCode?: string
|
2025-10-01 14:33:08 +09:00
|
|
|
): Promise<BatchApiResponse<BatchColumnInfo[]>> {
|
2025-09-25 11:04:16 +09:00
|
|
|
try {
|
2025-10-01 14:33:08 +09:00
|
|
|
console.log(
|
|
|
|
|
`[BatchManagementService] getExternalTableColumns 호출: connectionId=${connectionId}, tableName=${tableName}`
|
|
|
|
|
);
|
|
|
|
|
|
2025-10-28 12:06:54 +09:00
|
|
|
// 연결 정보 조회 (회사별 필터링)
|
|
|
|
|
let query_sql = `SELECT * FROM external_db_connections WHERE id = $1`;
|
|
|
|
|
const params: any[] = [connectionId];
|
|
|
|
|
|
|
|
|
|
// 회사별 필터링 (최고 관리자가 아닌 경우)
|
|
|
|
|
if (userCompanyCode && userCompanyCode !== "*") {
|
|
|
|
|
query_sql += ` AND company_code = $2`;
|
|
|
|
|
params.push(userCompanyCode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const connection = await queryOne<any>(query_sql, params);
|
2025-09-25 11:04:16 +09:00
|
|
|
|
|
|
|
|
if (!connection) {
|
2025-10-01 14:33:08 +09:00
|
|
|
console.log(
|
2025-10-28 12:06:54 +09:00
|
|
|
`[BatchManagementService] 연결 정보를 찾을 수 없거나 권한이 없음: connectionId=${connectionId}`
|
2025-10-01 14:33:08 +09:00
|
|
|
);
|
2025-09-25 11:04:16 +09:00
|
|
|
return {
|
|
|
|
|
success: false,
|
2025-10-01 14:33:08 +09:00
|
|
|
message: "연결 정보를 찾을 수 없습니다.",
|
2025-09-25 11:04:16 +09:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.log(`[BatchManagementService] 연결 정보 조회 성공:`, {
|
|
|
|
|
id: connection.id,
|
|
|
|
|
connection_name: connection.connection_name,
|
|
|
|
|
db_type: connection.db_type,
|
|
|
|
|
host: connection.host,
|
|
|
|
|
port: connection.port,
|
2025-10-01 14:33:08 +09:00
|
|
|
database_name: connection.database_name,
|
2025-09-25 11:04:16 +09:00
|
|
|
});
|
2025-10-01 14:33:08 +09:00
|
|
|
|
2025-09-25 11:04:16 +09:00
|
|
|
// 비밀번호 복호화
|
|
|
|
|
const decryptedPassword = PasswordEncryption.decrypt(connection.password);
|
2025-10-01 14:33:08 +09:00
|
|
|
|
2025-09-25 11:04:16 +09:00
|
|
|
// 연결 설정 준비
|
|
|
|
|
const config = {
|
|
|
|
|
host: connection.host,
|
|
|
|
|
port: connection.port,
|
|
|
|
|
database: connection.database_name,
|
|
|
|
|
user: connection.username,
|
|
|
|
|
password: decryptedPassword,
|
2025-10-01 14:33:08 +09:00
|
|
|
connectionTimeoutMillis:
|
|
|
|
|
connection.connection_timeout != null
|
|
|
|
|
? connection.connection_timeout * 1000
|
|
|
|
|
: undefined,
|
|
|
|
|
queryTimeoutMillis:
|
|
|
|
|
connection.query_timeout != null
|
|
|
|
|
? connection.query_timeout * 1000
|
|
|
|
|
: undefined,
|
|
|
|
|
ssl:
|
|
|
|
|
connection.ssl_enabled === "Y"
|
|
|
|
|
? { rejectUnauthorized: false }
|
|
|
|
|
: false,
|
2025-09-25 11:04:16 +09:00
|
|
|
};
|
2025-10-01 14:33:08 +09:00
|
|
|
|
|
|
|
|
console.log(
|
|
|
|
|
`[BatchManagementService] 커넥터 생성 시작: db_type=${connection.db_type}`
|
|
|
|
|
);
|
|
|
|
|
|
2025-09-25 11:04:16 +09:00
|
|
|
// 데이터베이스 타입에 따른 커넥터 생성
|
2025-10-01 14:33:08 +09:00
|
|
|
const connector = await DatabaseConnectorFactory.createConnector(
|
|
|
|
|
connection.db_type,
|
|
|
|
|
config,
|
|
|
|
|
connectionId
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
console.log(
|
|
|
|
|
`[BatchManagementService] 커넥터 생성 완료, 컬럼 조회 시작: tableName=${tableName}`
|
|
|
|
|
);
|
|
|
|
|
|
2025-09-25 11:04:16 +09:00
|
|
|
// 컬럼 정보 조회
|
|
|
|
|
console.log(`[BatchManagementService] connector.getColumns 호출 전`);
|
|
|
|
|
const columns = await connector.getColumns(tableName);
|
2025-10-01 14:33:08 +09:00
|
|
|
|
2025-09-25 11:04:16 +09:00
|
|
|
console.log(`[BatchManagementService] 원본 컬럼 조회 결과:`, columns);
|
2025-10-01 14:33:08 +09:00
|
|
|
console.log(
|
|
|
|
|
`[BatchManagementService] 원본 컬럼 개수:`,
|
|
|
|
|
columns ? columns.length : "null/undefined"
|
|
|
|
|
);
|
|
|
|
|
|
2025-09-25 11:04:16 +09:00
|
|
|
// 각 데이터베이스 커넥터의 반환 구조가 다르므로 통일된 구조로 변환
|
|
|
|
|
const standardizedColumns: BatchColumnInfo[] = columns.map((col: any) => {
|
|
|
|
|
console.log(`[BatchManagementService] 컬럼 변환 중:`, col);
|
2025-10-01 14:33:08 +09:00
|
|
|
|
2025-09-25 11:04:16 +09:00
|
|
|
// MySQL/MariaDB 구조: {name, dataType, isNullable, defaultValue} (MySQLConnector만)
|
|
|
|
|
if (col.name && col.dataType !== undefined) {
|
|
|
|
|
const result = {
|
|
|
|
|
column_name: col.name,
|
|
|
|
|
data_type: col.dataType,
|
2025-10-01 14:33:08 +09:00
|
|
|
is_nullable: col.isNullable ? "YES" : "NO",
|
2025-09-25 11:04:16 +09:00
|
|
|
column_default: col.defaultValue || null,
|
|
|
|
|
};
|
2025-10-01 14:33:08 +09:00
|
|
|
console.log(
|
|
|
|
|
`[BatchManagementService] MySQL/MariaDB 구조로 변환:`,
|
|
|
|
|
result
|
|
|
|
|
);
|
2025-09-25 11:04:16 +09:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
// PostgreSQL/Oracle/MSSQL/MariaDB 구조: {column_name, data_type, is_nullable, column_default}
|
|
|
|
|
else {
|
|
|
|
|
const result = {
|
|
|
|
|
column_name: col.column_name || col.COLUMN_NAME,
|
|
|
|
|
data_type: col.data_type || col.DATA_TYPE,
|
2025-10-01 14:33:08 +09:00
|
|
|
is_nullable:
|
|
|
|
|
col.is_nullable ||
|
|
|
|
|
col.IS_NULLABLE ||
|
|
|
|
|
(col.nullable === "Y" ? "YES" : "NO"),
|
2025-09-25 11:04:16 +09:00
|
|
|
column_default: col.column_default || col.COLUMN_DEFAULT || null,
|
|
|
|
|
};
|
|
|
|
|
console.log(`[BatchManagementService] 표준 구조로 변환:`, result);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
});
|
2025-10-01 14:33:08 +09:00
|
|
|
|
|
|
|
|
console.log(
|
|
|
|
|
`[BatchManagementService] 표준화된 컬럼 목록:`,
|
|
|
|
|
standardizedColumns
|
|
|
|
|
);
|
|
|
|
|
|
2025-09-25 11:04:16 +09:00
|
|
|
return {
|
|
|
|
|
success: true,
|
|
|
|
|
data: standardizedColumns,
|
2025-10-01 14:33:08 +09:00
|
|
|
message: "컬럼 정보를 조회했습니다.",
|
2025-09-25 11:04:16 +09:00
|
|
|
};
|
|
|
|
|
} catch (error) {
|
2025-10-01 14:33:08 +09:00
|
|
|
console.error(
|
|
|
|
|
"[BatchManagementService] 외부 DB 컬럼 정보 조회 오류:",
|
|
|
|
|
error
|
|
|
|
|
);
|
|
|
|
|
console.error(
|
|
|
|
|
"[BatchManagementService] 오류 스택:",
|
|
|
|
|
error instanceof Error ? error.stack : "No stack trace"
|
|
|
|
|
);
|
2025-09-25 11:04:16 +09:00
|
|
|
return {
|
|
|
|
|
success: false,
|
|
|
|
|
message: "컬럼 정보 조회 중 오류가 발생했습니다.",
|
2025-10-01 14:33:08 +09:00
|
|
|
error: error instanceof Error ? error.message : "알 수 없는 오류",
|
2025-09-25 11:04:16 +09:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|