coman/core/
collection_manager.rs

1//! Collection Manager - Core business logic for managing API collections
2//!
3//! This module provides a clean API for managing collections and endpoints
4//! without any CLI dependencies.
5
6use crate::core::errors::CollectionError;
7use crate::models::collection::Collection;
8use crate::{helper, Request};
9
10/// Result type for collection operations
11pub type CollectionResult<T> = Result<T, CollectionError>;
12
13/// Manager for API collections
14///
15/// Provides methods for CRUD operations on collections and endpoints.
16#[derive(Clone)]
17pub struct CollectionManager {
18    in_memory: bool,
19    file_path: Option<String>,
20    pub loaded_collections: Option<Vec<Collection>>,
21}
22
23impl Default for CollectionManager {
24    fn default() -> Self {
25        Self::new(None, false)
26    }
27}
28
29impl CollectionManager {
30    /// Create a new CollectionManager
31    ///
32    /// # Arguments
33    ///
34    /// * `file_path` - Optional custom file path. If None, uses default location.
35    pub fn new(file_path: Option<String>, in_memory: bool) -> Self {
36        if let Some(ref path) = file_path {
37            std::env::set_var("COMAN_JSON", path);
38        }
39        Self {
40            in_memory,
41            file_path,
42            loaded_collections: if in_memory {
43                Some(Vec::new())
44            } else {
45                Self::load_collections_from_file().ok()
46            },
47        }
48    }
49
50    /// Get the file path being used
51    pub fn get_file_path(&self) -> String {
52        self.file_path
53            .clone()
54            .unwrap_or_else(|| helper::get_file_path().to_string())
55    }
56
57    /// Load all collections from the storage file
58    fn load_collections_from_file() -> CollectionResult<Vec<Collection>> {
59        match helper::read_json_from_file::<Vec<Collection>>() {
60            Ok(c) => Ok(c),
61            Err(e) => {
62                if let Some(io_err) = e.downcast_ref::<std::io::Error>() {
63                    if io_err.kind() == std::io::ErrorKind::NotFound {
64                        Ok(Vec::new())
65                    } else {
66                        Err(CollectionError::Other(e.to_string()))
67                    }
68                } else {
69                    Err(CollectionError::Other(e.to_string()))
70                }
71            }
72        }
73    }
74
75    /// Get a specific collection by name
76    pub fn get_collection(&mut self, name: &str) -> CollectionResult<&mut Collection> {
77        match &mut self.loaded_collections {
78            Some(cols) => cols
79                .iter_mut()
80                .find(|c| c.name == name)
81                .ok_or_else(|| CollectionError::CollectionNotFound(name.to_string())),
82            None => Err(CollectionError::CollectionNotFound(name.to_string())),
83        }
84    }
85
86    /// Get a specific collection imutable by name
87    pub fn get_collection_imutable(&self, name: &str) -> CollectionResult<&Collection> {
88        match &self.loaded_collections {
89            Some(cols) => cols
90                .iter()
91                .find(|c| c.name == name)
92                .ok_or_else(|| CollectionError::CollectionNotFound(name.to_string())),
93            None => Err(CollectionError::CollectionNotFound(name.to_string())),
94        }
95    }
96
97    /// Get a specific endpoint from a collection
98    pub fn get_endpoint(&mut self, col_name: &str, ep_name: &str) -> CollectionResult<Request> {
99        let col = self.get_collection(col_name)?;
100        col.get_request(ep_name)
101            .ok_or_else(|| CollectionError::EndpointNotFound(ep_name.to_string()))
102    }
103
104    /// Save collections to the storage file
105    pub fn save_collections(self) -> CollectionResult<()> {
106        if !self.in_memory {
107            if let Some(collections) = self.loaded_collections {
108                helper::write_json_to_file(&collections)?;
109                Ok(())
110            } else {
111                Err(CollectionError::Other(
112                    "No collections loaded to save".to_string(),
113                ))
114            }
115        } else {
116            Ok(())
117        }
118    }
119}
120
121#[cfg(test)]
122mod tests {
123
124    use super::*;
125    use serial_test::serial;
126
127    fn setup_test_manager() -> CollectionManager {
128        std::env::set_var("COMAN_JSON", "test.json");
129        CollectionManager::new(Some("test.json".to_string()), false)
130    }
131
132    #[test]
133    #[serial]
134    fn test_load_collections() {
135        let manager = setup_test_manager();
136        let result = manager.loaded_collections;
137        assert!(result.is_some());
138    }
139
140    #[test]
141    #[serial]
142    fn test_get_collection() {
143        let mut manager = setup_test_manager();
144
145        let result = manager.get_collection("coman");
146
147        assert!(result.is_ok());
148    }
149
150    #[test]
151    #[serial]
152    fn test_save_collections() {
153        let manager = setup_test_manager();
154
155        let result = manager.save_collections();
156        assert!(result.is_ok());
157    }
158}