Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

Explore optional typed command and event unions for exhaustive handling

Đang mở
#627 1 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 7 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
5/5
Thời gian dự kiến
Hơn một tuần
Mức phù hợp với người mới
35/100
Loại issue
Tính năng
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
csharp

Hướng nghiên cứu

Start by reading src/Core/src/Eventuous.Domain/State.cs, then compare the command and aggregate event APIs, target frameworks, and serialization paths named in the issue. Build a small end-to-end prototype with explicit command and event sets, and verify omitted and out-of-set cases produce errors while existing payloads replay unchanged. Done means the prototype, compatibility and runtime notes, and an API recommendation address the acceptance criteria.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Is your feature request related to a problem? Please describe.

Adding a command or event can leave handling incomplete without producing a compiler diagnostic. Eventuous provides typed handler registration, but it does not declare a closed set of commands and events for an aggregate against which handling can be checked.

For example, an application adds BookingCancelled and starts emitting it, but forgets to update the booking state. The default State<T>.When(object) returns the existing state when no handler is registered. Ignoring an event can be intentional, but an accidental omission can produce incorrect state during execution and replay. Similarly, a missing command registration is detected when the command is handled rather than when the application is compiled.

A community suggestion on Discord describes using F# discriminated unions and generics in Rosetta to make these omissions visible during compilation.

Describe the solution you'd like

Explore an optional API that lets an application declare the complete command and event sets for an aggregate and use exhaustive handling at its command and state-transition boundaries.

The initial deliverable should be a small prototype and design recommendation. Keep the existing APIs available and preserve their behavior for applications that do not opt in.

Example: forgetting to apply a cancellation event

An application initially supports creating a booking. Its declared event set, BookingEvent, contains only RoomBooked, and its state-update function handles that event.

A developer then adds cancellation:

  1. Add BookingCancelled to the BookingEvent set.
  2. Add a command handler that emits BookingCancelled.
  3. Forget to add cancellation handling to the state-update function.

With the current default state handling, the application can compile and store the cancellation event while leaving the booking state unchanged.

With the proposed typed API, the compiler knows that BookingEvent has two possible cases, but the state-update function handles only one. It reports the missing BookingCancelled case. Adding that case to update the booking's status resolves the diagnostic.

The same principle applies to commands: adding a command to the declared command set should produce a diagnostic wherever exhaustive command handling omits it.

The prototype should demonstrate build failures with the relevant diagnostics treated as errors. A general catch-all can hide newly added cases, so the example should use explicit cases, including explicit no-op handling where appropriate.

Exhaustiveness comes from the closed set and matching semantics. A marker interface alone does not provide this guarantee. These checks cover known cases in the consuming compilation; they do not prove business correctness, registration completeness elsewhere, or compatibility with unknown persisted events.

Design questions to resolve:

  • API placement: Can typed adapters or additional generic abstractions support both aggregate-based and functional command services without replacing existing APIs?
  • Language and runtime requirements: Compare F# unions, C# unions, and analyzer/generator approaches. C# union declarations produce structs, while current command handling and aggregate event application have class constraints. Account for those constraints and Eventuous's supported target frameworks.
  • Persistence compatibility: Keep existing event type names and serialized payloads stable. Determine how concrete events are wrapped and unwrapped at typed boundaries, including historical event versions and unknown-event behavior.
  • Selective consumption: Keep projection and subscription event sets independent. A projection that consumes a subset of events should not be required to handle every event in the system.

Acceptance criteria for this exploration:

  • Provide one end-to-end aggregate or functional service example with explicit command and event sets.
  • Demonstrate diagnostics for an omitted command case and an omitted event case after adding them to their respective sets.
  • Demonstrate rejection of commands or events outside the declared set at the typed API boundary.
  • Demonstrate explicit intentional ignoring without a catch-all that hides future cases.
  • Verify that existing serialized event payloads can be replayed through the prototype without changing their storage format.
  • Document compatibility, required language/runtime versions, and which guarantees remain outside compile-time checking.
  • Recommend an API direction, or explain why the tradeoffs do not justify adopting one.

Describe alternatives you've considered

  • Retain the current APIs and add application tests that check expected handler registrations and replay behavior.
  • Add opt-in startup validation against explicitly declared command/event sets. This catches omissions earlier than message processing, but still at runtime.
  • Extend Roslyn analyzers or source generators to check declared sets against handler registrations. The existing EventUsageAnalyzer checks event type annotations; it does not establish exhaustive command or event handling.
  • Keep unions in application domain code and adapt to Eventuous at the boundary, minimizing changes to the library.

Additional context

This proposal originates from the Discord discussion, which shared Rosetta's approach as inspiration for Eventuous.

Rosetta's aggregate example demonstrates typed command and event unions with exhaustive matching. Microsoft's C# union tutorial describes the preview feature, and the language reference explains exhaustiveness diagnostics and the generated struct representation. Evaluate the supported feature and runtime requirements during the prototype rather than assuming a particular release commitment.

Ngôn ngữ chính
C#
Star
512
Fork
99
Merge trung bình
5 ngày 6 giờ
Pull request đã merge (30 ngày)
5

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của Eventuous/eventuous

Tất cả issue của Eventuous/eventuous

Issue tương tự

Thêm issue về C#

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.