feat(dependencies): update database engine dependencies to support async operations

This commit is contained in:
2026-07-24 11:38:51 -04:00
parent 9f126fedc7
commit e510c94b95
5 changed files with 46 additions and 19 deletions
-7
View File
@@ -6,7 +6,6 @@ from typing import Annotated
import httpx
from fastapi import Depends, Request
from sqlalchemy.ext.asyncio import AsyncEngine
from python.ebook_search.config import EbookSearchConfig
@@ -16,16 +15,10 @@ def get_config(request: Request) -> EbookSearchConfig:
return request.app.state.config
def get_engine(request: Request) -> AsyncEngine:
"""Get the database engine from app state."""
return request.app.state.engine
def get_http_client(request: Request) -> httpx.AsyncClient:
"""Get the shared LLM HTTP client from app state."""
return request.app.state.http_client
AppConfig = Annotated[EbookSearchConfig, Depends(get_config)]
AppEngine = Annotated[AsyncEngine, Depends(get_engine)]
AppHttpClient = Annotated[httpx.AsyncClient, Depends(get_http_client)]
+9 -7
View File
@@ -10,7 +10,6 @@ from fastapi.responses import HTMLResponse
from python.ebook_search.api.bm25_tasks import schedule_bm25_refresh
from python.ebook_search.api.dependencies import ( # noqa: TC001 FastAPI resolves these annotated dependencies at runtime
AppConfig,
AppEngine,
AppHttpClient,
)
from python.ebook_search.api.web import error_response, templates
@@ -19,7 +18,10 @@ from python.ebook_search.ingest import ingest_configured_paths
from python.ebook_search.protected_phrases.generate_ngrams import generate_candidate_phrases_for_books
from python.ebook_search.protected_phrases.judge_ngrams import judge_candidate_phrases_for_books
from python.ebook_search.protected_phrases.store import book_ids_pending_first_judgment, corpus_phrase_stats
from python.fastapi_tools import AsyncDbSession # noqa: TC001 FastAPI resolves this annotated dependency at runtime
from python.fastapi_tools import ( # noqa: TC001 FastAPI resolves these annotated dependencies at runtime
AppAsyncEngine,
AsyncDbSession,
)
logger = logging.getLogger(__name__)
@@ -59,7 +61,7 @@ async def scan_library(request: Request, config: AppConfig, session: AsyncDbSess
@router.post("/phrases/generate-all", response_class=HTMLResponse)
async def generate_all_phrases(request: Request, config: AppConfig, engine: AppEngine) -> HTMLResponse:
async def generate_all_phrases(request: Request, config: AppConfig, engine: AppAsyncEngine) -> HTMLResponse:
"""Regenerate candidate phrases for every indexed book without LLM judging."""
try:
result = await generate_candidate_phrases_for_books(engine, config)
@@ -83,7 +85,7 @@ async def generate_all_phrases(request: Request, config: AppConfig, engine: AppE
@router.post("/phrases/judge-all", response_class=HTMLResponse)
async def judge_all_phrases(request: Request, engine: AppEngine, config: AppConfig) -> HTMLResponse:
async def judge_all_phrases(request: Request, engine: AppAsyncEngine, config: AppConfig) -> HTMLResponse:
"""Judge unjudged candidate phrases across every indexed book."""
return await run_phrase_judgment(request, engine, config, source_ids=None)
@@ -91,7 +93,7 @@ async def judge_all_phrases(request: Request, engine: AppEngine, config: AppConf
@router.post("/phrases/judge-missing", response_class=HTMLResponse)
async def judge_missing_phrases(
request: Request,
engine: AppEngine,
engine: AppAsyncEngine,
config: AppConfig,
session: AsyncDbSession,
) -> HTMLResponse:
@@ -108,7 +110,7 @@ async def judge_missing_phrases(
async def run_phrase_judgment(
request: Request,
engine: AppEngine,
engine: AppAsyncEngine,
config: AppConfig,
*,
source_ids: list[int] | None,
@@ -117,7 +119,7 @@ async def run_phrase_judgment(
Args:
request (Request): Current request, for template rendering.
engine (AppEngine): Engine used to open per-book judging sessions.
engine (AppAsyncEngine): Engine used to open per-book judging sessions.
config (AppConfig): Runtime phrase-tuning settings.
source_ids (list[int] | None): Books to judge; ``None`` judges every indexed book.
+2 -2
View File
@@ -13,7 +13,6 @@ from fastapi.responses import HTMLResponse
from python.ebook_search.answer import answer_query
from python.ebook_search.api.dependencies import ( # noqa: TC001 FastAPI resolves these annotated dependencies at runtime
AppConfig,
AppEngine,
AppHttpClient,
)
from python.ebook_search.api.web import error_response, templates
@@ -25,6 +24,7 @@ from python.ebook_search.guardrails import (
)
from python.ebook_search.search import SearchResponse, search_ebooks
from python.ebook_search.timing import runtime_step_from_start
from python.fastapi_tools import AppAsyncEngine # noqa: TC001 FastAPI resolves this annotated dependency at runtime
if TYPE_CHECKING:
import httpx
@@ -76,7 +76,7 @@ async def build_answer(
async def search(
request: Request,
config: AppConfig,
engine: AppEngine,
engine: AppAsyncEngine,
client: AppHttpClient,
query: Annotated[str, Form()],
*,
+21 -2
View File
@@ -1,6 +1,25 @@
"""Reusable FastAPI tools."""
from python.fastapi_tools.db import AsyncDbSession, DbSession, get_async_db, get_db
from python.fastapi_tools.db import (
AppAsyncEngine,
AppEngine,
AsyncDbSession,
DbSession,
get_async_db,
get_async_engine,
get_db,
get_engine,
)
from python.fastapi_tools.zstd_middleware import ZstdMiddleware
__all__ = ["AsyncDbSession", "DbSession", "ZstdMiddleware", "get_async_db", "get_db"]
__all__ = [
"AppAsyncEngine",
"AppEngine",
"AsyncDbSession",
"DbSession",
"ZstdMiddleware",
"get_async_db",
"get_async_engine",
"get_db",
"get_engine",
]
+14 -1
View File
@@ -5,13 +5,24 @@ from __future__ import annotations
from typing import TYPE_CHECKING, Annotated
from fastapi import Depends, Request
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.engine import Engine
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession
from sqlalchemy.orm import Session
if TYPE_CHECKING:
from collections.abc import AsyncIterator, Iterator
def get_engine(request: Request) -> Engine:
"""Get a synchronous database engine from app state."""
return request.app.state.engine
def get_async_engine(request: Request) -> AsyncEngine:
"""Get an asynchronous database engine from app state."""
return request.app.state.engine
def get_db(request: Request) -> Iterator[Session]:
"""Get database session from app state."""
with Session(request.app.state.engine) as session:
@@ -28,5 +39,7 @@ async def get_async_db(request: Request) -> AsyncIterator[AsyncSession]:
yield session
AppEngine = Annotated[Engine, Depends(get_engine)]
AppAsyncEngine = Annotated[AsyncEngine, Depends(get_async_engine)]
DbSession = Annotated[Session, Depends(get_db)]
AsyncDbSession = Annotated[AsyncSession, Depends(get_async_db)]