Fix FK violations when pruning stale routes
Some checks failed
CI / backend-tests (push) Successful in 26s
CI / frontend-tests (push) Successful in 27s
CI / e2e-tests (push) Has been cancelled

Bulk delete bypasses ORM-level cascades, so manually delete
route_encounters, nullify boss_battle.after_route_id, and skip
routes referenced by user encounters before deleting stale routes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-21 17:50:54 +01:00
parent 4f0f881736
commit 3b63285bd1

View File

@@ -1,11 +1,12 @@
"""Database upsert helpers for seed data.""" """Database upsert helpers for seed data."""
from sqlalchemy import delete, select from sqlalchemy import delete, select, update
from sqlalchemy.dialects.postgresql import insert from sqlalchemy.dialects.postgresql import insert
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from app.models.boss_battle import BossBattle from app.models.boss_battle import BossBattle
from app.models.boss_pokemon import BossPokemon from app.models.boss_pokemon import BossPokemon
from app.models.encounter import Encounter
from app.models.evolution import Evolution from app.models.evolution import Evolution
from app.models.game import Game from app.models.game import Game
from app.models.pokemon import Pokemon from app.models.pokemon import Pokemon
@@ -195,17 +196,33 @@ async def upsert_routes(
for child in route.get("children", []): for child in route.get("children", []):
seed_names.add(child["name"]) seed_names.add(child["name"])
pruned = await session.execute( # Find stale route IDs, excluding routes with user encounters
delete(Route) in_use_subq = select(Encounter.route_id).distinct().subquery()
.where( stale_route_ids_result = await session.execute(
select(Route.id).where(
Route.version_group_id == version_group_id, Route.version_group_id == version_group_id,
Route.name.not_in(seed_names), Route.name.not_in(seed_names),
Route.id.not_in(select(in_use_subq)),
) )
.returning(Route.id)
) )
pruned_count = len(pruned.all()) stale_route_ids = [row.id for row in stale_route_ids_result]
if pruned_count:
print(f" Pruned {pruned_count} stale route(s)") if stale_route_ids:
# Delete encounters referencing stale routes (no DB-level cascade)
await session.execute(
delete(RouteEncounter).where(
RouteEncounter.route_id.in_(stale_route_ids)
)
)
# Nullify boss battle references to stale routes
await session.execute(
update(BossBattle)
.where(BossBattle.after_route_id.in_(stale_route_ids))
.values(after_route_id=None)
)
# Now safe to delete the routes
await session.execute(delete(Route).where(Route.id.in_(stale_route_ids)))
print(f" Pruned {len(stale_route_ids)} stale route(s)")
await session.flush() await session.flush()