Fix FK violations when pruning stale routes
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:
@@ -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()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user