Autowire use-case DI, map chat-listing state, keyword-only use cases - #2
Merged
Merged
Conversation
Four wiring simplifications, no change to the HTTP contract. ModernDIPlugin now autowires ioc.UseCases, so build_app's twelve-entry dependencies= dict and its use-case imports are gone; a new use case needs only its provider. Database and Repositories stay unwired - a route handler has no business resolving a session, transaction or repository. ChatsTable maps unread_count (query_expression, filled by with_expression) and last_message (viewonly relationship, one selectinload) itself, so list_for_user returns plain entities whose attribute names already match the response schema. ChatListRow and ChatListItem.from_row both disappear and the listing endpoint is a single from_models call. last_message_id carries no ForeignKey, so the relationship annotates the join column foreign() and folds the soft-delete guard into its primaryjoin; list_for_user runs populate_existing because sessions are expire_on_commit=False. No DDL, so no migration. Every use case __call__ is keyword-only, and authenticated handlers annotate the request app.api.auth.AuthedRequest rather than restating litestar.Request[UsersTable, Any, Any].
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Four wiring simplifications with no change to the HTTP contract. Rationale and
rejected alternatives live in
planning/changes/2026-08-21.02-di-wiring-and-chat-listing.md.ModernDIPlugin(di_container, autowired_groups=[ioc.UseCases])replaces the twelve-entry
dependencies=dict and its imports inbuild_app.DatabaseandRepositoriesstay unwired on purpose.ChatsTablemapsunread_count(query_expression, filled bywith_expression) andlast_message(viewonly relationship, oneselectinload),so
list_for_userreturns entities whose attribute names already match theschema.
ChatListRow,ChatListItem.from_rowand the manualWHERE id IN (...)preview batch are gone; the endpoint is one
Chats.from_models(...).__call__s, e.g.create_chat_use_case(actor=request.user, data=data).AuthedRequest. Authenticated handlers annotate the request with the aliasinstead of restating
litestar.Request[UsersTable, Any, Any].Notes for review
tests/api/test_chat_listing_api.pyneeded no edits.list_for_userrunspopulate_existing=True: sessions areexpire_on_commit=False,so an identity-mapped chat would otherwise keep the
unread_countit was firstloaded with, and a second listing in the same session would return stale numbers.
Safe only because the query is read-only.
last_message_idcarries noForeignKey(it would close a cycle withmessages.chat_id), so the relationship annotates the join columnorm.foreign()and folds the soft-delete guard into its
primaryjoin.alembic checkreports the same pre-existingck_chats_chattypediff asmainand nothing else.Verification
just test— 108 passed, 100% coverage.just lint— clean.just check-planning— OK.