"""Alembic environment. Reads VELODROME_DATABASE_URL directly from the environment rather than importing velodrome.config.Settings — keeps a migration-only invocation from needing every other runtime env var the app requires, even though today they'd resolve to the same value. There's no more separate migration/owner role to reason about here (docs/DECISIONS.md D15): SQLite has no roles, so migrations run against the exact same file and connection the app itself uses. """ import asyncio import os from sqlalchemy.engine import Connection from sqlalchemy.ext.asyncio import async_engine_from_config from alembic import context from velodrome.models import Base config = context.config target_metadata = Base.metadata def _database_url() -> str: url = os.environ.get("VELODROME_DATABASE_URL") if not url: # Local-dev convenience only — CI and deploy/ both set this explicitly. url = "sqlite+aiosqlite:///./velodrome.db" return url def run_migrations_offline() -> None: context.configure( url=_database_url(), target_metadata=target_metadata, literal_binds=True, dialect_opts={"paramstyle": "named"}, ) with context.begin_transaction(): context.run_migrations() def _do_run_migrations(connection: Connection) -> None: context.configure(connection=connection, target_metadata=target_metadata) with context.begin_transaction(): context.run_migrations() async def run_migrations_online() -> None: configuration = config.get_section(config.config_ini_section) or {} configuration["sqlalchemy.url"] = _database_url() connectable = async_engine_from_config(configuration, prefix="sqlalchemy.") async with connectable.connect() as connection: await connection.run_sync(_do_run_migrations) await connectable.dispose() if context.is_offline_mode(): run_migrations_offline() else: asyncio.run(run_migrations_online())