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!(
273 EntityStatus::PersistedDeleted
274 .next(EntityAction::Update)
275 .is_err()
276 );
277 assert!(
278 EntityStatus::PersistedDeleted
279 .next(EntityAction::Delete)
280 .is_err()
281 );
282 assert!(
283 EntityStatus::PersistedDeleted
284 .next(EntityAction::Persist)
285 .is_err()
286 );
287 assert!(EntityStatus::Updated.next(EntityAction::Delete).is_err());
288 assert!(EntityStatus::Updated.next(EntityAction::Recover).is_err());
289 assert!(
290 EntityStatus::UpdatedDeleted
291 .next(EntityAction::Update)
292 .is_err()
293 );
294 assert!(
295 EntityStatus::UpdatedDeleted
296 .next(EntityAction::Recover)
297 .is_err()
298 );
299 assert!(
300 EntityStatus::UpdatedRecover
301 .next(EntityAction::Update)
302 .is_err()
303 );
304 assert!(
305 EntityStatus::UpdatedRecover
306 .next(EntityAction::Delete)
307 .is_err()
308 );
309 assert!(EntityStatus::Refer.next(EntityAction::Update).is_err());
310 assert!(EntityStatus::Refer.next(EntityAction::Delete).is_err());
311 assert!(EntityStatus::Refer.next(EntityAction::Persist).is_err());
312 assert!(EntityStatus::Refer.next(EntityAction::Recover).is_err());
313 }
314
315 #[test]
316 fn need_persist_flags() {
317 assert!(EntityStatus::New.need_persist());
318 assert!(!EntityStatus::Persisted.need_persist());
319 assert!(!EntityStatus::PersistedDeleted.need_persist());
320 assert!(EntityStatus::Updated.need_persist());
321 assert!(EntityStatus::UpdatedDeleted.need_persist());
322 assert!(EntityStatus::UpdatedRecover.need_persist());
323 assert!(!EntityStatus::Refer.need_persist());
324 }
325
326 #[test]
327 fn helper_predicates() {
328 assert!(EntityStatus::New.is_new());
329 assert!(!EntityStatus::Persisted.is_new());
330
331 assert!(EntityStatus::Updated.is_updated());
332 assert!(!EntityStatus::New.is_updated());
333
334 assert!(EntityStatus::UpdatedDeleted.is_deleted());
335 assert!(EntityStatus::PersistedDeleted.is_deleted());
336 assert!(!EntityStatus::Updated.is_deleted());
337
338 assert!(EntityStatus::UpdatedRecover.is_recover());
339 assert!(!EntityStatus::Updated.is_recover());
340 }
341
342 #[test]
343 fn full_lifecycle_create_update_delete() {
344 let status = EntityStatus::default();
345 assert_eq!(status, EntityStatus::New);
346
347 let status = status.next(EntityAction::Persist).unwrap();
348 assert_eq!(status, EntityStatus::Persisted);
349
350 let status = status.next(EntityAction::Update).unwrap();
351 assert_eq!(status, EntityStatus::Updated);
352
353 let status = status.next(EntityAction::Persist).unwrap();
354 assert_eq!(status, EntityStatus::Persisted);
355
356 let status = status.next(EntityAction::Delete).unwrap();
357 assert_eq!(status, EntityStatus::UpdatedDeleted);
358
359 let status = status.next(EntityAction::Persist).unwrap();
360 assert_eq!(status, EntityStatus::PersistedDeleted);
361
362 let status = status.next(EntityAction::Recover).unwrap();
363 assert_eq!(status, EntityStatus::UpdatedRecover);
364
365 let status = status.next(EntityAction::Persist).unwrap();
366 assert_eq!(status, EntityStatus::Persisted);
367 }
368}