use domain::{ ConfigRepository, DataSource, DataSourceId, DomainEvent, EventPublisher, Layout, LayoutPreset, LayoutPresetId, ThemeConfig, User, WidgetConfig, WidgetId, }; use std::collections::HashMap; use std::sync::Mutex; pub struct InMemoryConfigRepository { widgets: Mutex>, data_sources: Mutex>, layout: Mutex>, theme: Mutex>, presets: Mutex>, } impl InMemoryConfigRepository { pub fn new() -> Self { Self { widgets: Mutex::new(HashMap::new()), data_sources: Mutex::new(HashMap::new()), layout: Mutex::new(None), theme: Mutex::new(None), presets: Mutex::new(HashMap::new()), } } } #[derive(Debug)] pub struct Never; impl std::fmt::Display for Never { fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { unreachable!() } } impl ConfigRepository for InMemoryConfigRepository { type Error = Never; async fn get_widget(&self, id: WidgetId) -> Result, Self::Error> { Ok(self.widgets.lock().unwrap().get(&id).cloned()) } async fn list_widgets(&self) -> Result, Self::Error> { Ok(self.widgets.lock().unwrap().values().cloned().collect()) } async fn save_widget(&self, config: &WidgetConfig) -> Result<(), Self::Error> { self.widgets .lock() .unwrap() .insert(config.id, config.clone()); Ok(()) } async fn delete_widget(&self, id: WidgetId) -> Result<(), Self::Error> { self.widgets.lock().unwrap().remove(&id); Ok(()) } async fn get_data_source(&self, id: DataSourceId) -> Result, Self::Error> { Ok(self.data_sources.lock().unwrap().get(&id).cloned()) } async fn list_data_sources(&self) -> Result, Self::Error> { Ok(self .data_sources .lock() .unwrap() .values() .cloned() .collect()) } async fn save_data_source(&self, source: &DataSource) -> Result<(), Self::Error> { self.data_sources .lock() .unwrap() .insert(source.id, source.clone()); Ok(()) } async fn delete_data_source(&self, id: DataSourceId) -> Result<(), Self::Error> { self.data_sources.lock().unwrap().remove(&id); Ok(()) } async fn get_layout(&self) -> Result, Self::Error> { Ok(self.layout.lock().unwrap().clone()) } async fn save_layout(&self, layout: &Layout) -> Result<(), Self::Error> { *self.layout.lock().unwrap() = Some(layout.clone()); Ok(()) } async fn get_theme(&self) -> Result, Self::Error> { Ok(self.theme.lock().unwrap().clone()) } async fn save_theme(&self, theme: &ThemeConfig) -> Result<(), Self::Error> { *self.theme.lock().unwrap() = Some(theme.clone()); Ok(()) } async fn get_preset(&self, id: LayoutPresetId) -> Result, Self::Error> { Ok(self.presets.lock().unwrap().get(&id).cloned()) } async fn list_presets(&self) -> Result, Self::Error> { Ok(self.presets.lock().unwrap().values().cloned().collect()) } async fn save_preset(&self, preset: &LayoutPreset) -> Result<(), Self::Error> { self.presets .lock() .unwrap() .insert(preset.id, preset.clone()); Ok(()) } async fn delete_preset(&self, id: LayoutPresetId) -> Result<(), Self::Error> { self.presets.lock().unwrap().remove(&id); Ok(()) } async fn get_user_by_username(&self, _username: &str) -> Result, Self::Error> { Ok(None) } async fn save_user(&self, _user: &User) -> Result<(), Self::Error> { Ok(()) } async fn count_users(&self) -> Result { Ok(0) } } pub struct InMemoryEventPublisher { events: Mutex>, } impl InMemoryEventPublisher { pub fn new() -> Self { Self { events: Mutex::new(Vec::new()), } } pub fn emitted(&self) -> Vec { self.events.lock().unwrap().clone() } } impl EventPublisher for InMemoryEventPublisher { type Error = Never; async fn publish(&self, event: DomainEvent) -> Result<(), Self::Error> { self.events.lock().unwrap().push(event); Ok(()) } }