coman/core/
collection_manager.rs1use std::sync::Arc;
7
8use tokio::sync::Mutex;
9
10use crate::core::errors::CollectionError;
11use crate::models::collection::Collection;
12use crate::{helper, Request};
13
14pub type CollectionResult<T> = Result<T, CollectionError>;
16
17#[derive(Clone)]
21pub struct CollectionManager {
22 in_memory: bool,
23 file_path: Option<String>,
24 loaded_collections: Arc<Mutex<Vec<Collection>>>,
25}
26
27impl Default for CollectionManager {
28 fn default() -> Self {
29 Self::new(None, false)
30 }
31}
32
33impl CollectionManager {
34 pub fn new(file_path: Option<String>, in_memory: bool) -> Self {
40 if let Some(ref path) = file_path {
41 std::env::set_var("COMAN_JSON", path);
42 }
43 Self {
44 in_memory,
45 file_path,
46 loaded_collections: if in_memory {
47 Arc::new(Mutex::new(Vec::new()))
48 } else {
49 Self::load_collections_from_file()
50 .unwrap_or_else(|_| Arc::new(Mutex::new(Vec::new())))
51 },
52 }
53 }
54
55 pub fn get_file_path(&self) -> String {
57 self.file_path
58 .clone()
59 .unwrap_or_else(|| helper::get_file_path().to_string())
60 }
61
62 fn load_collections_from_file() -> CollectionResult<Arc<Mutex<Vec<Collection>>>> {
64 match helper::read_json_from_file::<Vec<Collection>>() {
65 Ok(c) => Ok(Arc::new(Mutex::new(c))),
66 Err(e) => {
67 if let Some(io_err) = e.downcast_ref::<std::io::Error>() {
68 if io_err.kind() == std::io::ErrorKind::NotFound {
69 Ok(Arc::new(Mutex::new(Vec::new())))
70 } else {
71 Err(CollectionError::Other(e.to_string()))
72 }
73 } else {
74 Err(CollectionError::Other(e.to_string()))
75 }
76 }
77 }
78 }
79
80 pub async fn get_collections(&self) -> Vec<Collection> {
82 let collections = self.loaded_collections.lock().await;
83 collections.clone()
84 }
85
86 pub async fn get_collection(&self, name: &str) -> CollectionResult<Option<Collection>> {
88 let collections = self.loaded_collections.lock().await;
89 for c in collections.iter() {
90 if c.name == name {
91 return Ok(Some(c.clone()));
92 }
93 }
94 Err(CollectionError::CollectionNotFound(name.to_string()))
95 }
96
97 pub async fn get_endpoint(
99 &self,
100 col_name: &str,
101 ep_name: &str,
102 ) -> CollectionResult<Option<Request>> {
103 let collections = self.loaded_collections.lock().await;
104 for c in collections.iter() {
105 if c.name == col_name {
106 if let Some(ref requests) = c.requests {
107 for r in requests.iter() {
108 if r.name == ep_name {
109 return Ok(Some(r.clone()));
110 }
111 }
112 }
113 }
114 }
115 Err(CollectionError::EndpointNotFound(format!(
116 "{} in {}",
117 ep_name, col_name
118 )))
119 }
120
121 pub async fn update_add_collection(&self, updated: Collection) -> CollectionResult<()> {
123 let mut collections = self.loaded_collections.lock().await;
124 if let Some(pos) = collections.iter().position(|c| c.name == updated.name) {
125 collections[pos] = updated;
126 if !self.in_memory {
127 helper::write_json_to_file(&*collections)?;
128 }
129 Ok(())
130 } else {
131 collections.push(updated);
132 if !self.in_memory {
133 helper::write_json_to_file(&*collections)?;
134 }
135 Ok(())
136 }
137 }
138
139 pub async fn update_add_request(
141 &self,
142 col_name: &str,
143 ep_name: &str,
144 updated: Request,
145 ) -> CollectionResult<()> {
146 let mut collections = self.loaded_collections.lock().await;
147 if let Some(col_pos) = collections.iter().position(|c| c.name == col_name) {
148 if let Some(ref mut requests) = collections[col_pos].requests {
149 if let Some(req_pos) = requests.iter().position(|r| r.name == ep_name) {
150 requests[req_pos] = updated;
151 if !self.in_memory {
152 helper::write_json_to_file(&*collections)?;
153 }
154 return Ok(());
155 } else {
156 requests.push(updated);
157 if !self.in_memory {
158 helper::write_json_to_file(&*collections)?;
159 }
160 return Ok(());
161 }
162 } else {
163 collections[col_pos].requests = Some(vec![updated]);
164 if !self.in_memory {
165 helper::write_json_to_file(&*collections)?;
166 }
167 return Ok(());
168 }
169 }
170 Err(CollectionError::CollectionNotFound(col_name.to_string()))
171 }
172
173 pub async fn delete_collection(&self, name: &str) -> CollectionResult<()> {
175 match self.get_collection(name).await {
176 Ok(_) => {
177 let mut collections = self.loaded_collections.lock().await;
178 collections.retain(|c| c.name != name);
179 if !self.in_memory {
180 helper::write_json_to_file(&*collections)?;
181 }
182 Ok(())
183 }
184 Err(_) => Err(CollectionError::CollectionNotFound(name.to_string())),
185 }
186 }
187
188 pub async fn save_loaded_collections(self) -> CollectionResult<()> {
190 if !self.in_memory {
191 let collections = self.loaded_collections.lock().await;
192 helper::write_json_to_file(&*collections)?;
193 }
194 Ok(())
195 }
196}
197
198#[cfg(test)]
199mod tests {
200
201 use super::*;
202 use serial_test::serial;
203
204 fn setup_test_manager() -> CollectionManager {
205 std::env::set_var("COMAN_JSON", "test.json");
206 CollectionManager::new(Some("test.json".to_string()), false)
207 }
208
209 #[tokio::test]
210 #[serial]
211 async fn test_load_collections() {
212 let manager = setup_test_manager();
213 let result = manager.get_collections().await;
214 assert!(!result.is_empty());
215 }
216
217 #[tokio::test]
218 #[serial]
219 async fn test_get_collection() {
220 let manager = setup_test_manager();
221
222 let result = manager.get_collection("coman").await;
223
224 assert!(result.is_ok());
225 }
226
227 #[tokio::test]
228 #[serial]
229 async fn test_save_collections() {
230 let manager = setup_test_manager();
231
232 let result = manager.save_loaded_collections().await;
233 assert!(result.is_ok());
234 }
235}