debate/backend/alembic/env.py
Mikkel Georgsen c261664784 feat(01-02): configure Alembic and create Build model
- Configure Alembic for async migrations with SQLAlchemy 2.0
- Create Build model with UUID primary key, config_hash, status enum
- Add indexes on status (queue queries) and config_hash (cache lookups)
- Generate and apply initial migration creating builds table

Build model fields: id, config_hash, status, iso_path, error_message,
build_log, started_at, completed_at, created_at, updated_at.
2026-01-25 20:11:55 +00:00

80 lines
2.3 KiB
Python

"""Alembic migration environment configuration for async SQLAlchemy."""
import asyncio
import sys
from logging.config import fileConfig
from pathlib import Path
from alembic import context
from sqlalchemy import pool
from sqlalchemy.ext.asyncio import async_engine_from_config
# Add parent directory to path for imports
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from backend.app.core.config import settings # noqa: E402
from backend.app.db.base import Base # noqa: E402
# Import all models for autogenerate to discover them
from backend.app.db.models import build # noqa: E402, F401
# Alembic Config object
config = context.config
# Set sqlalchemy.url from application settings
config.set_main_option("sqlalchemy.url", settings.database_url)
# Interpret the config file for Python logging
if config.config_file_name is not None:
fileConfig(config.config_file_name)
# SQLAlchemy 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,
skipping Engine creation so no DBAPI is needed.
"""
url = config.get_main_option("sqlalchemy.url")
context.configure(
url=url,
target_metadata=target_metadata,
literal_binds=True,
dialect_opts={"paramstyle": "named"},
)
with context.begin_transaction():
context.run_migrations()
def do_run_migrations(connection) -> None:
"""Run migrations with the given connection."""
context.configure(connection=connection, target_metadata=target_metadata)
with context.begin_transaction():
context.run_migrations()
async def run_migrations_online() -> None:
"""Run migrations in 'online' mode with async engine.
Creates an async Engine and associates a connection with the context.
"""
connectable = async_engine_from_config(
config.get_section(config.config_ini_section, {}),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
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())