""" run_migrations.py — fleettickets · apply SQL migrations in order. Applies migrations/*.sql (lexical order) against DATABASE_URL, tracking applied files in tickets.schema_migrations. Migrations are idempotent, so re-running is safe. Run: `python run_migrations.py`. """ from __future__ import annotations import glob import os import psycopg2 MIG_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "migrations") def main() -> None: dsn = os.environ.get("DATABASE_URL") if not dsn: raise SystemExit("DATABASE_URL is not set") conn = psycopg2.connect(dsn) conn.autocommit = False try: with conn.cursor() as cur: cur.execute("CREATE SCHEMA IF NOT EXISTS tickets") cur.execute( "CREATE TABLE IF NOT EXISTS tickets.schema_migrations " "(filename text PRIMARY KEY, applied_at timestamptz NOT NULL DEFAULT now())" ) conn.commit() cur.execute("SELECT filename FROM tickets.schema_migrations") applied = {r[0] for r in cur.fetchall()} for path in sorted(glob.glob(os.path.join(MIG_DIR, "*.sql"))): fn = os.path.basename(path) if fn in applied: print(f" skip {fn}") continue print(f" apply {fn}") with open(path, encoding="utf-8") as f: cur.execute(f.read()) cur.execute( "INSERT INTO tickets.schema_migrations (filename) VALUES (%s) " "ON CONFLICT DO NOTHING", (fn,), ) conn.commit() print("migrations up to date.") finally: conn.close() if __name__ == "__main__": main()