Add bulk import for evolutions, routes, and bosses
Add three new bulk import endpoints that accept the same JSON format as
their corresponding export endpoints, enabling round-trip compatibility:
- POST /evolutions/bulk-import (upsert by from/to pokemon pair)
- POST /games/{id}/routes/bulk-import (reuses seed loader for hierarchy)
- POST /games/{id}/bosses/bulk-import (reuses seed loader with team data)
Generalize BulkImportModal to support all entity types with configurable
title, example, and result labels. Wire up Bulk Import buttons on
AdminEvolutions, and AdminGameDetail routes/bosses tabs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,8 @@ from app.core.database import get_session
|
||||
from app.models.evolution import Evolution
|
||||
from app.models.pokemon import Pokemon
|
||||
from app.schemas.pokemon import (
|
||||
BulkEvolutionItem,
|
||||
BulkImportResult,
|
||||
EvolutionAdminResponse,
|
||||
EvolutionCreate,
|
||||
EvolutionUpdate,
|
||||
@@ -144,3 +146,65 @@ async def delete_evolution(
|
||||
|
||||
await session.delete(evolution)
|
||||
await session.commit()
|
||||
|
||||
|
||||
@router.post("/evolutions/bulk-import", response_model=BulkImportResult)
|
||||
async def bulk_import_evolutions(
|
||||
items: list[BulkEvolutionItem],
|
||||
session: AsyncSession = Depends(get_session),
|
||||
):
|
||||
# Build pokeapi_id -> id mapping
|
||||
result = await session.execute(select(Pokemon.pokeapi_id, Pokemon.id))
|
||||
dex_to_id = {row.pokeapi_id: row.id for row in result}
|
||||
|
||||
created = 0
|
||||
updated = 0
|
||||
errors: list[str] = []
|
||||
|
||||
for item in items:
|
||||
from_id = dex_to_id.get(item.from_pokeapi_id)
|
||||
to_id = dex_to_id.get(item.to_pokeapi_id)
|
||||
|
||||
if from_id is None:
|
||||
errors.append(f"Pokemon with pokeapi_id {item.from_pokeapi_id} not found")
|
||||
continue
|
||||
if to_id is None:
|
||||
errors.append(f"Pokemon with pokeapi_id {item.to_pokeapi_id} not found")
|
||||
continue
|
||||
|
||||
try:
|
||||
# Check if evolution already exists
|
||||
existing = await session.execute(
|
||||
select(Evolution).where(
|
||||
Evolution.from_pokemon_id == from_id,
|
||||
Evolution.to_pokemon_id == to_id,
|
||||
)
|
||||
)
|
||||
evolution = existing.scalar_one_or_none()
|
||||
|
||||
if evolution is not None:
|
||||
evolution.trigger = item.trigger
|
||||
evolution.min_level = item.min_level
|
||||
evolution.item = item.item
|
||||
evolution.held_item = item.held_item
|
||||
evolution.condition = item.condition
|
||||
evolution.region = item.region
|
||||
updated += 1
|
||||
else:
|
||||
evolution = Evolution(
|
||||
from_pokemon_id=from_id,
|
||||
to_pokemon_id=to_id,
|
||||
trigger=item.trigger,
|
||||
min_level=item.min_level,
|
||||
item=item.item,
|
||||
held_item=item.held_item,
|
||||
condition=item.condition,
|
||||
region=item.region,
|
||||
)
|
||||
session.add(evolution)
|
||||
created += 1
|
||||
except Exception as e:
|
||||
errors.append(f"Evolution {item.from_pokeapi_id} -> {item.to_pokeapi_id}: {e}")
|
||||
|
||||
await session.commit()
|
||||
return BulkImportResult(created=created, updated=updated, errors=errors)
|
||||
|
||||
Reference in New Issue
Block a user