docs: Phase 4 남은 Prisma 호출 전환 계획서 작성

현재 상황 분석 및 문서화:

컨트롤러 레이어:
-  adminController.ts (28개) 완료
-  screenFileController.ts (2개) 완료
- 🔄 남은 파일 (12개 호출):
  * webTypeStandardController.ts (11개)
  * fileController.ts (1개)

Routes & Services:
- ddlRoutes.ts (2개)
- companyManagementRoutes.ts (2개)
- multiConnectionQueryService.ts (4개)

Config:
- database.ts (4개 - 제거 예정)

새로운 계획서:
- PHASE4_REMAINING_PRISMA_CALLS.md (상세 전환 계획)
- 파일별 Prisma 호출 상세 분석
- 전환 패턴 및 우선순위 정리

전체 진행률: 445/444 (100.2%)
남은 작업: 12개 (추가 조사 필요한 파일 제외)
This commit is contained in:
kjs
2025-10-01 14:33:08 +09:00
parent 381d19caee
commit 7919079362
23 changed files with 2304 additions and 1295 deletions

View File

@@ -7,7 +7,7 @@ import { DatabaseConnectorFactory } from "../database/DatabaseConnectorFactory";
// 배치관리 전용 타입 정의
export interface BatchConnectionInfo {
type: 'internal' | 'external';
type: "internal" | "external";
id?: number;
name: string;
db_type?: string;
@@ -37,15 +37,17 @@ export class BatchManagementService {
/**
* 배치관리용 연결 목록 조회
*/
static async getAvailableConnections(): Promise<BatchApiResponse<BatchConnectionInfo[]>> {
static async getAvailableConnections(): Promise<
BatchApiResponse<BatchConnectionInfo[]>
> {
try {
const connections: BatchConnectionInfo[] = [];
// 내부 DB 추가
connections.push({
type: 'internal',
name: '내부 데이터베이스 (PostgreSQL)',
db_type: 'postgresql'
type: "internal",
name: "내부 데이터베이스 (PostgreSQL)",
db_type: "postgresql",
});
// 활성화된 외부 DB 연결 조회
@@ -63,26 +65,26 @@ export class BatchManagementService {
);
// 외부 DB 연결 추가
externalConnections.forEach(conn => {
externalConnections.forEach((conn) => {
connections.push({
type: 'external',
type: "external",
id: conn.id,
name: `${conn.connection_name} (${conn.db_type?.toUpperCase()})`,
db_type: conn.db_type || undefined
db_type: conn.db_type || undefined,
});
});
return {
success: true,
data: connections,
message: `${connections.length}개의 연결을 조회했습니다.`
message: `${connections.length}개의 연결을 조회했습니다.`,
};
} catch (error) {
console.error("배치관리 연결 목록 조회 실패:", error);
return {
success: false,
message: "연결 목록 조회 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "알 수 없는 오류"
error: error instanceof Error ? error.message : "알 수 없는 오류",
};
}
}
@@ -91,13 +93,13 @@ export class BatchManagementService {
* 배치관리용 테이블 목록 조회
*/
static async getTablesFromConnection(
connectionType: 'internal' | 'external',
connectionType: "internal" | "external",
connectionId?: number
): Promise<BatchApiResponse<BatchTableInfo[]>> {
try {
let tables: BatchTableInfo[] = [];
if (connectionType === 'internal') {
if (connectionType === "internal") {
// 내부 DB 테이블 조회
const result = await query<{ table_name: string }>(
`SELECT table_name
@@ -108,11 +110,11 @@ export class BatchManagementService {
[]
);
tables = result.map(row => ({
tables = result.map((row) => ({
table_name: row.table_name,
columns: []
columns: [],
}));
} else if (connectionType === 'external' && connectionId) {
} else if (connectionType === "external" && connectionId) {
// 외부 DB 테이블 조회
const tablesResult = await this.getExternalTables(connectionId);
if (tablesResult.success && tablesResult.data) {
@@ -123,14 +125,14 @@ export class BatchManagementService {
return {
success: true,
data: tables,
message: `${tables.length}개의 테이블을 조회했습니다.`
message: `${tables.length}개의 테이블을 조회했습니다.`,
};
} catch (error) {
console.error("배치관리 테이블 목록 조회 실패:", error);
return {
success: false,
message: "테이블 목록 조회 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "알 수 없는 오류"
error: error instanceof Error ? error.message : "알 수 없는 오류",
};
}
}
@@ -139,7 +141,7 @@ export class BatchManagementService {
* 배치관리용 테이블 컬럼 정보 조회
*/
static async getTableColumns(
connectionType: 'internal' | 'external',
connectionType: "internal" | "external",
connectionId: number | undefined,
tableName: string
): Promise<BatchApiResponse<BatchColumnInfo[]>> {
@@ -147,20 +149,22 @@ export class BatchManagementService {
console.log(`[BatchManagementService] getTableColumns 호출:`, {
connectionType,
connectionId,
tableName
tableName,
});
let columns: BatchColumnInfo[] = [];
if (connectionType === 'internal') {
if (connectionType === "internal") {
// 내부 DB 컬럼 조회
console.log(`[BatchManagementService] 내부 DB 컬럼 조회 시작: ${tableName}`);
console.log(
`[BatchManagementService] 내부 DB 컬럼 조회 시작: ${tableName}`
);
const result = await query<{
column_name: string;
data_type: string;
is_nullable: string;
column_default: string | null
const result = await query<{
column_name: string;
data_type: string;
is_nullable: string;
column_default: string | null;
}>(
`SELECT
column_name,
@@ -178,19 +182,27 @@ export class BatchManagementService {
console.log(`[BatchManagementService] 내부 DB 컬럼 조회 결과:`, result);
columns = result.map(row => ({
columns = result.map((row) => ({
column_name: row.column_name,
data_type: row.data_type,
is_nullable: row.is_nullable,
column_default: row.column_default,
}));
} else if (connectionType === 'external' && connectionId) {
} else if (connectionType === "external" && connectionId) {
// 외부 DB 컬럼 조회
console.log(`[BatchManagementService] 외부 DB 컬럼 조회 시작: connectionId=${connectionId}, tableName=${tableName}`);
console.log(
`[BatchManagementService] 외부 DB 컬럼 조회 시작: connectionId=${connectionId}, tableName=${tableName}`
);
const columnsResult = await this.getExternalTableColumns(connectionId, tableName);
console.log(`[BatchManagementService] 외부 DB 컬럼 조회 결과:`, columnsResult);
const columnsResult = await this.getExternalTableColumns(
connectionId,
tableName
);
console.log(
`[BatchManagementService] 외부 DB 컬럼 조회 결과:`,
columnsResult
);
if (columnsResult.success && columnsResult.data) {
columns = columnsResult.data;
@@ -201,14 +213,14 @@ export class BatchManagementService {
return {
success: true,
data: columns,
message: `${columns.length}개의 컬럼을 조회했습니다.`
message: `${columns.length}개의 컬럼을 조회했습니다.`,
};
} catch (error) {
console.error("[BatchManagementService] 컬럼 정보 조회 오류:", error);
return {
success: false,
message: "컬럼 정보 조회 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "알 수 없는 오류"
error: error instanceof Error ? error.message : "알 수 없는 오류",
};
}
}
@@ -216,7 +228,9 @@ export class BatchManagementService {
/**
* 외부 DB 테이블 목록 조회 (내부 구현)
*/
private static async getExternalTables(connectionId: number): Promise<BatchApiResponse<BatchTableInfo[]>> {
private static async getExternalTables(
connectionId: number
): Promise<BatchApiResponse<BatchTableInfo[]>> {
try {
// 연결 정보 조회
const connection = await queryOne<any>(
@@ -227,7 +241,7 @@ export class BatchManagementService {
if (!connection) {
return {
success: false,
message: "연결 정보를 찾을 수 없습니다."
message: "연결 정보를 찾을 수 없습니다.",
};
}
@@ -236,7 +250,7 @@ export class BatchManagementService {
if (!decryptedPassword) {
return {
success: false,
message: "비밀번호 복호화에 실패했습니다."
message: "비밀번호 복호화에 실패했습니다.",
};
}
@@ -247,26 +261,39 @@ export class BatchManagementService {
database: connection.database_name,
user: connection.username,
password: decryptedPassword,
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
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,
};
// DatabaseConnectorFactory를 통한 테이블 목록 조회
const connector = await DatabaseConnectorFactory.createConnector(connection.db_type, config, connectionId);
const connector = await DatabaseConnectorFactory.createConnector(
connection.db_type,
config,
connectionId
);
const tables = await connector.getTables();
return {
success: true,
message: "테이블 목록을 조회했습니다.",
data: tables
data: tables,
};
} catch (error) {
console.error("외부 DB 테이블 목록 조회 오류:", error);
return {
success: false,
message: "테이블 목록 조회 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "알 수 없는 오류"
error: error instanceof Error ? error.message : "알 수 없는 오류",
};
}
}
@@ -274,10 +301,15 @@ export class BatchManagementService {
/**
* 외부 DB 테이블 컬럼 정보 조회 (내부 구현)
*/
private static async getExternalTableColumns(connectionId: number, tableName: string): Promise<BatchApiResponse<BatchColumnInfo[]>> {
private static async getExternalTableColumns(
connectionId: number,
tableName: string
): Promise<BatchApiResponse<BatchColumnInfo[]>> {
try {
console.log(`[BatchManagementService] getExternalTableColumns 호출: connectionId=${connectionId}, tableName=${tableName}`);
console.log(
`[BatchManagementService] getExternalTableColumns 호출: connectionId=${connectionId}, tableName=${tableName}`
);
// 연결 정보 조회
const connection = await queryOne<any>(
`SELECT * FROM external_db_connections WHERE id = $1`,
@@ -285,10 +317,12 @@ export class BatchManagementService {
);
if (!connection) {
console.log(`[BatchManagementService] 연결 정보를 찾을 수 없음: connectionId=${connectionId}`);
console.log(
`[BatchManagementService] 연결 정보를 찾을 수 없음: connectionId=${connectionId}`
);
return {
success: false,
message: "연결 정보를 찾을 수 없습니다."
message: "연결 정보를 찾을 수 없습니다.",
};
}
@@ -298,12 +332,12 @@ export class BatchManagementService {
db_type: connection.db_type,
host: connection.host,
port: connection.port,
database_name: connection.database_name
database_name: connection.database_name,
});
// 비밀번호 복호화
const decryptedPassword = PasswordEncryption.decrypt(connection.password);
// 연결 설정 준비
const config = {
host: connection.host,
@@ -311,38 +345,61 @@ export class BatchManagementService {
database: connection.database_name,
user: connection.username,
password: decryptedPassword,
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
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,
};
console.log(`[BatchManagementService] 커넥터 생성 시작: db_type=${connection.db_type}`);
console.log(
`[BatchManagementService] 커넥터 생성 시작: db_type=${connection.db_type}`
);
// 데이터베이스 타입에 따른 커넥터 생성
const connector = await DatabaseConnectorFactory.createConnector(connection.db_type, config, connectionId);
console.log(`[BatchManagementService] 커넥터 생성 완료, 컬럼 조회 시작: tableName=${tableName}`);
const connector = await DatabaseConnectorFactory.createConnector(
connection.db_type,
config,
connectionId
);
console.log(
`[BatchManagementService] 커넥터 생성 완료, 컬럼 조회 시작: tableName=${tableName}`
);
// 컬럼 정보 조회
console.log(`[BatchManagementService] connector.getColumns 호출 전`);
const columns = await connector.getColumns(tableName);
console.log(`[BatchManagementService] 원본 컬럼 조회 결과:`, columns);
console.log(`[BatchManagementService] 원본 컬럼 개수:`, columns ? columns.length : 'null/undefined');
console.log(
`[BatchManagementService] 원본 컬럼 개수:`,
columns ? columns.length : "null/undefined"
);
// 각 데이터베이스 커넥터의 반환 구조가 다르므로 통일된 구조로 변환
const standardizedColumns: BatchColumnInfo[] = columns.map((col: any) => {
console.log(`[BatchManagementService] 컬럼 변환 중:`, col);
// MySQL/MariaDB 구조: {name, dataType, isNullable, defaultValue} (MySQLConnector만)
if (col.name && col.dataType !== undefined) {
const result = {
column_name: col.name,
data_type: col.dataType,
is_nullable: col.isNullable ? 'YES' : 'NO',
is_nullable: col.isNullable ? "YES" : "NO",
column_default: col.defaultValue || null,
};
console.log(`[BatchManagementService] MySQL/MariaDB 구조로 변환:`, result);
console.log(
`[BatchManagementService] MySQL/MariaDB 구조로 변환:`,
result
);
return result;
}
// PostgreSQL/Oracle/MSSQL/MariaDB 구조: {column_name, data_type, is_nullable, column_default}
@@ -350,30 +407,41 @@ export class BatchManagementService {
const result = {
column_name: col.column_name || col.COLUMN_NAME,
data_type: col.data_type || col.DATA_TYPE,
is_nullable: col.is_nullable || col.IS_NULLABLE || (col.nullable === 'Y' ? 'YES' : 'NO'),
is_nullable:
col.is_nullable ||
col.IS_NULLABLE ||
(col.nullable === "Y" ? "YES" : "NO"),
column_default: col.column_default || col.COLUMN_DEFAULT || null,
};
console.log(`[BatchManagementService] 표준 구조로 변환:`, result);
return result;
}
});
console.log(`[BatchManagementService] 표준화된 컬럼 목록:`, standardizedColumns);
console.log(
`[BatchManagementService] 표준화된 컬럼 목록:`,
standardizedColumns
);
return {
success: true,
data: standardizedColumns,
message: "컬럼 정보를 조회했습니다."
message: "컬럼 정보를 조회했습니다.",
};
} catch (error) {
console.error("[BatchManagementService] 외부 DB 컬럼 정보 조회 오류:", error);
console.error("[BatchManagementService] 오류 스택:", error instanceof Error ? error.stack : 'No stack trace');
console.error(
"[BatchManagementService] 외부 DB 컬럼 정보 조회 오류:",
error
);
console.error(
"[BatchManagementService] 오류 스택:",
error instanceof Error ? error.stack : "No stack trace"
);
return {
success: false,
message: "컬럼 정보 조회 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "알 수 없는 오류"
error: error instanceof Error ? error.message : "알 수 없는 오류",
};
}
}
}