UNPKG

@onurege3467/zerohelper

Version:

ZeroHelper is a versatile high-performance utility library and database framework for Node.js, fully written in TypeScript.

98 lines (97 loc) 4.48 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MigrationManager = void 0; const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); class MigrationManager { constructor(database, options = {}) { this.db = database; this.migrationsDir = options.migrationsDir || './migrations'; this.migrationsTable = options.migrationsTable || 'migrations'; this.ensureMigrationsDir(); } ensureMigrationsDir() { if (!fs_1.default.existsSync(this.migrationsDir)) { fs_1.default.mkdirSync(this.migrationsDir, { recursive: true }); } } async ensureMigrationsTable() { try { await this.db.selectOne(this.migrationsTable, {}); } catch (error) { if (this.db.constructor.name === 'MySQLDatabase') { await this.db.query(`CREATE TABLE IF NOT EXISTS ${this.migrationsTable} (id INTEGER PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255) NOT NULL UNIQUE, executed_at DATETIME DEFAULT CURRENT_TIMESTAMP)`); } else if (this.db.constructor.name === 'PostgreSQLDatabase') { await this.db.query(`CREATE TABLE IF NOT EXISTS ${this.migrationsTable} (id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL UNIQUE, executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)`); } else { await this.db.query(`CREATE TABLE IF NOT EXISTS ${this.migrationsTable} (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(255) NOT NULL UNIQUE, executed_at DATETIME DEFAULT CURRENT_TIMESTAMP)`); } } } createMigration(name, description = '') { const timestamp = Date.now(); const filename = `${timestamp}_${name}.ts`; const filePath = path_1.default.join(this.migrationsDir, filename); const template = `import { IDatabase } from "../database/IDatabase";\n\nexport const up = async (db: IDatabase) => {\n // Migration logic here\n};\n\nexport const down = async (db: IDatabase) => {\n // Rollback logic here\n};\n`; fs_1.default.writeFileSync(filePath, template); return filename; } getMigrationFiles() { return fs_1.default.readdirSync(this.migrationsDir) .filter(file => file.endsWith('.ts') || file.endsWith('.js')) .sort() .map(file => ({ name: file, path: path_1.default.join(this.migrationsDir, file) })); } async getExecutedMigrations() { await this.ensureMigrationsTable(); try { const executed = await this.db.select(this.migrationsTable, {}); return executed.map((row) => row.name); } catch { return []; } } async getPendingMigrations() { const all = this.getMigrationFiles(); const executed = await this.getExecutedMigrations(); return all.filter(m => !executed.includes(m.name)); } async runMigration(migrationFile, direction = 'up') { try { const migration = require(path_1.default.resolve(migrationFile.path)); if (typeof migration[direction] !== 'function') throw new Error(`Migration ${migrationFile.name} has no ${direction} method`); await migration[direction](this.db); if (direction === 'up') await this.db.insert(this.migrationsTable, { name: migrationFile.name }); else await this.db.delete(this.migrationsTable, { name: migrationFile.name }); return true; } catch (error) { console.error(`Migration ${migrationFile.name} error:`, error); throw error; } } async migrate() { const pending = await this.getPendingMigrations(); for (const m of pending) await this.runMigration(m, 'up'); } async rollback(steps = 1) { const executed = await this.getExecutedMigrations(); const all = this.getMigrationFiles(); const toRollback = executed.slice(-steps).reverse().map(name => all.find(m => m.name === name)).filter((m) => !!m); for (const m of toRollback) await this.runMigration(m, 'down'); } } exports.MigrationManager = MigrationManager; exports.default = MigrationManager;