elif_orm/model/
lifecycle.rs

1use crate::event_error::EventError;
2use crate::events::ModelObserver;
3use crate::observers::ObserverManager;
4
5pub struct ModelLifecycle {
6    observer_manager: ObserverManager,
7}
8
9impl ModelLifecycle {
10    pub fn new() -> Self {
11        Self {
12            observer_manager: ObserverManager::new(),
13        }
14    }
15
16    pub fn register_observer<T: 'static>(&mut self, observer: Box<dyn ModelObserver<T>>) {
17        self.observer_manager.register_for_model(observer);
18    }
19
20    pub fn register_global_observer<T: 'static>(&mut self, observer: Box<dyn ModelObserver<T>>) {
21        self.observer_manager.register_global(observer);
22    }
23
24    pub async fn trigger_create_flow<T: 'static>(&self, model: &mut T) -> Result<(), EventError> {
25        if let Some(registry) = self.observer_manager.get_registry_for::<T>() {
26            // creating -> saving -> saved -> created
27            registry.trigger_creating(model).await?;
28            registry.trigger_saving(model).await?;
29            registry.trigger_saved(model).await?;
30            registry.trigger_created(model).await?;
31        }
32        Ok(())
33    }
34
35    pub async fn trigger_update_flow<T: 'static>(
36        &self,
37        model: &mut T,
38        original: &T,
39    ) -> Result<(), EventError> {
40        if let Some(registry) = self.observer_manager.get_registry_for::<T>() {
41            // updating -> saving -> saved -> updated
42            registry.trigger_updating(model, original).await?;
43            registry.trigger_saving(model).await?;
44            registry.trigger_saved(model).await?;
45            registry.trigger_updated(model, original).await?;
46        }
47        Ok(())
48    }
49
50    pub async fn trigger_delete_flow<T: 'static>(&self, model: &T) -> Result<(), EventError> {
51        if let Some(registry) = self.observer_manager.get_registry_for::<T>() {
52            // deleting -> deleted
53            registry.trigger_deleting(model).await?;
54            registry.trigger_deleted(model).await?;
55        }
56        Ok(())
57    }
58
59    pub fn has_observers_for<T: 'static>(&self) -> bool {
60        self.observer_manager.has_observers_for::<T>()
61    }
62}
63
64impl Default for ModelLifecycle {
65    fn default() -> Self {
66        Self::new()
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73    use async_trait::async_trait;
74    use std::sync::{Arc, Mutex};
75
76    #[derive(Debug, Clone, PartialEq)]
77    struct TestUser {
78        id: i64,
79        name: String,
80        email: String,
81    }
82
83    impl Default for TestUser {
84        fn default() -> Self {
85            Self {
86                id: 1,
87                name: "Test User".to_string(),
88                email: "test@example.com".to_string(),
89            }
90        }
91    }
92
93    #[derive(Debug, Clone)]
94    struct LifecycleTracker {
95        events: Arc<Mutex<Vec<String>>>,
96    }
97
98    impl LifecycleTracker {
99        fn new() -> Self {
100            Self {
101                events: Arc::new(Mutex::new(Vec::new())),
102            }
103        }
104
105        fn track(&self, event: &str) {
106            self.events.lock().unwrap().push(event.to_string());
107        }
108
109        fn get_events(&self) -> Vec<String> {
110            self.events.lock().unwrap().clone()
111        }
112
113        #[allow(dead_code)]
114        fn clear(&self) {
115            self.events.lock().unwrap().clear();
116        }
117    }
118
119    #[derive(Clone)]
120    struct LifecycleObserver {
121        tracker: LifecycleTracker,
122    }
123
124    impl LifecycleObserver {
125        fn new(tracker: LifecycleTracker) -> Self {
126            Self { tracker }
127        }
128    }
129
130    #[async_trait]
131    impl ModelObserver<TestUser> for LifecycleObserver {
132        async fn creating(&self, model: &mut TestUser) -> Result<(), EventError> {
133            self.tracker.track(&format!("creating: {}", model.name));
134            // Simulate email normalization
135            model.email = model.email.to_lowercase();
136            Ok(())
137        }
138
139        async fn created(&self, model: &TestUser) -> Result<(), EventError> {
140            self.tracker.track(&format!("created: {}", model.name));
141            Ok(())
142        }
143
144        async fn updating(
145            &self,
146            model: &mut TestUser,
147            original: &TestUser,
148        ) -> Result<(), EventError> {
149            self.tracker
150                .track(&format!("updating: {} -> {}", original.name, model.name));
151            Ok(())
152        }
153
154        async fn updated(&self, model: &TestUser, original: &TestUser) -> Result<(), EventError> {
155            self.tracker
156                .track(&format!("updated: {} -> {}", original.name, model.name));
157            Ok(())
158        }
159
160        async fn saving(&self, model: &mut TestUser) -> Result<(), EventError> {
161            self.tracker.track(&format!("saving: {}", model.name));
162            Ok(())
163        }
164
165        async fn saved(&self, model: &TestUser) -> Result<(), EventError> {
166            self.tracker.track(&format!("saved: {}", model.name));
167            Ok(())
168        }
169
170        async fn deleting(&self, model: &TestUser) -> Result<(), EventError> {
171            self.tracker.track(&format!("deleting: {}", model.name));
172            Ok(())
173        }
174
175        async fn deleted(&self, model: &TestUser) -> Result<(), EventError> {
176            self.tracker.track(&format!("deleted: {}", model.name));
177            Ok(())
178        }
179    }
180
181    #[tokio::test]
182    async fn test_model_lifecycle_create_flow() {
183        let tracker = LifecycleTracker::new();
184        let observer = LifecycleObserver::new(tracker.clone());
185
186        let mut lifecycle = ModelLifecycle::new();
187        lifecycle.register_observer::<TestUser>(Box::new(observer));
188
189        let mut user = TestUser {
190            name: "John Doe".to_string(),
191            email: "JOHN@EXAMPLE.COM".to_string(),
192            ..Default::default()
193        };
194
195        // Simulate create flow: creating -> saving -> saved -> created
196        let result = lifecycle.trigger_create_flow(&mut user).await;
197        assert!(result.is_ok());
198
199        let events = tracker.get_events();
200        assert_eq!(events.len(), 4);
201        assert_eq!(events[0], "creating: John Doe");
202        assert_eq!(events[1], "saving: John Doe");
203        assert_eq!(events[2], "saved: John Doe");
204        assert_eq!(events[3], "created: John Doe");
205
206        // Check email was normalized
207        assert_eq!(user.email, "john@example.com");
208    }
209
210    #[tokio::test]
211    async fn test_model_lifecycle_update_flow() {
212        let tracker = LifecycleTracker::new();
213        let observer = LifecycleObserver::new(tracker.clone());
214
215        let mut lifecycle = ModelLifecycle::new();
216        lifecycle.register_observer::<TestUser>(Box::new(observer));
217
218        let original = TestUser::default();
219        let mut updated = TestUser {
220            name: "Updated User".to_string(),
221            ..original.clone()
222        };
223
224        // Simulate update flow: updating -> saving -> saved -> updated
225        let result = lifecycle.trigger_update_flow(&mut updated, &original).await;
226        assert!(result.is_ok());
227
228        let events = tracker.get_events();
229        assert_eq!(events.len(), 4);
230        assert_eq!(events[0], "updating: Test User -> Updated User");
231        assert_eq!(events[1], "saving: Updated User");
232        assert_eq!(events[2], "saved: Updated User");
233        assert_eq!(events[3], "updated: Test User -> Updated User");
234    }
235
236    #[tokio::test]
237    async fn test_model_lifecycle_delete_flow() {
238        let tracker = LifecycleTracker::new();
239        let observer = LifecycleObserver::new(tracker.clone());
240
241        let mut lifecycle = ModelLifecycle::new();
242        lifecycle.register_observer::<TestUser>(Box::new(observer));
243
244        let user = TestUser::default();
245
246        // Simulate delete flow: deleting -> deleted
247        let result = lifecycle.trigger_delete_flow(&user).await;
248        assert!(result.is_ok());
249
250        let events = tracker.get_events();
251        assert_eq!(events.len(), 2);
252        assert_eq!(events[0], "deleting: Test User");
253        assert_eq!(events[1], "deleted: Test User");
254    }
255
256    #[tokio::test]
257    async fn test_model_lifecycle_error_stops_flow() {
258        struct FailingObserver;
259
260        #[async_trait]
261        impl ModelObserver<TestUser> for FailingObserver {
262            async fn creating(&self, _model: &mut TestUser) -> Result<(), EventError> {
263                Err(EventError::validation("Creation not allowed"))
264            }
265        }
266
267        let mut lifecycle = ModelLifecycle::new();
268        lifecycle.register_observer::<TestUser>(Box::new(FailingObserver));
269
270        let mut user = TestUser::default();
271
272        let result = lifecycle.trigger_create_flow(&mut user).await;
273        assert!(result.is_err());
274
275        match result.unwrap_err() {
276            EventError::Validation { message, .. } => {
277                assert_eq!(message, "Creation not allowed");
278            }
279            _ => panic!("Expected validation error"),
280        }
281    }
282
283    #[tokio::test]
284    async fn test_model_lifecycle_multiple_observers() {
285        let tracker1 = LifecycleTracker::new();
286        let tracker2 = LifecycleTracker::new();
287
288        let observer1 = LifecycleObserver::new(tracker1.clone());
289        let observer2 = LifecycleObserver::new(tracker2.clone());
290
291        let mut lifecycle = ModelLifecycle::new();
292        lifecycle.register_observer::<TestUser>(Box::new(observer1));
293        lifecycle.register_observer::<TestUser>(Box::new(observer2));
294
295        let mut user = TestUser::default();
296        let result = lifecycle.trigger_create_flow(&mut user).await;
297        assert!(result.is_ok());
298
299        // Both observers should have been called
300        let events1 = tracker1.get_events();
301        let events2 = tracker2.get_events();
302
303        assert_eq!(events1.len(), 4);
304        assert_eq!(events2.len(), 4);
305
306        // Both should have same event sequence
307        assert_eq!(events1[0], "creating: Test User");
308        assert_eq!(events2[0], "creating: Test User");
309    }
310
311    #[tokio::test]
312    async fn test_model_lifecycle_observer_modification_persists() {
313        struct NormalizingObserver;
314
315        #[async_trait]
316        impl ModelObserver<TestUser> for NormalizingObserver {
317            async fn creating(&self, model: &mut TestUser) -> Result<(), EventError> {
318                model.name = model.name.to_uppercase();
319                model.email = model.email.to_lowercase();
320                Ok(())
321            }
322        }
323
324        let mut lifecycle = ModelLifecycle::new();
325        lifecycle.register_observer::<TestUser>(Box::new(NormalizingObserver));
326
327        let mut user = TestUser {
328            name: "john doe".to_string(),
329            email: "JOHN@EXAMPLE.COM".to_string(),
330            ..Default::default()
331        };
332
333        let result = lifecycle.trigger_create_flow(&mut user).await;
334        assert!(result.is_ok());
335
336        // Check modifications persisted
337        assert_eq!(user.name, "JOHN DOE");
338        assert_eq!(user.email, "john@example.com");
339    }
340
341    #[tokio::test]
342    async fn test_model_lifecycle_event_propagation_control() {
343        struct PropagationStoppingObserver;
344
345        #[async_trait]
346        impl ModelObserver<TestUser> for PropagationStoppingObserver {
347            async fn creating(&self, _model: &mut TestUser) -> Result<(), EventError> {
348                Err(EventError::propagation_stopped("User decided to cancel"))
349            }
350        }
351
352        let mut lifecycle = ModelLifecycle::new();
353        lifecycle.register_observer::<TestUser>(Box::new(PropagationStoppingObserver));
354
355        let mut user = TestUser::default();
356        let result = lifecycle.trigger_create_flow(&mut user).await;
357
358        assert!(result.is_err());
359        match result.unwrap_err() {
360            EventError::PropagationStopped { reason, .. } => {
361                assert_eq!(reason, "User decided to cancel");
362            }
363            _ => panic!("Expected propagation stopped error"),
364        }
365    }
366}