from fastapi import APIRouter, Depends, Query from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession from orrery_search.db import get_db from orrery_search.models.document import Document from orrery_search.schemas.search import ( SearchResponse, SearchResult, SectionCount, SectionsResponse, ) from orrery_search.services.search import search_documents router = APIRouter() @router.get("", response_model=SearchResponse) async def search( q: str = Query(..., min_length=1, max_length=500), content_type: str | None = Query(None, description="Filter by content type"), section: str | None = Query( None, max_length=200, description="Section prefix filter" ), limit: int = Query(10, ge=1, le=50), mode: str = Query("hybrid", pattern="^(hybrid|semantic|text)$"), db: AsyncSession = Depends(get_db), ): """Search pg_orrery documentation using semantic and/or text matching.""" output = await search_documents( q=q, db=db, mode=mode, content_type=content_type, section=section, limit=limit, ) return SearchResponse( query=output.query, results=[ SearchResult( title=r.title, slug=r.slug, section=r.section, content_type=r.content_type, description=r.description, snippet=r.snippet, url=r.url, score=r.score, source=r.source, ) for r in output.results ], count=output.count, mode=output.mode, ) @router.get("/sections", response_model=SectionsResponse) async def list_sections( db: AsyncSession = Depends(get_db), ): """List all sections with document counts for the filter UI.""" stmt = ( select(Document.section, func.count(Document.id).label("count")) .group_by(Document.section) .order_by(Document.section) ) result = await db.execute(stmt) sections = [ SectionCount(section=row[0], count=row[1]) for row in result if row[0] ] return SectionsResponse(sections=sections)