refactor(actions): make Context a type-keyed extensions map#341
Merged
Conversation
c09067d to
987962c
Compare
Replace the two-slot `Context<TopArgs, SubArgs>` with a type-keyed extensions map. Every subcommand level provides its own args struct into the context; leaf handlers extract whichever ancestors they need via `ctx.require::<T>()`. This frees deeply-nested handlers from being limited to the immediate parent and self, and removes the generics noise on handler signatures. All handlers now share the same signature: `async fn run(args, ctx)`. The `subcommands!` macro inserts each level's args into ctx before dispatch.
987962c to
7bf31da
Compare
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.
Summary
Replaces the two-slot `Context<TopArgs, SubArgs>` with a type-keyed extensions map, axum/React-style. Each subcommand level provides its own args struct into the context; leaf handlers extract whichever ancestors they need via `ctx.require::()`.
Motivation
The old `Context<A, B>` could only carry two args shapes (immediate parent + self), so a handler nested more than two deep would lose access to its grandparent's args (e.g. `Args` from inside a tamanu leaf). Deep features like the WIP `tamanu logs` and `reload` would either have to thread args through manually or duplicate state.
What changed
Tradeoff
Compile-time "you definitely have these two levels" guarantee → runtime "panic if you forgot to provide". Mitigated by the macro inserting symmetrically and 5 unit tests on the Context primitives. Worst case is `bestool foo bar` panicking with a clear `required value of type `X` not provided` if I missed a provide() somewhere — which we'd catch on the first dev run.