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
//! Entities and aggregate roots.
use Identifier;
/// A thing with a stable identity over time; equality is by id, not by field
/// values. Object-*unsafe* (associated `Id`, `Self`-shaped contract): entities
/// are concrete, so this is implemented directly, never used behind `dyn`.
///
/// # Examples
///
/// ```
/// use ev_lib::architecture::{Entity, Id};
///
/// struct OrderTag;
/// type OrderId = Id<OrderTag, u64>;
///
/// struct Order {
/// id: OrderId,
/// total_cents: u64,
/// }
///
/// impl Entity for Order {
/// type Id = OrderId;
/// fn id(&self) -> OrderId {
/// self.id
/// }
/// }
///
/// let order = Order { id: OrderId::from_raw(1), total_cents: 999 };
/// assert_eq!(order.id(), OrderId::from_raw(1));
/// ```
/// The transactional consistency boundary — the only kind of type a
/// [`super::repository::Repository`] loads or stores. A marker: it adds intent,
/// not methods. It deliberately does *not* require an event type (see
/// [`super::event::EmitsEvents`]), so a non-event aggregate is truly zero-cost.
///
/// # Examples
///
/// ```
/// use ev_lib::architecture::{AggregateRoot, Entity, Id};
///
/// struct OrderTag;
/// type OrderId = Id<OrderTag, u64>;
///
/// struct Order {
/// id: OrderId,
/// }
///
/// impl Entity for Order {
/// type Id = OrderId;
/// fn id(&self) -> OrderId {
/// self.id
/// }
/// }
///
/// impl AggregateRoot for Order {
/// const NAME: &'static str = "order";
/// }
///
/// // `NAME` is a compile-time constant, reachable without an instance — e.g. for
/// // a `NotFound { entity: Order::NAME, .. }` error.
/// assert_eq!(Order::NAME, "order");
/// ```