// 수집 관리 서비스 // 작성일: 2024-12-23 import { query, queryOne, transaction } from "../database/db"; import { DataCollectionConfig, CollectionFilter, CollectionJob, CollectionHistory, } from "../types/collectionManagement"; export class CollectionService { /** * 수집 설정 목록 조회 */ static async getCollectionConfigs( filter: CollectionFilter ): Promise { const whereConditions: string[] = ["company_code = $1"]; const values: any[] = [filter.company_code || "*"]; let paramIndex = 2; if (filter.config_name) { whereConditions.push(`config_name ILIKE $${paramIndex++}`); values.push(`%${filter.config_name}%`); } if (filter.source_connection_id) { whereConditions.push(`source_connection_id = $${paramIndex++}`); values.push(filter.source_connection_id); } if (filter.collection_type) { whereConditions.push(`collection_type = $${paramIndex++}`); values.push(filter.collection_type); } if (filter.is_active) { whereConditions.push(`is_active = $${paramIndex++}`); values.push(filter.is_active === "Y"); } if (filter.search) { whereConditions.push( `(config_name ILIKE $${paramIndex} OR description ILIKE $${paramIndex})` ); values.push(`%${filter.search}%`); paramIndex++; } const configs = await query( `SELECT * FROM data_collection_configs WHERE ${whereConditions.join(" AND ")} ORDER BY created_date DESC`, values ); return configs.map((config: any) => ({ ...config, is_active: config.is_active ? "Y" : "N", })) as DataCollectionConfig[]; } /** * 수집 설정 상세 조회 */ static async getCollectionConfigById( id: number ): Promise { const config = await queryOne( `SELECT * FROM data_collection_configs WHERE id = $1`, [id] ); if (!config) return null; return { ...config, is_active: config.is_active ? "Y" : "N", } as DataCollectionConfig; } /** * 수집 설정 생성 */ static async createCollectionConfig( data: DataCollectionConfig ): Promise { const { id, collection_options, ...createData } = data; const config = await queryOne( `INSERT INTO data_collection_configs (config_name, company_code, source_connection_id, collection_type, collection_options, schedule_cron, is_active, description, created_by, updated_by, created_date, updated_date) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, NOW(), NOW()) RETURNING *`, [ createData.config_name, createData.company_code, createData.source_connection_id, createData.collection_type, collection_options ? JSON.stringify(collection_options) : null, createData.schedule_cron, data.is_active, createData.description, createData.created_by, createData.updated_by, ] ); return { ...config, is_active: config.is_active ? "Y" : "N", } as DataCollectionConfig; } /** * 수집 설정 수정 */ static async updateCollectionConfig( id: number, data: Partial ): Promise { const updateFields: string[] = ["updated_date = NOW()"]; const values: any[] = []; let paramIndex = 1; if (data.config_name !== undefined) { updateFields.push(`config_name = $${paramIndex++}`); values.push(data.config_name); } if (data.source_connection_id !== undefined) { updateFields.push(`source_connection_id = $${paramIndex++}`); values.push(data.source_connection_id); } if (data.collection_type !== undefined) { updateFields.push(`collection_type = $${paramIndex++}`); values.push(data.collection_type); } if (data.collection_options !== undefined) { updateFields.push(`collection_options = $${paramIndex++}`); values.push( data.collection_options ? JSON.stringify(data.collection_options) : null ); } if (data.schedule_cron !== undefined) { updateFields.push(`schedule_cron = $${paramIndex++}`); values.push(data.schedule_cron); } if (data.is_active !== undefined) { updateFields.push(`is_active = $${paramIndex++}`); values.push(data.is_active); } if (data.description !== undefined) { updateFields.push(`description = $${paramIndex++}`); values.push(data.description); } if (data.updated_by !== undefined) { updateFields.push(`updated_by = $${paramIndex++}`); values.push(data.updated_by); } const config = await queryOne( `UPDATE data_collection_configs SET ${updateFields.join(", ")} WHERE id = $${paramIndex} RETURNING *`, [...values, id] ); return { ...config, is_active: config.is_active ? "Y" : "N", } as DataCollectionConfig; } /** * 수집 설정 삭제 */ static async deleteCollectionConfig(id: number): Promise { await query(`DELETE FROM data_collection_configs WHERE id = $1`, [id]); } /** * 수집 작업 실행 */ static async executeCollection(configId: number): Promise { const config = await queryOne( `SELECT * FROM data_collection_configs WHERE id = $1`, [configId] ); if (!config) { throw new Error("수집 설정을 찾을 수 없습니다."); } if (!config.is_active) { throw new Error("비활성화된 수집 설정입니다."); } // 수집 작업 기록 생성 const job = await queryOne( `INSERT INTO data_collection_jobs (config_id, job_status, started_at, created_date) VALUES ($1, $2, NOW(), NOW()) RETURNING *`, [configId, "running"] ); // 실제 수집 작업 실행 로직은 여기에 구현 // 현재는 시뮬레이션으로 처리 setTimeout(async () => { try { // 수집 작업 시뮬레이션 await new Promise((resolve) => setTimeout(resolve, 3000)); const recordsCollected = Math.floor(Math.random() * 1000) + 100; await query( `UPDATE data_collection_jobs SET job_status = $1, completed_at = NOW(), records_processed = $2 WHERE id = $3`, ["completed", recordsCollected, job.id] ); } catch (error) { await query( `UPDATE data_collection_jobs SET job_status = $1, completed_at = NOW(), error_message = $2 WHERE id = $3`, [ "failed", error instanceof Error ? error.message : "알 수 없는 오류", job.id, ] ); } }, 0); return job as CollectionJob; } /** * 수집 작업 목록 조회 */ static async getCollectionJobs(configId?: number): Promise { let sql = ` SELECT j.*, c.config_name, c.collection_type FROM data_collection_jobs j LEFT JOIN data_collection_configs c ON j.config_id = c.id `; const values: any[] = []; if (configId) { sql += ` WHERE j.config_id = $1`; values.push(configId); } sql += ` ORDER BY j.started_at DESC`; const jobs = await query(sql, values); return jobs as CollectionJob[]; } /** * 수집 이력 조회 */ static async getCollectionHistory( configId: number ): Promise { const history = await query( `SELECT * FROM data_collection_jobs WHERE config_id = $1 ORDER BY started_at DESC LIMIT 50`, [configId] ); return history.map((item: any) => ({ id: item.id, config_id: item.config_id, status: item.job_status, collection_date: item.started_at, started_at: item.started_at, completed_at: item.completed_at, execution_time_ms: item.completed_at && item.started_at ? new Date(item.completed_at).getTime() - new Date(item.started_at).getTime() : null, records_collected: item.records_processed || 0, result_message: `${item.records_processed || 0}개의 레코드가 처리되었습니다.`, error_message: item.error_message, })) as CollectionHistory[]; } }