const sqlite3 = require('sqlite3').verbose(); const path = require('path'); const fs = require('fs'); const dbPath = path.join(__dirname, '..', 'data', 'database.sqlite'); const migrationsDir = __dirname; class MigrationManager { constructor() { this.db = new sqlite3.Database(dbPath); } // 初始化迁移表 async initMigrationTable() { return new Promise((resolve, reject) => { this.db.run(` CREATE TABLE IF NOT EXISTS migrations ( id INTEGER PRIMARY KEY AUTOINCREMENT, version INTEGER NOT NULL UNIQUE, name TEXT NOT NULL, executed_at DATETIME DEFAULT CURRENT_TIMESTAMP ) `, (err) => { if (err) reject(err); else resolve(); }); }); } // 获取已执行的迁移版本 async getExecutedMigrations() { return new Promise((resolve, reject) => { this.db.all('SELECT version FROM migrations ORDER BY version', (err, rows) => { if (err) reject(err); else resolve(rows.map(r => r.version)); }); }); } // 记录迁移执行 async recordMigration(version, name) { return new Promise((resolve, reject) => { this.db.run( 'INSERT INTO migrations (version, name) VALUES (?, ?)', [version, name], (err) => { if (err) reject(err); else resolve(); } ); }); } // 执行SQL语句 async executeSql(sql) { return new Promise((resolve, reject) => { this.db.run(sql, (err) => { if (err) { // 忽略字段已存在的错误 if (err.message.includes('duplicate column name')) { resolve(); } else { reject(err); } } else { resolve(); } }); }); } // 加载所有迁移文件 loadMigrations() { const files = fs.readdirSync(migrationsDir) .filter(f => f.match(/^\d{4}-.*\.js$/) && f !== 'index.js') .sort(); return files.map(file => { const version = parseInt(file.split('-')[0]); const name = file.replace(/^\d{4}-/, '').replace('.js', ''); const migration = require(path.join(migrationsDir, file)); return { version, name, file, migration }; }); } // 执行迁移 async runMigrations() { try { console.log('🔄 开始数据库迁移...\n'); // 初始化迁移表 await this.initMigrationTable(); // 获取已执行的迁移 const executed = await this.getExecutedMigrations(); console.log(`📊 已执行迁移: ${executed.length} 个`); // 加载所有迁移文件 const migrations = this.loadMigrations(); console.log(`📁 发现迁移文件: ${migrations.length} 个\n`); // 执行未执行的迁移 let count = 0; for (const { version, name, file, migration } of migrations) { if (!executed.includes(version)) { console.log(`⏳ 执行迁移 [${version}] ${name}...`); try { await migration.up(this); await this.recordMigration(version, name); console.log(`✅ 迁移 [${version}] ${name} 完成\n`); count++; } catch (error) { console.error(`❌ 迁移 [${version}] ${name} 失败:`, error.message); throw error; } } else { console.log(`⏭️ 跳过已执行的迁移 [${version}] ${name}`); } } console.log(`\n✨ 迁移完成!共执行 ${count} 个新迁移`); } catch (error) { console.error('\n❌ 迁移失败:', error); throw error; } finally { this.db.close(); } } } // 如果直接运行此文件 if (require.main === module) { const manager = new MigrationManager(); manager.runMigrations() .then(() => process.exit(0)) .catch(() => process.exit(1)); } module.exports = MigrationManager;