1use mxr_core::id::SavedSearchId;
2use mxr_core::types::SavedSearch;
3use mxr_store::Store;
4use std::sync::Arc;
5
6pub struct SavedSearchService {
7 store: Arc<Store>,
8}
9
10impl SavedSearchService {
11 pub fn new(store: Arc<Store>) -> Self {
12 Self { store }
13 }
14
15 pub async fn create(&self, search: &SavedSearch) -> Result<(), mxr_core::MxrError> {
16 self.store
17 .insert_saved_search(search)
18 .await
19 .map_err(|e| mxr_core::MxrError::Store(e.to_string()))
20 }
21
22 pub async fn list(&self) -> Result<Vec<SavedSearch>, mxr_core::MxrError> {
23 self.store
24 .list_saved_searches()
25 .await
26 .map_err(|e| mxr_core::MxrError::Store(e.to_string()))
27 }
28
29 pub async fn delete(&self, id: &SavedSearchId) -> Result<(), mxr_core::MxrError> {
30 self.store
31 .delete_saved_search(id)
32 .await
33 .map_err(|e| mxr_core::MxrError::Store(e.to_string()))
34 }
35
36 pub async fn get_by_name(&self, name: &str) -> Result<Option<SavedSearch>, mxr_core::MxrError> {
37 let searches = self.list().await?;
38 Ok(searches.into_iter().find(|s| s.name == name))
39 }
40}
41
42#[cfg(test)]
43mod tests {
44 use super::*;
45 use mxr_core::types::SortOrder;
46
47 fn make_saved_search(name: &str, query: &str) -> SavedSearch {
48 SavedSearch {
49 id: SavedSearchId::new(),
50 account_id: None,
51 name: name.to_string(),
52 query: query.to_string(),
53 sort: SortOrder::DateDesc,
54 icon: None,
55 position: 0,
56 created_at: chrono::Utc::now(),
57 }
58 }
59
60 #[tokio::test]
61 async fn saved_create_list_delete() {
62 let store = Arc::new(Store::in_memory().await.unwrap());
63 let svc = SavedSearchService::new(store);
64
65 let search = make_saved_search("Unread from Alice", "from:alice is:unread");
66 svc.create(&search).await.unwrap();
67
68 let list = svc.list().await.unwrap();
69 assert_eq!(list.len(), 1);
70 assert_eq!(list[0].name, "Unread from Alice");
71
72 svc.delete(&search.id).await.unwrap();
73 let list = svc.list().await.unwrap();
74 assert_eq!(list.len(), 0);
75 }
76
77 #[tokio::test]
78 async fn saved_get_by_name() {
79 let store = Arc::new(Store::in_memory().await.unwrap());
80 let svc = SavedSearchService::new(store);
81
82 let search = make_saved_search("Important", "is:starred");
83 svc.create(&search).await.unwrap();
84
85 let found = svc.get_by_name("Important").await.unwrap();
86 assert!(found.is_some());
87 assert_eq!(found.unwrap().query, "is:starred");
88
89 let not_found = svc.get_by_name("Nonexistent").await.unwrap();
90 assert!(not_found.is_none());
91 }
92
93 #[tokio::test]
94 async fn saved_duplicate_names_allowed() {
95 let store = Arc::new(Store::in_memory().await.unwrap());
96 let svc = SavedSearchService::new(store);
97
98 let s1 = make_saved_search("Inbox", "label:inbox");
99 let s2 = make_saved_search("Inbox", "label:inbox is:unread");
100 svc.create(&s1).await.unwrap();
101 svc.create(&s2).await.unwrap();
102
103 let list = svc.list().await.unwrap();
104 assert_eq!(list.len(), 2);
105 }
106}