import { AppDataSource } from "./ormconfig.js";
export class MigrationManager {
constructor() {
this.dataSource = AppDataSource;
}
/**
* Executa todas as migrations pendentes
*/
async runMigrations() {
try {
console.log("🔄 Executando migrations...");
// Verificar se a tabela de migrations existe
await this.createMigrationsTable();
// Executar migrations pendentes
const pendingMigrations = await this.getPendingMigrations();
for (const MigrationClass of pendingMigrations) {
const migration = new MigrationClass();
console.log(`📦 Executando migration: ${migration.name}`);
await this.runMigration(migration);
}
console.log("✅ Todas as migrations foram executadas com sucesso!");
} catch (error) {
console.error("❌ Erro ao executar migrations:", error);
throw error;
}
}
/**
* Cria a tabela de controle de migrations
*/
async createMigrationsTable() {
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect();
try {
await queryRunner.query(`
CREATE TABLE IF NOT EXISTS "migrations" (
"id" SERIAL PRIMARY KEY,
"name" VARCHAR(255) NOT NULL UNIQUE,
"executed_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
} finally {
await queryRunner.release();
}
}
/**
* Obtém migrations pendentes
*/
async getPendingMigrations() {
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect();
try {
// Obter migrations já executadas
const executedMigrations = await queryRunner.query(`
SELECT name FROM migrations
`);
const executedNames = executedMigrations.map((m) => m.name);
// Filtrar migrations pendentes
const allMigrations = this.dataSource.options.migrations || [];
return allMigrations.filter((MigrationClass) => {
const migration = new MigrationClass();
return !executedNames.includes(migration.name);
});
} finally {
await queryRunner.release();
}
}
/**
* Executa uma migration específica
*/
async runMigration(migration) {
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect();
try {
await queryRunner.startTransaction();
// Executar migration
await migration.up(queryRunner);
// Registrar migration como executada
await queryRunner.query(
`
INSERT INTO migrations (name) VALUES ($1)
`,
[migration.name]
);
await queryRunner.commitTransaction();
console.log(`✅ Migration ${migration.name} executada com sucesso!`);
} catch (error) {
await queryRunner.rollbackTransaction();
throw error;
} finally {
await queryRunner.release();
}
}
/**
* Reverte uma migration específica
*/
async revertMigration(migrationName) {
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect();
try {
await queryRunner.startTransaction();
// Encontrar migration
const MigrationClass = this.dataSource.options.migrations.find((MigrationClass) => {
const migration = new MigrationClass();
return migration.name === migrationName;
});
if (!MigrationClass) {
throw new Error(`Migration ${migrationName} não encontrada`);
}
const migration = new MigrationClass();
// Executar rollback
await migration.down(queryRunner);
// Remover registro da migration
await queryRunner.query(
`
DELETE FROM migrations WHERE name = $1
`,
[migrationName]
);
await queryRunner.commitTransaction();
console.log(`✅ Migration ${migrationName} revertida com sucesso!`);
} catch (error) {
await queryRunner.rollbackTransaction();
throw error;
} finally {
await queryRunner.release();
}
}
}