fastapi updates
This commit is contained in:
@@ -110,6 +110,14 @@ Pool sizing, overflow, recycle, pre-ping, isolation, statement timeouts, and hea
|
||||
|
||||
See [observability and resilience](references/observability.md).
|
||||
|
||||
### Test through the production seam
|
||||
|
||||
Keep the production engine and session-factory construction path intact in tests. Select a dedicated PostgreSQL, local SQLite, or in-memory SQLite URL at that seam, then override the request-session dependency only for the test lifetime. Use a test-scoped outer transaction with SAVEPOINT-backed session commits when application code calls `commit()`; it exercises normal transaction behavior while cleanup remains deterministic.
|
||||
|
||||
In-memory SQLite is suitable for serial tests. For multiple simultaneous sessions, use a named shared-cache SQLite URL or a temporary file, and retain PostgreSQL integration coverage for PostgreSQL-specific behavior.
|
||||
|
||||
See [database testing and fixture data](references/testing.md).
|
||||
|
||||
## Reference Map
|
||||
|
||||
| Concept | Reference |
|
||||
@@ -123,6 +131,7 @@ See [observability and resilience](references/observability.md).
|
||||
| Observability and resilience | [Observability reference](references/observability.md) |
|
||||
| SQLModel-first modeling | [SQLModel integration reference](references/sqlmodel.md) |
|
||||
| CRUD repository and standalone functions | [Basic CRUD reference](references/crud.md) |
|
||||
| Test database selection and fixture data | [Database testing reference](references/testing.md) |
|
||||
|
||||
## Canonical Composition Pattern
|
||||
|
||||
@@ -133,7 +142,8 @@ from contextlib import AsyncExitStack, asynccontextmanager
|
||||
from collections.abc import AsyncIterator
|
||||
|
||||
from fastapi import FastAPI
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
|
||||
from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI) -> AsyncIterator[None]:
|
||||
@@ -141,7 +151,11 @@ async def lifespan(app: FastAPI) -> AsyncIterator[None]:
|
||||
engine = create_async_engine(settings.database_url)
|
||||
stack.push_async_callback(engine.dispose)
|
||||
|
||||
session_factory = async_sessionmaker(engine, expire_on_commit=False)
|
||||
session_factory = async_sessionmaker(
|
||||
engine,
|
||||
class_=AsyncSession,
|
||||
expire_on_commit=False,
|
||||
)
|
||||
app.state.session_factory = session_factory
|
||||
yield
|
||||
|
||||
@@ -173,6 +187,7 @@ When reviewing code, verify:
|
||||
- Relationship and deferred-column access cannot surprise the event loop with implicit I/O.
|
||||
- Pool and timeout settings are justified by deployment behavior.
|
||||
- Tests exercise rollback, cleanup, concurrency, and lifespan behavior where relevant.
|
||||
- Tests use a dedicated database target and preserve production session mechanics.
|
||||
|
||||
## Anti-Patterns to Flag
|
||||
|
||||
|
||||
Reference in New Issue
Block a user