62 lines
2.1 KiB
Python
62 lines
2.1 KiB
Python
|
|
"""GET /api/examples and /api/examples/summary.
|
||
|
|
|
||
|
|
`/examples` returns the raw FireExample rows (filterable by country,
|
||
|
|
fi_status, with a sane limit). `/examples/summary` is the aggregated
|
||
|
|
view the UI / simulator overlay actually wants.
|
||
|
|
"""
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from typing import Annotated
|
||
|
|
|
||
|
|
from fastapi import APIRouter, Depends, Query
|
||
|
|
from sqlalchemy import select
|
||
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||
|
|
|
||
|
|
from fire_planner.api.dependencies import get_session
|
||
|
|
from fire_planner.db import FireExample
|
||
|
|
from fire_planner.examples.models import Summary
|
||
|
|
from fire_planner.examples.service import summary_for_country
|
||
|
|
|
||
|
|
router = APIRouter(prefix="/examples", tags=["examples"])
|
||
|
|
|
||
|
|
|
||
|
|
@router.get("")
|
||
|
|
async def list_examples(
|
||
|
|
country: Annotated[str | None, Query()] = None,
|
||
|
|
fi_status: Annotated[str | None, Query()] = None,
|
||
|
|
limit: Annotated[int, Query(ge=1, le=500)] = 100,
|
||
|
|
session: AsyncSession = Depends(get_session),
|
||
|
|
) -> list[dict[str, object]]:
|
||
|
|
stmt = select(FireExample)
|
||
|
|
if country is not None:
|
||
|
|
stmt = stmt.where(FireExample.country == country)
|
||
|
|
if fi_status is not None:
|
||
|
|
stmt = stmt.where(FireExample.fi_status == fi_status)
|
||
|
|
stmt = stmt.order_by(FireExample.post_date.desc()).limit(limit)
|
||
|
|
rows = (await session.execute(stmt)).scalars().all()
|
||
|
|
return [
|
||
|
|
{
|
||
|
|
"reddit_id": r.reddit_id,
|
||
|
|
"source_sub": r.source_sub,
|
||
|
|
"post_url": r.post_url,
|
||
|
|
"post_date": r.post_date.isoformat(),
|
||
|
|
"country": r.country,
|
||
|
|
"city": r.city,
|
||
|
|
"portfolio_gbp": float(r.portfolio_gbp) if r.portfolio_gbp else None,
|
||
|
|
"annual_exp_gbp": float(r.annual_exp_gbp) if r.annual_exp_gbp else None,
|
||
|
|
"age": r.age,
|
||
|
|
"family_size": r.family_size,
|
||
|
|
"fi_status": r.fi_status,
|
||
|
|
"is_retired": r.is_retired,
|
||
|
|
}
|
||
|
|
for r in rows
|
||
|
|
]
|
||
|
|
|
||
|
|
|
||
|
|
@router.get("/summary", response_model=Summary)
|
||
|
|
async def get_summary(
|
||
|
|
country: Annotated[str, Query(min_length=2)],
|
||
|
|
session: AsyncSession = Depends(get_session),
|
||
|
|
) -> Summary:
|
||
|
|
return await summary_for_country(session, country)
|