fix(todos): datetime query params typés FastAPI, ORDER BY déterministe

- Changer due_after/due_before de str | None vers datetime | None pour typage FastAPI
- FastAPI parse et valide automatiquement, retourne 422 si format invalide (pas 500)
- Supprimer le parsing manuel datetime.fromisoformat() qui levait ValueError brute
- Ajouter ORDER BY déterministe: due_date ASC NULLS LAST, created_at DESC
  évite les réordonnances aléatoires entre requêtes PostgreSQL

Tests: 15/15 passent ✓

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-24 12:02:37 +02:00
co-authored by Claude Sonnet 4.6
parent a3704a2b27
commit b5f0453cdd
+5 -4
View File
@@ -18,8 +18,8 @@ async def list_todos(
status: str | None = "pending", status: str | None = "pending",
priority: str | None = None, priority: str | None = None,
tag: str | None = None, tag: str | None = None,
due_after: str | None = None, due_after: datetime | None = None,
due_before: str | None = None, due_before: datetime | None = None,
limit: int = 200, limit: int = 200,
session: AsyncSession = Depends(get_session), session: AsyncSession = Depends(get_session),
): ):
@@ -33,13 +33,14 @@ async def list_todos(
if tag: if tag:
conditions.append(TodoItem.tags.contains([tag])) conditions.append(TodoItem.tags.contains([tag]))
if due_after: if due_after:
conditions.append(TodoItem.due_date >= datetime.fromisoformat(due_after)) conditions.append(TodoItem.due_date >= due_after)
if due_before: if due_before:
conditions.append(TodoItem.due_date <= datetime.fromisoformat(due_before)) conditions.append(TodoItem.due_date <= due_before)
stmt = select(TodoItem) stmt = select(TodoItem)
if conditions: if conditions:
stmt = stmt.where(and_(*conditions)) stmt = stmt.where(and_(*conditions))
stmt = stmt.order_by(TodoItem.due_date.asc().nulls_last(), TodoItem.created_at.desc())
stmt = stmt.limit(limit) stmt = stmt.limit(limit)
result = await session.execute(stmt) result = await session.execute(stmt)
return result.scalars().all() return result.scalars().all()