""" Alembic migration environment configuration. Uses synchronous psycopg2 driver for migrations while the application uses asyncpg at runtime. This is the standard pattern for Alembic with async SQLAlchemy applications. """ from logging.config import fileConfig from sqlalchemy import create_engine, pool from sqlalchemy.engine import Connection from alembic import context # Import Base and all models to ensure metadata is complete from app.database.session import Base from app.models.db_models import ( # noqa: F401 Game, GameCardsetLink, GameSession, Lineup, Play, Roll, RosterLink, ) # Load settings for database URL from app.config import get_settings # Alembic Config object - provides access to the .ini file values config = context.config # Get database URL from settings and convert for sync driver (psycopg2) settings = get_settings() # Replace asyncpg with psycopg2 for synchronous migrations sync_database_url = settings.database_url.replace("+asyncpg", "+psycopg2") config.set_main_option("sqlalchemy.url", sync_database_url) # Interpret the config file for Python logging if config.config_file_name is not None: fileConfig(config.config_file_name) # Target metadata for 'autogenerate' support target_metadata = Base.metadata def run_migrations_offline() -> None: """ Run migrations in 'offline' mode. This configures the context with just a URL and not an Engine, generating SQL scripts without connecting to the database. """ url = config.get_main_option("sqlalchemy.url") context.configure( url=url, target_metadata=target_metadata, literal_binds=True, dialect_opts={"paramstyle": "named"}, compare_type=True, # Detect column type changes compare_server_default=True, # Detect server_default changes ) with context.begin_transaction(): context.run_migrations() def do_run_migrations(connection: Connection) -> None: """Execute migrations using the provided connection.""" context.configure( connection=connection, target_metadata=target_metadata, compare_type=True, compare_server_default=True, ) with context.begin_transaction(): context.run_migrations() def run_migrations_online() -> None: """ Run migrations in 'online' mode. Creates a synchronous engine and associates a connection with the context. """ connectable = create_engine( config.get_main_option("sqlalchemy.url"), poolclass=pool.NullPool, ) with connectable.connect() as connection: do_run_migrations(connection) connectable.dispose() if context.is_offline_mode(): run_migrations_offline() else: run_migrations_online()