1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
use ;
use ;
use Uuid;
/// The serializable shape of a domain event. Every variant must report
/// a stable `event_type` string — this is what mire stores in the
/// `event_type` column and uses as the schema discriminator for the
/// event log.
///
/// **`event_type` strings are load-bearing.** Once an event has been
/// persisted under a given string, changing that string orphans the
/// historical event (it no longer deserializes into the new shape).
/// Treat them as part of your wire format.
///
/// ## Implementing via the derive macro (recommended)
///
/// Available behind the default-on `derive` feature. One line on the
/// enum sets the entity prefix; variants get CamelCase → kebab-case
/// translation automatically:
///
/// ```rust,ignore
/// use mire::EventData;
/// use serde::{Serialize, Deserialize};
///
/// #[derive(Debug, Clone, Serialize, Deserialize, EventData)]
/// #[serde(tag = "type")]
/// #[mire(entity = "account")]
/// enum AccountEvent {
/// Opened { owner: String }, // → "account.opened"
/// MoneyDeposited { amount: i64 }, // → "account.money-deposited"
///
/// #[mire(rename = "closed-v2")] // pin a specific variant
/// Closed, // → "account.closed-v2"
/// }
/// ```
///
/// **Stability rule:** the `entity` attribute is fixed at the enum
/// level (no per-variant override). A variant rename in Rust *will*
/// change the persisted event_type unless you pin it with
/// `#[mire(rename = "...")]`. If you're renaming variants on a stream
/// that's already in production, pin first or you'll orphan history.
///
/// ## Implementing by hand
///
/// If you turn off the `derive` feature, hand-write the impl:
///
/// ```rust,ignore
/// impl EventData for AccountEvent {
/// fn event_type(&self) -> &'static str {
/// match self {
/// AccountEvent::Opened { .. } => "account.opened",
/// // ...
/// }
/// }
/// }
/// ```
/// An [`EventData`] type whose `event_type` discriminator string is known at
/// compile time. Enables references like `await_event::<E>()` that don't have
/// an instance to call `event_type(&self)` on.
///
/// Implemented automatically by `#[derive(EventData)]` for struct-shaped
/// events. Enum-shaped events (multi-variant) cannot have a single static
/// const and don't implement this trait.
///
/// ```rust,ignore
/// use mire::{EventData, EventTypeStatic};
/// use serde::{Serialize, Deserialize};
///
/// #[derive(Debug, Clone, Serialize, Deserialize, EventData)]
/// #[mire(event_type = "flight.held")]
/// struct FlightHeld { hold_id: String }
///
/// assert_eq!(<FlightHeld as EventTypeStatic>::EVENT_TYPE, "flight.held");
/// ```
// =====================================================================
// IntoResponse — what a saga request handler can return.
//
// Lives in `mire` (not mire-sagas) so the derive macro can emit
// per-event-type impls without depending on mire-sagas, AND so the
// `Result<Ok, Err>` impl can coexist (Rust's orphan rule requires the
// trait or the type to be local). There is no blanket `impl<T:
// EventTypeStatic> IntoResponse for T` — that would coherence-conflict
// with the `Result` impl. Per-type impls come from the derive.
// =====================================================================
/// A value that can be turned into a response event.
///
/// Implemented automatically by `#[derive(EventData)]` on struct events,
/// and by the framework for `Result<Ok, Err>` where both branches are
/// `EventTypeStatic` events (Err must also implement `Display` for the
/// reason string surfaced to compensation handlers).
/// What [`IntoResponse::into_response`] returns. The saga runner uses the
/// fields to deliver the response back to the awaiting step (or fail it
/// when `is_error` is true).