Spaces:
Running on Zero
Running on Zero
File size: 1,888 Bytes
440bb5b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | #!/usr/bin/env python3
# SPDX-FileCopyrightText: 2026 Shamiur Rashid Sunny
# SPDX-License-Identifier: AGPL-3.0-only
"""Idempotent migration runner for Neon Postgres."""
import asyncio
import os
import sys
from pathlib import Path
import asyncpg
from dotenv import load_dotenv
MIGRATIONS_DIR = Path(__file__).parent.parent / "migrations"
async def run_migrations():
load_dotenv()
url = os.getenv("NEON_DATABASE_URL")
if not url:
print("ERROR: NEON_DATABASE_URL not set")
return 1
print("-> Connecting to Neon...")
conn = await asyncpg.connect(url, statement_cache_size=0)
try:
await conn.execute("""
CREATE TABLE IF NOT EXISTS schema_migrations (
version TEXT PRIMARY KEY,
applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
""")
applied = {
r["version"] for r in await conn.fetch("SELECT version FROM schema_migrations")
}
print(f"-> Already applied: {len(applied)} migration(s)")
files = sorted(MIGRATIONS_DIR.glob("*.sql"))
if not files:
print("-> No migration files found")
return 0
for f in files:
version = f.stem
if version in applied:
print(f" [skip] {version} (already applied)")
continue
print(f" -> Applying {version}...")
sql = f.read_text()
async with conn.transaction():
await conn.execute(sql)
await conn.execute(
"INSERT INTO schema_migrations (version) VALUES ($1)", version
)
print(f" [ok] {version} applied")
print("[done] All migrations complete")
return 0
finally:
await conn.close()
if __name__ == "__main__":
sys.exit(asyncio.run(run_migrations()))
|