"""Alembic env — async engine, target metadata from core.db.models. URL comes from `DATABASE_URL` (via core.config.Settings), overriding the placeholder in alembic.ini. Importing `contract_check.core.db.models` populates `Base.metadata`; autogenerate is used only to draft, migrations are committed hand-written (docs/ARCHITECTURE.md §7). """ from __future__ import annotations import asyncio import sys from logging.config import fileConfig from pathlib import Path from alembic import context from sqlalchemy import pool from sqlalchemy.engine import Connection from sqlalchemy.ext.asyncio import create_async_engine # ensure src/ is importable when running alembic from the repo root sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src")) import contract_check.core.db.models # noqa: E402,F401 — populate Base.metadata from contract_check.core.config import get_settings # noqa: E402 from contract_check.core.db.models import Base # noqa: E402 config = context.config if config.config_file_name is not None: fileConfig(config.config_file_name) target_metadata = Base.metadata def run_migrations_offline() -> None: url = get_settings().database_url context.configure( url=url, target_metadata=target_metadata, literal_binds=True, dialect_opts={"paramstyle": "named"}, compare_type=True, ) with context.begin_transaction(): context.run_migrations() def do_run_migrations(connection: Connection) -> None: context.configure(connection=connection, target_metadata=target_metadata, compare_type=True) with context.begin_transaction(): context.run_migrations() async def run_migrations_online() -> None: connectable = create_async_engine(get_settings().database_url, poolclass=pool.NullPool) try: async with connectable.connect() as connection: await connection.run_sync(do_run_migrations) finally: await connectable.dispose() if context.is_offline_mode(): run_migrations_offline() else: asyncio.run(run_migrations_online())