from __future__ import annotations import os import sys from logging.config import fileConfig from pathlib import Path from alembic import context from sqlalchemy import engine_from_config, pool from sqlalchemy.engine.url import make_url config = context.config if config.config_file_name is not None: fileConfig(config.config_file_name) BACKEND_DIR = Path(__file__).resolve().parents[1] if str(BACKEND_DIR) not in sys.path: sys.path.insert(0, str(BACKEND_DIR)) target_metadata = None def _get_database_url() -> str: url = (os.environ.get("DATABASE_URL") or config.get_main_option("sqlalchemy.url") or "").strip() if not url: raise RuntimeError("DATABASE_URL (or sqlalchemy.url) is required") return url.replace("+aiosqlite", "") def _ensure_sqlite_dir(url: str) -> None: parsed = make_url(url) if parsed.get_backend_name() != "sqlite": return db_path = parsed.database if not db_path or db_path == ":memory:": return Path(db_path).expanduser().resolve().parent.mkdir(parents=True, exist_ok=True) def run_migrations_offline() -> None: url = _get_database_url() _ensure_sqlite_dir(url) context.configure( url=url, target_metadata=target_metadata, literal_binds=True, dialect_opts={"paramstyle": "named"}, render_as_batch=url.startswith("sqlite"), ) with context.begin_transaction(): context.run_migrations() def run_migrations_online() -> None: url = _get_database_url() _ensure_sqlite_dir(url) connectable = engine_from_config( config.get_section(config.config_ini_section, {}), prefix="sqlalchemy.", url=url, poolclass=pool.NullPool, ) with connectable.connect() as connection: context.configure( connection=connection, target_metadata=target_metadata, render_as_batch=url.startswith("sqlite"), ) with context.begin_transaction(): context.run_migrations() if context.is_offline_mode(): run_migrations_offline() else: run_migrations_online()