diff --git a/backend/src/app/seeds/loader.py b/backend/src/app/seeds/loader.py index efa1730..4b47db9 100644 --- a/backend/src/app/seeds/loader.py +++ b/backend/src/app/seeds/loader.py @@ -1,11 +1,12 @@ """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.ext.asyncio import AsyncSession from app.models.boss_battle import BossBattle from app.models.boss_pokemon import BossPokemon +from app.models.encounter import Encounter from app.models.evolution import Evolution from app.models.game import Game from app.models.pokemon import Pokemon @@ -195,17 +196,33 @@ async def upsert_routes( for child in route.get("children", []): seed_names.add(child["name"]) - pruned = await session.execute( - delete(Route) - .where( + # Find stale route IDs, excluding routes with user encounters + in_use_subq = select(Encounter.route_id).distinct().subquery() + stale_route_ids_result = await session.execute( + select(Route.id).where( Route.version_group_id == version_group_id, Route.name.not_in(seed_names), + Route.id.not_in(select(in_use_subq)), ) - .returning(Route.id) ) - pruned_count = len(pruned.all()) - if pruned_count: - print(f" Pruned {pruned_count} stale route(s)") + stale_route_ids = [row.id for row in stale_route_ids_result] + + 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()