import fs from "node:fs"; import { readdir } from "node:fs/promises"; import path from "node:path"; import dbClient from "./index.js"; const __dirname = import.meta.dirname; const createMigrationTable = () => { return dbClient.query(` CREATE TABLE IF NOT EXISTS migrations ( id VARCHAR(255) PRIMARY KEY, name VARCHAR(255), executed_at TIMESTAMP ) `); } const getMigrationsFiles = () => { try { return readdir(path.resolve(__dirname, "./migrations")); } catch(err) { return new Error("[Migration] getMigrations err: ", err); } }; const runMigrations = async () => { try { // Create migration table if needed await createMigrationTable(); const migrationFiles = await getMigrationsFiles(); const migrationsDb = await dbClient.query("SELECT name FROM migrations WHERE executed_at IS NOT NULL"); const migrationsToRun = migrationFiles.filter(m => !migrationsDb.rows.map(m => m.name).includes(m)); console.log("[Migration] migrations to run: ", migrationsToRun); for (const migration of migrationsToRun) { await dbClient.query("BEGIN"); const sqlQuery = fs.readFileSync(path.resolve(__dirname, `./migrations/${migration}`), "utf-8"); try { await dbClient.query(sqlQuery); await dbClient.query({ text: "INSERT INTO migrations(id, name, executed_at) VALUES($1, $2, $3)", values: [migration.slice(0, -4), migration, new Date().toISOString().slice(0, 19).replace('T', ' ')] }); await dbClient.query("COMMIT"); } catch(err) { console.log(err); await dbClient.query("ROLLBACK"); } } console.log("[Migration]: SUCCESS"); } catch (err) { console.error("Error", err); process.exit(1); } }; // Run this from CLI if (import.meta.main) { console.log("Run migrations"); runMigrations() .then(() => process.exit(0)) .catch(() => process.exit(1)); }