Skip to content

Bind EventMeta and IdempotencyKey directly on application traits - #2

Merged
idugalic merged 6 commits into
mainfrom
feature/idempotency-eventmeta-bounds
Jul 23, 2026
Merged

idugalic merged 6 commits into
mainfrom
feature/idempotency-eventmeta-bounds

Conversation

@idugalic

Copy link
Copy Markdown
Member

Add where-clause bounds so EventRepository/StateRepository require C: IdempotencyKey (dedup retried commands) and EventRepository/ViewRepository/ EventLoader require their event type params to implement EventMeta (secondary indexing). Restate the bounds on every handler that wraps these traits (EventSourcedCommandHandler, StateStoredCommandHandler, MaterializedViewHandler, EventSourcedQueryHandler), since Rust doesn't propagate a trait's own where-clause to external bound sites. Rewrite all doc examples to satisfy the new contract. Bump version to 0.3.0 for this breaking API change.

idugalic and others added 6 commits July 23, 2026 20:27
Add where-clause bounds so EventRepository/StateRepository require
C: IdempotencyKey (dedup retried commands) and EventRepository/ViewRepository/
EventLoader require their event type params to implement EventMeta (secondary
indexing). Restate the bounds on every handler that wraps these traits
(EventSourcedCommandHandler, StateStoredCommandHandler, MaterializedViewHandler,
EventSourcedQueryHandler), since Rust doesn't propagate a trait's own
where-clause to external bound sites. Rewrite all doc examples to satisfy the
new contract. Bump version to 0.3.0 for this breaking API change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replace the hand-formatted "key:value" string convention with a Tag { key,
value } struct (Display produces the canonical "key:value" wire format).
This removes the risk of malformed tags from manual format!() calls, e.g. a
missing separator or a value containing a colon. EventMeta::tags() and
QueryTuple.tags now both return/hold Vec<Tag> instead of Vec<String>, keeping
events and queries structurally consistent. Update all doc examples
accordingly and bump version to 0.4.0.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Add Send + Sync bounds to C/Ei/Eo on EventRepository, C/S on StateRepository,
E/S on ViewRepository, and E on EventLoader (multi-threaded variants only).
These types are moved into or held across the Send future each trait's
methods already promise to return, so the bound was previously an unstated
requirement left to each implementor to satisfy; making it explicit on the
trait catches violations at the trait-bound level instead of deep inside an
implementation's async fn body. Restate the bounds on every handler that
wraps these traits, since Rust doesn't propagate a trait's own where-clause
to external bound sites. Single-threaded variants are untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
QueryTuple is a plain, dependency-free data type (like Tag, EventMeta,
IdempotencyKey) rather than an application-layer concern, so it belongs in
lib.rs alongside them instead of inside event_sourced_query_handler.rs.
EventLoader and EventSourcedQueryHandler now import it from crate root.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
EventRepository::execute currently has no way to know which events are
relevant to a given command beyond a hardcoded single-stream lookup baked
into each implementation. Introduce CommandQueries (implemented by the
command type, returning Vec<QueryTuple>) so DCB-style repositories can fetch
exactly the events matching the command's declared queries — the same
pattern already used for IdempotencyKey (dedup) and EventMeta (event
indexing), rather than threading an unnameable closure type through
EventRepository's own generic parameters.

Bind C: CommandQueries on both EventRepository variants and restate it on
EventSourcedCommandHandler, consistent with how the other command/event
capability traits are already handled.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@idugalic
idugalic merged commit 9ff3287 into main Jul 23, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant