From fc99beb8516b05ba56932614356961b2d4307b0f Mon Sep 17 00:00:00 2001 From: leeheejin Date: Wed, 1 Oct 2025 09:58:38 +0900 Subject: [PATCH] =?UTF-8?q?TypeScript=20=EC=98=A4=EB=A5=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EB=B0=8F=20Merge=20conflict=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - dataflowControlService.ts: condition.field non-null assertion 추가 - batchExternalDbService.ts: connection 속성들 non-null assertion 추가, error 타입 unknown으로 변경 - multiConnectionQueryService.ts: connection, schemaResult.data non-null assertion 추가 - dataflowExecutionController.ts: 도달할 수 없는 코드 제거 - TableListComponent.tsx, SingleTableWithSticky.tsx: merge conflict 마커 제거 - 모든 TypeScript 컴파일 오류 해결 완료 --- .../dataflowExecutionController.ts | 12 -- .../src/services/batchExternalDbService.ts | 134 +++++++++--------- .../src/services/dataflowControlService.ts | 8 +- .../services/multiConnectionQueryService.ts | 10 +- .../table-list/SingleTableWithSticky.tsx | 4 - .../table-list/TableListComponent.tsx | 4 - 6 files changed, 76 insertions(+), 96 deletions(-) diff --git a/backend-node/src/controllers/dataflowExecutionController.ts b/backend-node/src/controllers/dataflowExecutionController.ts index 7f8dc0f1..b4714e0e 100644 --- a/backend-node/src/controllers/dataflowExecutionController.ts +++ b/backend-node/src/controllers/dataflowExecutionController.ts @@ -101,18 +101,6 @@ async function executeExternalDatabaseAction( ): Promise { // 보안상 외부 DB에 대한 모든 데이터 변경 작업은 비활성화 throw new Error(`보안상 외부 데이터베이스에 대한 ${actionType.toUpperCase()} 작업은 허용되지 않습니다. SELECT 쿼리만 사용해주세요.`); - - return { - success: true, - message: `외부 DB 액션 실행 완료: ${actionType} on ${tableName}`, - connection: connection.name, - data: result, - affectedRows: 1, - }; - } catch (error) { - logger.error(`외부 DB 액션 실행 오류 (${actionType}):`, error); - throw error; - } } /** diff --git a/backend-node/src/services/batchExternalDbService.ts b/backend-node/src/services/batchExternalDbService.ts index 6cbc8ca5..f67edab5 100644 --- a/backend-node/src/services/batchExternalDbService.ts +++ b/backend-node/src/services/batchExternalDbService.ts @@ -60,12 +60,12 @@ export class BatchExternalDbService { data: connections, message: `${connections.length}개의 연결을 조회했습니다.` }; - } catch (error) { + } catch (error: unknown) { console.error("배치관리 연결 목록 조회 실패:", error); return { success: false, message: "연결 목록 조회 중 오류가 발생했습니다.", - error: error instanceof Error ? error.message : "알 수 없는 오류" + error: error instanceof Error ? (error as Error).message : "알 수 없는 오류" }; } } @@ -107,12 +107,12 @@ export class BatchExternalDbService { data: tables, message: `${tables.length}개의 테이블을 조회했습니다.` }; - } catch (error) { + } catch (error: unknown) { console.error("배치관리 테이블 목록 조회 실패:", error); return { success: false, message: "테이블 목록 조회 중 오류가 발생했습니다.", - error: error instanceof Error ? error.message : "알 수 없는 오류" + error: error instanceof Error ? (error as Error).message : "알 수 없는 오류" }; } } @@ -182,12 +182,12 @@ export class BatchExternalDbService { data: columns, message: `${columns.length}개의 컬럼을 조회했습니다.` }; - } catch (error) { + } catch (error: unknown) { console.error("[BatchExternalDbService] 컬럼 정보 조회 오류:", error); return { success: false, message: "컬럼 정보 조회 중 오류가 발생했습니다.", - error: error instanceof Error ? error.message : "알 수 없는 오류" + error: error instanceof Error ? (error as Error).message : "알 수 없는 오류" }; } } @@ -210,7 +210,7 @@ export class BatchExternalDbService { } // 비밀번호 복호화 - const decryptedPassword = PasswordEncryption.decrypt(connection.password); + const decryptedPassword = PasswordEncryption.decrypt(connection!.password); if (!decryptedPassword) { return { success: false, @@ -220,10 +220,10 @@ export class BatchExternalDbService { // 연결 설정 준비 const config = { - host: connection.host, - port: connection.port, - database: connection.database_name, - user: connection.username, + host: connection!.host, + port: connection!.port, + 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, @@ -231,7 +231,7 @@ export class BatchExternalDbService { }; // 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 { @@ -239,12 +239,12 @@ export class BatchExternalDbService { message: "테이블 목록을 조회했습니다.", data: tables }; - } catch (error) { + } catch (error: unknown) { console.error("외부 DB 테이블 목록 조회 오류:", error); return { success: false, message: "테이블 목록 조회 중 오류가 발생했습니다.", - error: error instanceof Error ? error.message : "알 수 없는 오류" + error: error instanceof Error ? (error as Error).message : "알 수 없는 오류" }; } } @@ -272,31 +272,31 @@ export class BatchExternalDbService { console.log(`[BatchExternalDbService] 연결 정보 조회 성공:`, { id: connection.id, connection_name: connection.connection_name, - db_type: connection.db_type, - host: connection.host, - port: connection.port, - database_name: connection.database_name + db_type: connection!.db_type, + host: connection!.host, + port: connection!.port, + database_name: connection!.database_name }); // 비밀번호 복호화 - const decryptedPassword = PasswordEncryption.decrypt(connection.password); + const decryptedPassword = PasswordEncryption.decrypt(connection!.password); // 연결 설정 준비 const config = { - host: connection.host, - port: connection.port, - database: connection.database_name, - user: connection.username, + host: connection!.host, + port: connection!.port, + 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 }; - console.log(`[BatchExternalDbService] 커넥터 생성 시작: db_type=${connection.db_type}`); + console.log(`[BatchExternalDbService] 커넥터 생성 시작: db_type=${connection!.db_type}`); // 데이터베이스 타입에 따른 커넥터 생성 - const connector = await DatabaseConnectorFactory.createConnector(connection.db_type, config, connectionId); + const connector = await DatabaseConnectorFactory.createConnector(connection!.db_type, config, connectionId); console.log(`[BatchExternalDbService] 커넥터 생성 완료, 컬럼 조회 시작: tableName=${tableName}`); @@ -341,11 +341,11 @@ export class BatchExternalDbService { if (!standardizedColumns || standardizedColumns.length === 0) { console.warn(`[BatchExternalDbService] 컬럼이 비어있음: connectionId=${connectionId}, tableName=${tableName}`); console.warn(`[BatchExternalDbService] 연결 정보:`, { - db_type: connection.db_type, - host: connection.host, - port: connection.port, - database_name: connection.database_name, - username: connection.username + db_type: connection!.db_type, + host: connection!.host, + port: connection!.port, + database_name: connection!.database_name, + username: connection!.username }); // 테이블 존재 여부 확인 @@ -395,13 +395,13 @@ export class BatchExternalDbService { data: standardizedColumns, message: "컬럼 정보를 조회했습니다." }; - } catch (error) { + } catch (error: unknown) { console.error("[BatchExternalDbService] 외부 DB 컬럼 정보 조회 오류:", error); console.error("[BatchExternalDbService] 오류 스택:", error instanceof Error ? error.stack : 'No stack trace'); return { success: false, message: "컬럼 정보 조회 중 오류가 발생했습니다.", - error: error instanceof Error ? error.message : "알 수 없는 오류" + error: error instanceof Error ? (error as Error).message : "알 수 없는 오류" }; } } @@ -430,27 +430,27 @@ export class BatchExternalDbService { } // 패스워드 복호화 - const decryptedPassword = PasswordEncryption.decrypt(connection.password); + const decryptedPassword = PasswordEncryption.decrypt(connection!.password); // DB 연결 설정 const config = { - host: connection.host, - port: connection.port, - user: connection.username, + host: connection!.host, + port: connection!.port, + user: connection!.username, password: decryptedPassword, - database: connection.database_name, + database: connection!.database_name, }; // DB 커넥터 생성 const connector = await DatabaseConnectorFactory.createConnector( - connection.db_type || 'postgresql', + connection!.db_type || 'postgresql', config, connectionId ); // 데이터 조회 (DB 타입에 따라 쿼리 구문 변경) let query: string; - const dbType = connection.db_type?.toLowerCase() || 'postgresql'; + const dbType = connection!.db_type?.toLowerCase() || 'postgresql'; if (dbType === 'oracle') { query = `SELECT * FROM ${tableName} WHERE ROWNUM <= ${limit}`; @@ -467,12 +467,12 @@ export class BatchExternalDbService { success: true, data: result.rows }; - } catch (error) { + } catch (error: unknown) { console.error(`외부 DB 데이터 조회 오류 (connectionId: ${connectionId}, table: ${tableName}):`, error); return { success: false, message: "외부 DB 데이터 조회 중 오류가 발생했습니다.", - error: error instanceof Error ? error.message : "알 수 없는 오류" + error: error instanceof Error ? (error as Error).message : "알 수 없는 오류" }; } } @@ -502,27 +502,27 @@ export class BatchExternalDbService { } // 패스워드 복호화 - const decryptedPassword = PasswordEncryption.decrypt(connection.password); + const decryptedPassword = PasswordEncryption.decrypt(connection!.password); // DB 연결 설정 const config = { - host: connection.host, - port: connection.port, - user: connection.username, + host: connection!.host, + port: connection!.port, + user: connection!.username, password: decryptedPassword, - database: connection.database_name, + database: connection!.database_name, }; // DB 커넥터 생성 const connector = await DatabaseConnectorFactory.createConnector( - connection.db_type || 'postgresql', + connection!.db_type || 'postgresql', config, connectionId ); // 데이터 조회 (DB 타입에 따라 쿼리 구문 변경) let query: string; - const dbType = connection.db_type?.toLowerCase() || 'postgresql'; + const dbType = connection!.db_type?.toLowerCase() || 'postgresql'; const columnList = columns.join(', '); if (dbType === 'oracle') { @@ -540,12 +540,12 @@ export class BatchExternalDbService { success: true, data: result.rows }; - } catch (error) { + } catch (error: unknown) { console.error(`외부 DB 특정 컬럼 조회 오류 (connectionId: ${connectionId}, table: ${tableName}):`, error); return { success: false, message: "외부 DB 특정 컬럼 조회 중 오류가 발생했습니다.", - error: error instanceof Error ? error.message : "알 수 없는 오류" + error: error instanceof Error ? (error as Error).message : "알 수 없는 오류" }; } } @@ -586,20 +586,20 @@ export class BatchExternalDbService { } // 패스워드 복호화 - const decryptedPassword = PasswordEncryption.decrypt(connection.password); + const decryptedPassword = PasswordEncryption.decrypt(connection!.password); // DB 연결 설정 const config = { - host: connection.host, - port: connection.port, - user: connection.username, + host: connection!.host, + port: connection!.port, + user: connection!.username, password: decryptedPassword, - database: connection.database_name, + database: connection!.database_name, }; // DB 커넥터 생성 const connector = await DatabaseConnectorFactory.createConnector( - connection.db_type || 'postgresql', + connection!.db_type || 'postgresql', config, connectionId ); @@ -649,7 +649,7 @@ export class BatchExternalDbService { const updateColumns = columns.filter(col => col !== primaryKeyColumn); let query: string; - const dbType = connection.db_type?.toLowerCase() || 'mysql'; + const dbType = connection!.db_type?.toLowerCase() || 'mysql'; if (dbType === 'mysql' || dbType === 'mariadb') { // MySQL/MariaDB: ON DUPLICATE KEY UPDATE 사용 @@ -671,7 +671,7 @@ export class BatchExternalDbService { await connector.executeQuery(query); successCount++; - } catch (error) { + } catch (error: unknown) { console.error(`외부 DB 레코드 UPSERT 실패:`, error); failedCount++; } @@ -683,12 +683,12 @@ export class BatchExternalDbService { success: true, data: { successCount, failedCount } }; - } catch (error) { + } catch (error: unknown) { console.error(`외부 DB 데이터 삽입 오류 (connectionId: ${connectionId}, table: ${tableName}):`, error); return { success: false, message: "외부 DB 데이터 삽입 중 오류가 발생했습니다.", - error: error instanceof Error ? error.message : "알 수 없는 오류" + error: error instanceof Error ? (error as Error).message : "알 수 없는 오류" }; } } @@ -776,12 +776,12 @@ export class BatchExternalDbService { success: true, data: data }; - } catch (error) { + } catch (error: unknown) { console.error(`[BatchExternalDbService] REST API 데이터 조회 오류 (${apiUrl}${endpoint}):`, error); return { success: false, message: "REST API 데이터 조회 중 오류가 발생했습니다.", - error: error instanceof Error ? error.message : "알 수 없는 오류" + error: error instanceof Error ? (error as Error).message : "알 수 없는 오류" }; } } @@ -868,7 +868,7 @@ export class BatchExternalDbService { await connector.executeQuery(finalEndpoint, method, requestData); successCount++; - } catch (error) { + } catch (error: unknown) { console.error(`REST API 레코드 전송 실패:`, error); failedCount++; } @@ -880,7 +880,7 @@ export class BatchExternalDbService { success: true, data: { successCount, failedCount } }; - } catch (error) { + } catch (error: unknown) { console.error(`[BatchExternalDbService] 템플릿 기반 REST API 데이터 전송 오류:`, error); return { success: false, @@ -924,7 +924,7 @@ export class BatchExternalDbService { await connector.executeQuery(endpoint, method, record); successCount++; - } catch (error) { + } catch (error: unknown) { console.error(`REST API 레코드 전송 실패:`, error); failedCount++; } @@ -936,12 +936,12 @@ export class BatchExternalDbService { success: true, data: { successCount, failedCount } }; - } catch (error) { + } catch (error: unknown) { console.error(`[BatchExternalDbService] REST API 데이터 전송 오류 (${apiUrl}${endpoint}):`, error); return { success: false, message: "REST API 데이터 전송 중 오류가 발생했습니다.", - error: error instanceof Error ? error.message : "알 수 없는 오류" + error: error instanceof Error ? (error as Error).message : "알 수 없는 오류" }; } } diff --git a/backend-node/src/services/dataflowControlService.ts b/backend-node/src/services/dataflowControlService.ts index 07a6bd79..1263d490 100644 --- a/backend-node/src/services/dataflowControlService.ts +++ b/backend-node/src/services/dataflowControlService.ts @@ -958,7 +958,7 @@ export class DataflowControlService { condition.value !== undefined ) { // 조건에서 테이블명을 추출 (테이블명.필드명 형식이거나 기본 소스 테이블) - const parts = condition.field.split("."); + const parts = condition.field!.split("."); let tableName: string; let fieldName: string; @@ -976,7 +976,7 @@ export class DataflowControlService { `DELETE 조건에서 테이블을 결정할 수 없습니다. 필드를 "테이블명.필드명" 형식으로 지정하거나 fieldMappings에 targetTable을 설정하세요.` ); } - fieldName = condition.field; + fieldName = condition.field!; } if (!tableGroups.has(tableName)) { @@ -1041,14 +1041,14 @@ export class DataflowControlService { targetTable: tableName, whereClause, }); - } catch (error) { + } catch (error: unknown) { console.error(`❌ DELETE 실패:`, { table: tableName, error: error, }); const userFriendlyMessage = - error instanceof Error ? error.message : String(error); + error instanceof Error ? (error as Error).message : String(error); results.push({ message: `DELETE 실패: ${tableName}`, diff --git a/backend-node/src/services/multiConnectionQueryService.ts b/backend-node/src/services/multiConnectionQueryService.ts index 0f05269e..2549fcdc 100644 --- a/backend-node/src/services/multiConnectionQueryService.ts +++ b/backend-node/src/services/multiConnectionQueryService.ts @@ -152,7 +152,7 @@ export class MultiConnectionQueryService { let values = Object.values(data); // Oracle의 경우 테이블 스키마 확인 및 데이터 타입 변환 처리 - if (connection.db_type?.toLowerCase() === 'oracle') { + if (connection?.db_type?.toLowerCase() === 'oracle') { try { // Oracle 테이블 스키마 조회 const schemaQuery = ` @@ -171,13 +171,13 @@ export class MultiConnectionQueryService { if (schemaResult.success && schemaResult.data) { logger.info(`📋 Oracle 테이블 ${tableName} 스키마:`); - schemaResult.data.forEach((col: any) => { + schemaResult.data!.forEach((col: any) => { logger.info(` - ${col.COLUMN_NAME}: ${col.DATA_TYPE}, NULL: ${col.NULLABLE}, DEFAULT: ${col.DATA_DEFAULT || 'None'}`); }); // 필수 컬럼 중 누락된 컬럼이 있는지 확인 (기본값이 없는 NOT NULL 컬럼만) const providedColumns = columns.map(col => col.toUpperCase()); - const missingRequiredColumns = schemaResult.data.filter((schemaCol: any) => + const missingRequiredColumns = schemaResult.data!.filter((schemaCol: any) => schemaCol.NULLABLE === 'N' && !schemaCol.DATA_DEFAULT && !providedColumns.includes(schemaCol.COLUMN_NAME) @@ -216,7 +216,7 @@ export class MultiConnectionQueryService { let query: string; let queryParams: any[]; - const dbType = connection.db_type?.toLowerCase() || 'postgresql'; + const dbType = connection?.db_type?.toLowerCase() || 'postgresql'; switch (dbType) { case 'oracle': @@ -281,7 +281,7 @@ export class MultiConnectionQueryService { } logger.info(`데이터 삽입 완료`); - return result.data[0] || result.data; + return result.data?.[0] || result.data || []; } catch (error) { logger.error(`데이터 삽입 실패: ${error}`); throw new Error( diff --git a/frontend/lib/registry/components/table-list/SingleTableWithSticky.tsx b/frontend/lib/registry/components/table-list/SingleTableWithSticky.tsx index 82f6ca33..a0d78ad8 100644 --- a/frontend/lib/registry/components/table-list/SingleTableWithSticky.tsx +++ b/frontend/lib/registry/components/table-list/SingleTableWithSticky.tsx @@ -88,11 +88,7 @@ export const SingleTableWithSticky: React.FC = ({ ? "h-12 border-0 px-6 py-4 text-center align-middle" : "h-12 cursor-pointer border-0 px-6 py-4 text-left align-middle font-semibold whitespace-nowrap text-gray-700 select-none transition-all duration-200 hover:text-gray-900", `text-${column.align}`, -<<<<<<< HEAD - column.sortable && "hover:bg-orange-50 hover:text-orange-700", -======= column.sortable && "hover:bg-orange-200/70", ->>>>>>> 8c19d57ced949bde4c9ffcce6544791d3e4b051f // 고정 컬럼 스타일 column.fixed === "left" && "sticky z-10 border-r border-gray-200/40 bg-gradient-to-r from-slate-50/90 to-gray-50/70 shadow-sm", column.fixed === "right" && "sticky z-10 border-l border-gray-200/40 bg-gradient-to-r from-slate-50/90 to-gray-50/70 shadow-sm", diff --git a/frontend/lib/registry/components/table-list/TableListComponent.tsx b/frontend/lib/registry/components/table-list/TableListComponent.tsx index f5725c68..55bcaa40 100644 --- a/frontend/lib/registry/components/table-list/TableListComponent.tsx +++ b/frontend/lib/registry/components/table-list/TableListComponent.tsx @@ -1329,11 +1329,7 @@ export const TableListComponent: React.FC = ({ {/* 헤더 */} {tableConfig.showHeader && (
>>>>>> 8c19d57ced949bde4c9ffcce6544791d3e4b051f style={{ width: "100%", maxWidth: "100%",