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
//! Domain events.
//!
//! The traits here are *defined but not yet wired* in the EV codebase: no
//! aggregate raises events today. They are the documented home for a future
//! Postgres↔external-system consistency story — a domain event can be written to
//! a Postgres `outbox` table inside the same
//! [`super::unit_of_work::UnitOfWork`] as the state change, then dispatched
//! asynchronously.
use ;
/// A fact that happened in the domain, named in the past tense.
///
/// Serializable so it can be persisted to an outbox. Object-*unsafe*
/// (associated const, `DeserializeOwned`): used as a concrete per-context enum,
/// never as `dyn DomainEvent`.
///
/// # Examples
///
/// ```
/// use ev_lib::architecture::DomainEvent;
/// use serde::{Deserialize, Serialize};
///
/// #[derive(Clone, Deserialize, Serialize)]
/// enum BlogEvent {
/// Published { slug: String },
/// }
///
/// impl DomainEvent for BlogEvent {
/// const KIND: &'static str = "blog";
/// }
///
/// assert_eq!(BlogEvent::KIND, "blog");
/// ```
/// Implemented only by aggregates that actually raise events. Aggregates that
/// raise none (like a plain CRUD `Blog`) simply do not implement this, so the
/// non-event case carries no stub event type.
///
/// # Examples
///
/// ```
/// use ev_lib::architecture::{AggregateRoot, DomainEvent, EmitsEvents, Entity, Id};
/// use serde::{Deserialize, Serialize};
///
/// struct CartTag;
/// type CartId = Id<CartTag, u64>;
///
/// #[derive(Clone, Deserialize, Serialize)]
/// enum CartEvent {
/// ItemAdded { sku: String },
/// }
/// impl DomainEvent for CartEvent {
/// const KIND: &'static str = "cart";
/// }
///
/// #[derive(Default)]
/// struct Cart {
/// id: u64,
/// pending: Vec<CartEvent>,
/// }
///
/// impl Cart {
/// fn add(&mut self, sku: &str) {
/// self.pending.push(CartEvent::ItemAdded { sku: sku.to_owned() });
/// }
/// }
///
/// impl Entity for Cart {
/// type Id = CartId;
/// fn id(&self) -> CartId {
/// CartId::from_raw(self.id)
/// }
/// }
/// impl AggregateRoot for Cart {
/// const NAME: &'static str = "cart";
/// }
/// impl EmitsEvents for Cart {
/// type Event = CartEvent;
/// fn drain_events(&mut self) -> Vec<CartEvent> {
/// std::mem::take(&mut self.pending)
/// }
/// }
///
/// let mut cart = Cart::default();
/// cart.add("SKU-1");
/// assert_eq!(cart.drain_events().len(), 1);
/// assert!(cart.drain_events().is_empty()); // drained
/// ```
/// A domain event plus the metadata an outbox needs to store and order it.
///
/// The explicit serde bound resolves the ambiguity between the derive's default
/// `E: Deserialize<'de>` bound and `DomainEvent`'s `DeserializeOwned` supertrait.