"""Retirement-goal CRUD nested under a scenario.""" from __future__ import annotations from fastapi import APIRouter, Depends, HTTPException from sqlalchemy import delete, select from sqlalchemy.ext.asyncio import AsyncSession from fire_planner.api.dependencies import get_session from fire_planner.api.schemas import GoalCreate, GoalOut from fire_planner.db import RetirementGoal, Scenario router = APIRouter(tags=["goals"]) @router.get( "/scenarios/{scenario_id}/goals", response_model=list[GoalOut], ) async def list_goals( scenario_id: int, session: AsyncSession = Depends(get_session), ) -> list[RetirementGoal]: scen = await session.get(Scenario, scenario_id) if scen is None: raise HTTPException(status_code=404, detail="Scenario not found") rows = (await session.execute( select(RetirementGoal).where(RetirementGoal.scenario_id == scenario_id).order_by( RetirementGoal.id))).scalars().all() return list(rows) @router.post( "/scenarios/{scenario_id}/goals", response_model=GoalOut, status_code=201, ) async def create_goal( scenario_id: int, payload: GoalCreate, session: AsyncSession = Depends(get_session), ) -> RetirementGoal: scen = await session.get(Scenario, scenario_id) if scen is None: raise HTTPException(status_code=404, detail="Scenario not found") goal = RetirementGoal(scenario_id=scenario_id, **payload.model_dump()) session.add(goal) await session.commit() await session.refresh(goal) return goal @router.delete( "/goals/{goal_id}", status_code=204, response_model=None, ) async def delete_goal( goal_id: int, session: AsyncSession = Depends(get_session), ) -> None: goal = await session.get(RetirementGoal, goal_id) if goal is None: raise HTTPException(status_code=404, detail="Goal not found") await session.execute(delete(RetirementGoal).where(RetirementGoal.id == goal_id)) await session.commit()