Spaces:
Sleeping
Sleeping
| from datetime import datetime, timezone | |
| from math import ceil | |
| from fastapi import APIRouter, Depends, Query | |
| from fastapi.responses import JSONResponse | |
| from sqlalchemy.ext.asyncio import AsyncSession | |
| from app.schemas.schemas import Definition, DefinitionPage | |
| from app.database.db import get_async_session | |
| import logging | |
| from app.services.definitions import definition_service | |
| log = logging.getLogger(__name__) | |
| router = APIRouter(prefix="/api", tags=["definitions"]) | |
| MAX_PAGE_SIZE = 100 | |
| DEFAULT_PAGE_SIZE = 24 | |
| MAX_EXPORT_ROWS = 50_000 | |
| async def list_definitions_paginated( | |
| page: int = Query(1, ge=1), | |
| page_size: int = Query(DEFAULT_PAGE_SIZE, ge=1, le=MAX_PAGE_SIZE), | |
| q: str | None = Query( | |
| None, | |
| description="Search term, definition text, or committee description (ilike)", | |
| ), | |
| letter_tag: str | None = Query( | |
| None, | |
| description="Filter by letter tag / designation (ilike)", | |
| ), | |
| session: AsyncSession = Depends(get_async_session), | |
| ): | |
| total = await definition_service.count_definitions(session, q, letter_tag) | |
| total_pages = ceil(total / page_size) if total > 0 else 0 | |
| rows = await definition_service.get_definitions_page( | |
| session, page, page_size, q, letter_tag | |
| ) | |
| items = [ | |
| Definition.model_validate(definition_service.row_to_dict(d, c)) | |
| for d, c in rows | |
| ] | |
| return DefinitionPage( | |
| items=items, | |
| total=total, | |
| page=page, | |
| page_size=page_size, | |
| total_pages=total_pages, | |
| ) | |
| async def export_definitions_json( | |
| q: str | None = Query(None), | |
| letter_tag: str | None = Query(None), | |
| session: AsyncSession = Depends(get_async_session), | |
| ): | |
| """ | |
| Download definitions matching the same filters as the list (cap 50k rows). | |
| Prefer this over paging through /definitions in the client for large exports. | |
| """ | |
| rows = await definition_service.get_definitions_for_export( | |
| session, q, letter_tag, max_rows=MAX_EXPORT_ROWS | |
| ) | |
| payload = { | |
| "exportedAt": datetime.now(timezone.utc).isoformat(), | |
| "count": len(rows), | |
| "maxRowsCap": MAX_EXPORT_ROWS, | |
| "filters": {"q": q, "letter_tag": letter_tag}, | |
| "definitions": [ | |
| definition_service.row_to_dict(d, c) for d, c in rows | |
| ], | |
| } | |
| return JSONResponse( | |
| content=payload, | |
| headers={ | |
| "Content-Disposition": 'attachment; filename="definitions-export.json"' | |
| }, | |
| ) | |
| async def get_definition( | |
| term: str, | |
| session: AsyncSession = Depends(get_async_session), | |
| ): | |
| definitions = await definition_service.search_definition(session, term) | |
| definitions_list = [] | |
| for definition, committee_designation in definitions: | |
| definitions_list.append( | |
| Definition.model_validate( | |
| definition_service.row_to_dict( | |
| definition, committee_designation | |
| ) | |
| ) | |
| ) | |
| return definitions_list | |