@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
JavaScript
;
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;