1use crate::{entity::Entity, error::MutationError, model::View, reactor::ChangeNotification};
2use ankurah_proto::{Attested, Event};
3
4#[derive(Debug, Clone)]
5pub struct EntityChange {
6 entity: Entity,
7 events: Vec<Attested<Event>>,
8}
9
10impl ChangeNotification for EntityChange {
12 type Entity = Entity;
13 type Event = ankurah_proto::Attested<Event>;
14
15 fn into_parts(self) -> (Self::Entity, Vec<Self::Event>) { (self.entity, self.events) }
16 fn entity(&self) -> &Self::Entity { &self.entity }
17 fn events(&self) -> &[Self::Event] { &self.events }
18}
19
20impl EntityChange {
22 pub fn new(entity: Entity, events: Vec<Attested<Event>>) -> Result<Self, MutationError> {
23 for event in &events {
26 let head = entity.head();
27 if event.payload.entity_id != entity.id {
28 return Err(MutationError::InvalidEvent);
29 }
30 if !head.contains(&event.payload.id()) {
31 return Err(MutationError::InvalidEvent);
32 }
33 }
34 Ok(Self { entity, events })
35 }
36 pub fn into_parts(self) -> (Entity, Vec<Attested<Event>>) { (self.entity, self.events) }
37}
38
39#[derive(Debug, Clone)]
40pub enum ItemChange<I> {
41 Initial { item: I },
43 Add { item: I, events: Vec<Attested<Event>> },
45 Update { item: I, events: Vec<Attested<Event>> },
47 Remove { item: I, events: Vec<Attested<Event>> },
49}
50
51impl<I> ItemChange<I> {
52 pub fn entity(&self) -> &I {
53 match self {
54 ItemChange::Initial { item }
55 | ItemChange::Add { item, .. }
56 | ItemChange::Update { item, .. }
57 | ItemChange::Remove { item, .. } => item,
58 }
59 }
60
61 pub fn events(&self) -> &[Attested<Event>] {
62 match self {
63 ItemChange::Add { events, .. } | ItemChange::Update { events, .. } | ItemChange::Remove { events, .. } => events,
64 _ => &[],
65 }
66 }
67 pub fn kind(&self) -> ChangeKind { ChangeKind::from(self) }
68}
69
70impl<I> std::fmt::Display for ItemChange<I>
71where I: View
72{
73 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74 match self {
75 ItemChange::Initial { item } => {
76 write!(f, "Initial {}/{}", I::collection(), item.id())
77 }
78 ItemChange::Add { item, .. } => {
79 write!(f, "Add {}/{}", I::collection(), item.id())
80 }
81 ItemChange::Update { item, .. } => {
82 write!(f, "Update {}/{}", I::collection(), item.id())
83 }
84 ItemChange::Remove { item, .. } => {
85 write!(f, "Remove {}/{}", I::collection(), item.id())
86 }
87 }
88 }
89}
90
91impl std::fmt::Display for EntityChange {
92 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93 write!(f, "EntityChange {}/{}", self.entity.collection(), self.entity.id())
94 }
95}
96
97use crate::resultset::ResultSet;
98
99#[derive(Debug, Clone)]
100pub struct ChangeSet<R: View> {
101 pub resultset: ResultSet<R>,
102 pub changes: Vec<ItemChange<R>>,
103}
104
105impl<R: View> ChangeSet<R>
106where R: Clone
107{
108 pub fn initial(&self) -> Vec<R> {
110 self.changes
111 .iter()
112 .filter_map(|change| match change {
113 ItemChange::Initial { item } => Some(item.clone()),
114 _ => None,
115 })
116 .collect()
117 }
118
119 pub fn added(&self) -> Vec<R> {
121 self.changes
122 .iter()
123 .filter_map(|change| match change {
124 ItemChange::Add { item, .. } => Some(item.clone()),
125 _ => None,
126 })
127 .collect()
128 }
129
130 pub fn appeared(&self) -> Vec<R> {
132 self.changes
133 .iter()
134 .filter_map(|change| match change {
135 ItemChange::Add { item, .. } | ItemChange::Initial { item } => Some(item.clone()),
136 _ => None,
137 })
138 .collect()
139 }
140
141 #[deprecated(since = "0.7.10", note = "Use `appeared()`, `initial()`, or `added()` instead")]
142 pub fn adds(&self) -> Vec<R> { self.appeared() }
144
145 pub fn removed(&self) -> Vec<R> {
147 self.changes
148 .iter()
149 .filter_map(|change| match change {
150 ItemChange::Remove { item, .. } => Some(item.clone()),
151 _ => None,
152 })
153 .collect()
154 }
155
156 #[deprecated(since = "0.7.10", note = "Use `removed()` instead")]
157 pub fn removes(&self) -> Vec<R> { self.removed() }
159
160 pub fn updated(&self) -> Vec<R> {
162 self.changes
163 .iter()
164 .filter_map(|change| match change {
165 ItemChange::Update { item, .. } => Some(item.clone()),
166 _ => None,
167 })
168 .collect()
169 }
170
171 #[deprecated(since = "0.7.10", note = "Use `updated()` instead")]
172 pub fn updates(&self) -> Vec<R> { self.updated() }
174}
175
176impl<I> std::fmt::Display for ChangeSet<I>
177where I: View + Clone + 'static
178{
179 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
180 use ankurah_signals::Peek;
182 let results = self.resultset.peek().len();
183 write!(f, "ChangeSet({results} results): {}", self.changes.iter().map(|c| c.to_string()).collect::<Vec<_>>().join(", "))
184 }
185}
186
187impl<I> From<ItemChange<Entity>> for ItemChange<I>
191where I: View
192{
193 fn from(change: ItemChange<Entity>) -> Self {
194 match change {
195 ItemChange::Initial { item } => ItemChange::Initial { item: I::from_entity(item) },
196 ItemChange::Add { item, events } => ItemChange::Add { item: I::from_entity(item), events },
197 ItemChange::Update { item, events } => ItemChange::Update { item: I::from_entity(item), events },
198 ItemChange::Remove { item, events } => ItemChange::Remove { item: I::from_entity(item), events },
199 }
200 }
201}
202
203#[derive(Debug, Clone, PartialEq)]
204pub enum ChangeKind {
205 Initial,
206 Add,
207 Remove,
208 Update,
209}
210
211impl<R> From<&ItemChange<R>> for ChangeKind {
212 fn from(change: &ItemChange<R>) -> Self {
213 match change {
214 ItemChange::Initial { .. } => ChangeKind::Initial,
215 ItemChange::Add { .. } => ChangeKind::Add,
216 ItemChange::Remove { .. } => ChangeKind::Remove,
217 ItemChange::Update { .. } => ChangeKind::Update,
218 }
219 }
220}
221
222