1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3pub enum EntityAction {
4 Update,
5 Delete,
6 Persist,
7 Recover,
8}
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28pub enum EntityStatus {
29 New,
31 Persisted,
33 PersistedDeleted,
35 Updated,
37 UpdatedDeleted,
39 UpdatedRecover,
41 Refer,
43}
44
45impl Default for EntityStatus {
46 fn default() -> Self {
47 EntityStatus::New
48 }
49}
50
51impl EntityStatus {
52 pub fn next(self, action: EntityAction) -> Result<EntityStatus, String> {
56 match (self, action) {
57 (EntityStatus::New, EntityAction::Update) => Ok(EntityStatus::New),
59 (EntityStatus::New, EntityAction::Persist) => Ok(EntityStatus::Persisted),
60
61 (EntityStatus::Persisted, EntityAction::Update) => Ok(EntityStatus::Updated),
63 (EntityStatus::Persisted, EntityAction::Delete) => Ok(EntityStatus::UpdatedDeleted),
64
65 (EntityStatus::PersistedDeleted, EntityAction::Recover) => {
67 Ok(EntityStatus::UpdatedRecover)
68 }
69
70 (EntityStatus::Updated, EntityAction::Update) => Ok(EntityStatus::Updated),
72 (EntityStatus::Updated, EntityAction::Persist) => Ok(EntityStatus::Persisted),
73
74 (EntityStatus::UpdatedDeleted, EntityAction::Persist) => {
76 Ok(EntityStatus::PersistedDeleted)
77 }
78 (EntityStatus::UpdatedDeleted, EntityAction::Delete) => {
79 Ok(EntityStatus::UpdatedDeleted)
80 }
81
82 (EntityStatus::UpdatedRecover, EntityAction::Persist) => Ok(EntityStatus::Persisted),
84 (EntityStatus::UpdatedRecover, EntityAction::Recover) => {
85 Ok(EntityStatus::UpdatedRecover)
86 }
87
88 (status, action) => Err(format!(
90 "invalid entity status transition: {:?} + {:?}",
91 status, action
92 )),
93 }
94 }
95
96 pub fn need_persist(&self) -> bool {
101 matches!(
102 self,
103 EntityStatus::New
104 | EntityStatus::Updated
105 | EntityStatus::UpdatedDeleted
106 | EntityStatus::UpdatedRecover
107 )
108 }
109
110 pub fn is_new(&self) -> bool {
112 matches!(self, EntityStatus::New)
113 }
114
115 pub fn is_updated(&self) -> bool {
117 matches!(self, EntityStatus::Updated)
118 }
119
120 pub fn is_deleted(&self) -> bool {
122 matches!(
123 self,
124 EntityStatus::UpdatedDeleted | EntityStatus::PersistedDeleted
125 )
126 }
127
128 pub fn is_recover(&self) -> bool {
130 matches!(self, EntityStatus::UpdatedRecover)
131 }
132}
133
134impl std::fmt::Display for EntityStatus {
135 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
136 match self {
137 EntityStatus::New => write!(f, "New"),
138 EntityStatus::Persisted => write!(f, "Persisted"),
139 EntityStatus::PersistedDeleted => write!(f, "PersistedDeleted"),
140 EntityStatus::Updated => write!(f, "Updated"),
141 EntityStatus::UpdatedDeleted => write!(f, "UpdatedDeleted"),
142 EntityStatus::UpdatedRecover => write!(f, "UpdatedRecover"),
143 EntityStatus::Refer => write!(f, "Refer"),
144 }
145 }
146}
147
148impl std::fmt::Display for EntityAction {
149 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
150 match self {
151 EntityAction::Update => write!(f, "Update"),
152 EntityAction::Delete => write!(f, "Delete"),
153 EntityAction::Persist => write!(f, "Persist"),
154 EntityAction::Recover => write!(f, "Recover"),
155 }
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162
163 #[test]
164 fn default_is_new() {
165 assert_eq!(EntityStatus::default(), EntityStatus::New);
166 }
167
168 #[test]
169 fn new_update_stays_new() {
170 assert_eq!(
171 EntityStatus::New.next(EntityAction::Update).unwrap(),
172 EntityStatus::New
173 );
174 }
175
176 #[test]
177 fn new_persist_becomes_persisted() {
178 assert_eq!(
179 EntityStatus::New.next(EntityAction::Persist).unwrap(),
180 EntityStatus::Persisted
181 );
182 }
183
184 #[test]
185 fn persisted_update_becomes_updated() {
186 assert_eq!(
187 EntityStatus::Persisted.next(EntityAction::Update).unwrap(),
188 EntityStatus::Updated
189 );
190 }
191
192 #[test]
193 fn persisted_delete_becomes_updated_deleted() {
194 assert_eq!(
195 EntityStatus::Persisted.next(EntityAction::Delete).unwrap(),
196 EntityStatus::UpdatedDeleted
197 );
198 }
199
200 #[test]
201 fn persisted_deleted_recover_becomes_updated_recover() {
202 assert_eq!(
203 EntityStatus::PersistedDeleted
204 .next(EntityAction::Recover)
205 .unwrap(),
206 EntityStatus::UpdatedRecover
207 );
208 }
209
210 #[test]
211 fn updated_update_stays_updated() {
212 assert_eq!(
213 EntityStatus::Updated.next(EntityAction::Update).unwrap(),
214 EntityStatus::Updated
215 );
216 }
217
218 #[test]
219 fn updated_persist_becomes_persisted() {
220 assert_eq!(
221 EntityStatus::Updated.next(EntityAction::Persist).unwrap(),
222 EntityStatus::Persisted
223 );
224 }
225
226 #[test]
227 fn updated_deleted_persist_becomes_persisted_deleted() {
228 assert_eq!(
229 EntityStatus::UpdatedDeleted
230 .next(EntityAction::Persist)
231 .unwrap(),
232 EntityStatus::PersistedDeleted
233 );
234 }
235
236 #[test]
237 fn updated_deleted_delete_stays_updated_deleted() {
238 assert_eq!(
239 EntityStatus::UpdatedDeleted
240 .next(EntityAction::Delete)
241 .unwrap(),
242 EntityStatus::UpdatedDeleted
243 );
244 }
245
246 #[test]
247 fn updated_recover_persist_becomes_persisted() {
248 assert_eq!(
249 EntityStatus::UpdatedRecover
250 .next(EntityAction::Persist)
251 .unwrap(),
252 EntityStatus::Persisted
253 );
254 }
255
256 #[test]
257 fn updated_recover_recover_stays_updated_recover() {
258 assert_eq!(
259 EntityStatus::UpdatedRecover
260 .next(EntityAction::Recover)
261 .unwrap(),
262 EntityStatus::UpdatedRecover
263 );
264 }
265
266 #[test]
267 fn invalid_transition_returns_err() {
268 assert!(EntityStatus::New.next(EntityAction::Delete).is_err());
269 assert!(EntityStatus::New.next(EntityAction::Recover).is_err());
270 assert!(EntityStatus::Persisted.next(EntityAction::Persist).is_err());
271 assert!(EntityStatus::Persisted.next(EntityAction::Recover).is_err());
272 assert!(EntityStatus::PersistedDeleted
273 .next(EntityAction::Update)
274 .is_err());
275 assert!(EntityStatus::PersistedDeleted
276 .next(EntityAction::Delete)
277 .is_err());
278 assert!(EntityStatus::PersistedDeleted
279 .next(EntityAction::Persist)
280 .is_err());
281 assert!(EntityStatus::Updated.next(EntityAction::Delete).is_err());
282 assert!(EntityStatus::Updated.next(EntityAction::Recover).is_err());
283 assert!(EntityStatus::UpdatedDeleted
284 .next(EntityAction::Update)
285 .is_err());
286 assert!(EntityStatus::UpdatedDeleted
287 .next(EntityAction::Recover)
288 .is_err());
289 assert!(EntityStatus::UpdatedRecover
290 .next(EntityAction::Update)
291 .is_err());
292 assert!(EntityStatus::UpdatedRecover
293 .next(EntityAction::Delete)
294 .is_err());
295 assert!(EntityStatus::Refer.next(EntityAction::Update).is_err());
296 assert!(EntityStatus::Refer.next(EntityAction::Delete).is_err());
297 assert!(EntityStatus::Refer.next(EntityAction::Persist).is_err());
298 assert!(EntityStatus::Refer.next(EntityAction::Recover).is_err());
299 }
300
301 #[test]
302 fn need_persist_flags() {
303 assert!(EntityStatus::New.need_persist());
304 assert!(!EntityStatus::Persisted.need_persist());
305 assert!(!EntityStatus::PersistedDeleted.need_persist());
306 assert!(EntityStatus::Updated.need_persist());
307 assert!(EntityStatus::UpdatedDeleted.need_persist());
308 assert!(EntityStatus::UpdatedRecover.need_persist());
309 assert!(!EntityStatus::Refer.need_persist());
310 }
311
312 #[test]
313 fn helper_predicates() {
314 assert!(EntityStatus::New.is_new());
315 assert!(!EntityStatus::Persisted.is_new());
316
317 assert!(EntityStatus::Updated.is_updated());
318 assert!(!EntityStatus::New.is_updated());
319
320 assert!(EntityStatus::UpdatedDeleted.is_deleted());
321 assert!(EntityStatus::PersistedDeleted.is_deleted());
322 assert!(!EntityStatus::Updated.is_deleted());
323
324 assert!(EntityStatus::UpdatedRecover.is_recover());
325 assert!(!EntityStatus::Updated.is_recover());
326 }
327
328 #[test]
329 fn full_lifecycle_create_update_delete() {
330 let status = EntityStatus::default();
331 assert_eq!(status, EntityStatus::New);
332
333 let status = status.next(EntityAction::Persist).unwrap();
334 assert_eq!(status, EntityStatus::Persisted);
335
336 let status = status.next(EntityAction::Update).unwrap();
337 assert_eq!(status, EntityStatus::Updated);
338
339 let status = status.next(EntityAction::Persist).unwrap();
340 assert_eq!(status, EntityStatus::Persisted);
341
342 let status = status.next(EntityAction::Delete).unwrap();
343 assert_eq!(status, EntityStatus::UpdatedDeleted);
344
345 let status = status.next(EntityAction::Persist).unwrap();
346 assert_eq!(status, EntityStatus::PersistedDeleted);
347
348 let status = status.next(EntityAction::Recover).unwrap();
349 assert_eq!(status, EntityStatus::UpdatedRecover);
350
351 let status = status.next(EntityAction::Persist).unwrap();
352 assert_eq!(status, EntityStatus::Persisted);
353 }
354}