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