100 lines
3.0 KiB
Python
100 lines
3.0 KiB
Python
|
|
from fastapi import APIRouter, Depends, HTTPException, Response
|
||
|
|
from sqlalchemy import select
|
||
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||
|
|
from sqlalchemy.orm import joinedload, selectinload
|
||
|
|
|
||
|
|
from app.core.database import get_session
|
||
|
|
from app.models.encounter import Encounter
|
||
|
|
from app.models.game import Game
|
||
|
|
from app.models.nuzlocke_run import NuzlockeRun
|
||
|
|
from app.schemas.run import RunCreate, RunDetailResponse, RunResponse, RunUpdate
|
||
|
|
|
||
|
|
router = APIRouter()
|
||
|
|
|
||
|
|
|
||
|
|
@router.post("", response_model=RunResponse, status_code=201)
|
||
|
|
async def create_run(
|
||
|
|
data: RunCreate, session: AsyncSession = Depends(get_session)
|
||
|
|
):
|
||
|
|
# Validate game exists
|
||
|
|
game = await session.get(Game, data.game_id)
|
||
|
|
if game is None:
|
||
|
|
raise HTTPException(status_code=404, detail="Game not found")
|
||
|
|
|
||
|
|
run = NuzlockeRun(
|
||
|
|
game_id=data.game_id,
|
||
|
|
name=data.name,
|
||
|
|
status="active",
|
||
|
|
rules=data.rules,
|
||
|
|
)
|
||
|
|
session.add(run)
|
||
|
|
await session.commit()
|
||
|
|
await session.refresh(run)
|
||
|
|
return run
|
||
|
|
|
||
|
|
|
||
|
|
@router.get("", response_model=list[RunResponse])
|
||
|
|
async def list_runs(session: AsyncSession = Depends(get_session)):
|
||
|
|
result = await session.execute(
|
||
|
|
select(NuzlockeRun).order_by(NuzlockeRun.started_at.desc())
|
||
|
|
)
|
||
|
|
return result.scalars().all()
|
||
|
|
|
||
|
|
|
||
|
|
@router.get("/{run_id}", response_model=RunDetailResponse)
|
||
|
|
async def get_run(run_id: int, session: AsyncSession = Depends(get_session)):
|
||
|
|
result = await session.execute(
|
||
|
|
select(NuzlockeRun)
|
||
|
|
.where(NuzlockeRun.id == run_id)
|
||
|
|
.options(
|
||
|
|
joinedload(NuzlockeRun.game),
|
||
|
|
selectinload(NuzlockeRun.encounters)
|
||
|
|
.joinedload(Encounter.pokemon),
|
||
|
|
selectinload(NuzlockeRun.encounters)
|
||
|
|
.joinedload(Encounter.route),
|
||
|
|
)
|
||
|
|
)
|
||
|
|
run = result.scalar_one_or_none()
|
||
|
|
if run is None:
|
||
|
|
raise HTTPException(status_code=404, detail="Run not found")
|
||
|
|
return run
|
||
|
|
|
||
|
|
|
||
|
|
@router.patch("/{run_id}", response_model=RunResponse)
|
||
|
|
async def update_run(
|
||
|
|
run_id: int,
|
||
|
|
data: RunUpdate,
|
||
|
|
session: AsyncSession = Depends(get_session),
|
||
|
|
):
|
||
|
|
run = await session.get(NuzlockeRun, run_id)
|
||
|
|
if run is None:
|
||
|
|
raise HTTPException(status_code=404, detail="Run not found")
|
||
|
|
|
||
|
|
update_data = data.model_dump(exclude_unset=True)
|
||
|
|
for field, value in update_data.items():
|
||
|
|
setattr(run, field, value)
|
||
|
|
|
||
|
|
await session.commit()
|
||
|
|
await session.refresh(run)
|
||
|
|
return run
|
||
|
|
|
||
|
|
|
||
|
|
@router.delete("/{run_id}", status_code=204)
|
||
|
|
async def delete_run(
|
||
|
|
run_id: int, session: AsyncSession = Depends(get_session)
|
||
|
|
):
|
||
|
|
run = await session.get(NuzlockeRun, run_id)
|
||
|
|
if run is None:
|
||
|
|
raise HTTPException(status_code=404, detail="Run not found")
|
||
|
|
|
||
|
|
# Delete associated encounters first
|
||
|
|
encounters = await session.execute(
|
||
|
|
select(Encounter).where(Encounter.run_id == run_id)
|
||
|
|
)
|
||
|
|
for enc in encounters.scalars():
|
||
|
|
await session.delete(enc)
|
||
|
|
|
||
|
|
await session.delete(run)
|
||
|
|
await session.commit()
|
||
|
|
return Response(status_code=204)
|