Files
DECNET/decnet/web/db/migrate.py
anti 372375194c refactor(db): run Alembic at boot, retire ad-hoc _migrate_* helpers
initialize() now delegates to _apply_schema(): real boots run
'alembic upgrade head' (schema owned by the migration history); tests
(DECNET_TESTING=1) keep create_all, which is faster and needs no upgrade
path. MySQL wraps the upgrade in the existing GET_LOCK advisory lock so
concurrent uvicorn workers don't race on DDL.

Deletes the three _migrate_* crimes (attackers-table legacy drop +
GeoIP backfill, TEXT->MEDIUMTEXT widening) — all now handled by the
baseline migration and the _BIG_TEXT model variants. Drops the test
file that only exercised the deleted helpers; adds tests pinning the
alembic-vs-create_all gate and guarding that every model table is in
the migration head.
2026-06-16 16:31:10 -04:00

39 lines
1.4 KiB
Python

# SPDX-License-Identifier: AGPL-3.0-or-later
"""Programmatic Alembic upgrade, run at app boot for managed databases.
Real boots run ``alembic upgrade head`` so the schema is owned by the
versioned migration history. Test/ephemeral DBs skip this and use
``SQLModel.metadata.create_all`` instead (see
:meth:`SQLModelRepository._apply_schema`) — faster, and a throwaway DB never
needs an upgrade path.
The migration scripts live inside the package (``db/migrations``), so this
works from an installed wheel without depending on the repo-root
``alembic.ini`` (that file exists only for the ``alembic`` CLI).
"""
from __future__ import annotations
from pathlib import Path
from alembic import command
from alembic.config import Config
from sqlalchemy.engine import Connection
from sqlalchemy.ext.asyncio import AsyncEngine
_MIGRATIONS_DIR = Path(__file__).resolve().parent / "migrations"
def _upgrade(connection: Connection) -> None:
# No ini file: env.py skips fileConfig and reuses this connection
# (passed via attributes) instead of building its own engine.
cfg = Config()
cfg.set_main_option("script_location", str(_MIGRATIONS_DIR))
cfg.attributes["connection"] = connection
command.upgrade(cfg, "head")
async def run_migrations(engine: AsyncEngine) -> None:
"""Upgrade ``engine``'s database to the latest revision (alembic head)."""
async with engine.begin() as conn:
await conn.run_sync(_upgrade)