import mysql from 'mysql2/promise'; import dotenv from 'dotenv'; dotenv.config({ override: true }); const { DB_HOST, DB_USER, DB_PASS, DB_NAME, DB_PORT } = process.env; // 기존의 감점 계산 로직을 그대로 이용해 등급과 감점점수를 도출하는 헬퍼 함수 function parseCpu(cpu) { if (!cpu) return { tier: '기타', deduction: 30 }; const cpuUpper = cpu.toUpperCase().trim(); if (cpuUpper === '-' || cpuUpper === '') return { tier: '기타', deduction: 30 }; let tier = '기타'; let deduction = 30; if (cpuUpper.includes('I9') || cpuUpper.includes('RYZEN 9') || cpuUpper.includes('RYZEN9')) { tier = 'i9 / Ryzen 9'; deduction = 0; } else if (cpuUpper.includes('I7') || cpuUpper.includes('RYZEN 7') || cpuUpper.includes('RYZEN7')) { tier = 'i7 / Ryzen 7'; deduction = 5; } else if (cpuUpper.includes('I5') || cpuUpper.includes('RYZEN 5') || cpuUpper.includes('RYZEN5')) { tier = 'i5 / Ryzen 5'; deduction = 15; } else if (cpuUpper.includes('I3') || cpuUpper.includes('RYZEN 3') || cpuUpper.includes('RYZEN3')) { tier = 'i3 / Ryzen 3'; deduction = 25; } // CPU 세대 감점 계산 (최대 -15점) let genDeduction = 0; const intelMatch = cpuUpper.match(/I\d-?(\d+)/); let gen = 0; if (intelMatch && intelMatch[1]) { const numStr = intelMatch[1]; if (numStr.length === 5) gen = parseInt(numStr.substring(0, 2), 10); else if (numStr.length === 4) gen = parseInt(numStr.substring(0, 1), 10); } const amdMatch = cpuUpper.match(/RYZEN\s?\d\s?-?(\d+)/); let amdGen = 0; if (amdMatch && amdMatch[1] && !intelMatch) { const numStr = amdMatch[1]; if (numStr.length === 4) amdGen = parseInt(numStr.substring(0, 1), 10); } if (intelMatch) { if (gen >= 12) genDeduction = 0; else if (gen >= 10) genDeduction = 5; else if (gen >= 8) genDeduction = 10; else genDeduction = 15; } else if (amdMatch) { if (amdGen >= 5) genDeduction = 0; else if (amdGen >= 3) genDeduction = 5; else genDeduction = 10; } else { genDeduction = 15; } // 최종 등급 감점 + 세대 감점 합산 return { tier, deduction: deduction + genDeduction }; } function parseGpu(gpu) { if (!gpu) return { tier: 'C', deduction: 25 }; const gpuUpper = gpu.toUpperCase().trim(); if (gpuUpper === '-' || gpuUpper === '') return { tier: 'C', deduction: 25 }; if ( gpuUpper.includes('RTX 4090') || gpuUpper.includes('RTX 4080') || gpuUpper.includes('RTX 4070') || gpuUpper.includes('RTX A5000') || gpuUpper.includes('RTX A6000') || gpuUpper.includes('RTX A4000') ) { return { tier: 'S', deduction: 0 }; } else if ( gpuUpper.includes('RTX 3070') || gpuUpper.includes('RTX 3060') || gpuUpper.includes('RTX 2060') || gpuUpper.includes('RTX A2000') || gpuUpper.includes('RTX A3000') || gpuUpper.includes('QUADRO') ) { return { tier: 'A', deduction: 5 }; } else if ( gpuUpper.includes('GTX 1660') || gpuUpper.includes('GTX 1080') || gpuUpper.includes('GTX 1070') || gpuUpper.includes('GTX 1060') || gpuUpper.includes('RX 6700') || gpuUpper.includes('RX 6600') ) { return { tier: 'B', deduction: 15 }; } else { return { tier: 'C', deduction: 25 }; } } function parseRam(ram) { if (!ram) return { tier: '부족', deduction: 25 }; const ramUpper = ram.toUpperCase().trim(); if (ramUpper === '-' || ramUpper === '') return { tier: '부족', deduction: 25 }; const ramMatch = ramUpper.match(/(\d+)\s*GB/); if (ramMatch && ramMatch[1]) { const ramVal = parseInt(ramMatch[1], 10); if (ramVal >= 32) return { tier: '최적', deduction: 0 }; else if (ramVal >= 16) return { tier: '보통', deduction: 10 }; else if (ramVal >= 8) return { tier: '주의', deduction: 20 }; } return { tier: '부족', deduction: 25 }; } async function runMigration() { console.log('🔄 DB 커넥션 연결 중...'); const connection = await mysql.createConnection({ host: DB_HOST, user: DB_USER, password: DB_PASS, database: DB_NAME, port: parseInt(DB_PORT || '3306') }); try { console.log('⚙️ 1. hardware_components_master 테이블 생성...'); await connection.query('DROP TABLE IF EXISTS hardware_components_master'); await connection.query(` CREATE TABLE hardware_components_master ( id INT AUTO_INCREMENT PRIMARY KEY, category VARCHAR(50) NOT NULL COMMENT 'CPU, GPU, RAM 등', component_name VARCHAR(255) NOT NULL UNIQUE COMMENT '부품 표준 명칭', score_tier VARCHAR(50) COMMENT '성능 등급', deduction INT DEFAULT 0 COMMENT '감점 점수', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; `); console.log('✅ 테이블 생성 완료.'); console.log('🔍 2. 기존 asset_spec 테이블에서 부품명 조회...'); const [specRows] = await connection.query('SELECT DISTINCT cpu, ram, gpu FROM asset_spec'); const uniqueCpus = new Set(); const uniqueGpus = new Set(); const uniqueRams = new Set(); specRows.forEach(row => { if (row.cpu && row.cpu.trim() !== '-' && row.cpu.trim() !== '') uniqueCpus.add(row.cpu.trim()); if (row.gpu && row.gpu.trim() !== '-' && row.gpu.trim() !== '') uniqueGpus.add(row.gpu.trim()); if (row.ram && row.ram.trim() !== '-' && row.ram.trim() !== '') uniqueRams.add(row.ram.trim()); }); // 만약 데이터가 너무 비어있을 경우를 대비하여 기본 대표 부품 몇 개 추가 if (uniqueCpus.size === 0) { ['Intel Core i9-13900K', 'Intel Core i7-14700K', 'Intel Core i5-12400', 'AMD Ryzen 7 7800X3D', 'Intel Core i3-10100'].forEach(c => uniqueCpus.add(c)); } if (uniqueGpus.size === 0) { ['NVIDIA GeForce RTX 4090', 'NVIDIA GeForce RTX 4070', 'NVIDIA GeForce RTX 3060', 'Intel Iris Xe Graphics', 'NVIDIA GeForce GTX 1660 Super'].forEach(g => uniqueGpus.add(g)); } if (uniqueRams.size === 0) { ['8GB', '16GB', '32GB', '64GB'].forEach(r => uniqueRams.add(r)); } console.log(` - 추출된 CPU 개수: ${uniqueCpus.size}`); console.log(` - 추출된 GPU 개수: ${uniqueGpus.size}`); console.log(` - 추출된 RAM 개수: ${uniqueRams.size}`); console.log('💾 3. 마스터 테이블에 부품 데이터 및 감점 정보 삽입...'); // CPU 삽입 for (const cpu of uniqueCpus) { const { tier, deduction } = parseCpu(cpu); await connection.query( 'INSERT IGNORE INTO hardware_components_master (category, component_name, score_tier, deduction) VALUES (?, ?, ?, ?)', ['CPU', cpu, tier, deduction] ); } // GPU 삽입 for (const gpu of uniqueGpus) { const { tier, deduction } = parseGpu(gpu); await connection.query( 'INSERT IGNORE INTO hardware_components_master (category, component_name, score_tier, deduction) VALUES (?, ?, ?, ?)', ['GPU', gpu, tier, deduction] ); } // RAM 삽입 for (const ram of uniqueRams) { const { tier, deduction } = parseRam(ram); await connection.query( 'INSERT IGNORE INTO hardware_components_master (category, component_name, score_tier, deduction) VALUES (?, ?, ?, ?)', ['RAM', ram, tier, deduction] ); } console.log('✅ 마이그레이션이 성공적으로 완료되었습니다!'); } catch (error) { console.error('❌ 마이그레이션 오류 발생:', error); } finally { await connection.end(); } } runMigration();