#!/usr/bin/env ts-node import * as debugCtor from "debug"; import * as fs from "fs"; import * as path from "path"; import * as pgPromise from "pg-promise"; import {main} from "@wealthbar/mainjs"; const debug = debugCtor("db:migration"); const pgPromiseOptions = { query: (e) => { debug( "QUERY: ", e.query, ); if (e.params) { debug( "PARAMS:", e.params, ); } }, }; const pgp = pgPromise(pgPromiseOptions); const databaseUrlDdl = process.env.DATABASE_URL_DDL; main(async () => { if (!databaseUrlDdl) { console.log("DATABASE_URL_DDL environment variable must be set."); process.exit(-1); } else { const db = pgp(databaseUrlDdl); await doMigrations(db, fs, path); } }); async function doMigrations(db, fs, path) { await db.tx(async (db) => { await db.none(` CREATE TABLE IF NOT EXISTS data._data_migrations ( id VARCHAR NOT NULL PRIMARY KEY, applied_at TIMESTAMPTZ NOT NULL DEFAULT now() ); `); const baseDataMigrationsDir = "./data/migrations/"; const migrationsPresent = fs.readdirSync(baseDataMigrationsDir).filter((filename) => filename.endsWith(".sql")); if (migrationsPresent.length===0) { return; } const notApplied = await db.any( `SELECT x.id FROM unnest(ARRAY[$(migrationsPresent:csv)]) x(id) LEFT OUTER JOIN data._data_migrations m ON x.id=m.id WHERE m.id IS NULL` , { migrationsPresent, }, ); for (const {id} of notApplied) { const contents = fs.readFileSync(path.join(baseDataMigrationsDir, id), "utf-8"); try { await db.none(contents); } catch (e) { console.log(`${id} not applied do to error: ${e}`); continue; } await db.none(`INSERT INTO data._data_migrations VALUES ($(id))`, {id}); } if (process.env.DRY_RUN !== undefined) { throw new Error("Rollback"); } }); }