munch-ease-backend/api/persons.py

100 lines
2.9 KiB
Python
Raw Normal View History

2025-10-18 05:50:43 +00:00
from __future__ import annotations
from typing import List, Optional
import aiosqlite
2025-10-18 07:21:04 +00:00
from fastapi import APIRouter, Depends, Query, Response
2025-10-18 05:50:43 +00:00
import persons
2025-10-18 06:00:01 +00:00
from common import Page
from main import get_db
2025-10-18 05:50:43 +00:00
router = APIRouter(prefix="/persons", tags=["persons"])
2025-10-18 06:00:01 +00:00
@router.get(
"",
operation_id="listPersons",
response_model=Page[persons.Person],
summary="List persons (paginated)",
responses={
200: {
"description": "A page of persons",
"content": {
"application/json": {
"example": {
"items": [
{
"id": 1,
"name": "Ada Lovelace"
}
],
"nextCursor": "2",
"prevCursor": "0",
"total": 1
}
}
},
}
},
)
2025-10-18 05:50:43 +00:00
async def list_persons(
2025-10-18 06:00:01 +00:00
q: Optional[str] = Query(
default=None,
description="Optional case-insensitive name filter (applied after page read; may be pushed to SQL in the future).",
),
cursor: Optional[str] = Query(
default=None,
description="Opaque cursor for pagination. Pass the value returned in nextCursor to fetch the next page.",
),
limit: int = Query(
50,
ge=1,
le=200,
description="Maximum number of items to return (1-200).",
),
2025-10-18 05:50:43 +00:00
conn: aiosqlite.Connection = Depends(get_db),
) -> Page[persons.Person]:
2025-10-18 06:00:01 +00:00
# v1: DB-backed pagination
last_id = None
if cursor:
try:
last_id = int(cursor)
except ValueError:
last_id = None
2025-10-18 05:50:43 +00:00
2025-10-18 06:00:01 +00:00
fetch_limit = limit + 1
paged: List[persons.Person] = []
if q:
async for p in persons.search_by_name_paged(conn, q, last_id, fetch_limit):
paged.append(p)
else:
async for p in persons.get_all_paged(conn, last_id, fetch_limit):
paged.append(p)
2025-10-18 05:50:43 +00:00
2025-10-18 06:00:01 +00:00
has_more = len(paged) > limit
items = paged[:limit]
next_cursor = str(items[-1].id) if has_more and items else None
# Compute prevCursor via DB helper
prev_cursor: Optional[str] = None
if items:
first_id = items[0].id
prev_cursor = await persons.compute_prev_cursor(conn, first_id, limit, q)
total = await (persons.count_by_name(conn, q) if q else persons.count_all(conn))
return Page(items=items, nextCursor=next_cursor, prevCursor=prev_cursor, total=total)
@router.post(
"",
operation_id="createPerson",
summary="Create a person",
2025-10-18 07:21:04 +00:00
response_model=persons.Person,
2025-10-18 06:00:01 +00:00
)
2025-10-18 05:50:43 +00:00
async def create_person(
2025-10-18 07:21:04 +00:00
person: persons.Person, response: Response, conn: aiosqlite.Connection = Depends(get_db)
2025-10-18 05:50:43 +00:00
) -> persons.Person:
2025-10-18 06:00:01 +00:00
await persons.insert_person(conn, person)
await conn.commit()
2025-10-18 07:21:04 +00:00
response.headers["Location"] = f"/api/v1/persons/{person.id}"
2025-10-18 06:00:01 +00:00
return person