coman/core/
endpoint_ops.rs

1use std::collections::HashMap;
2
3use crate::{
4    core::{
5        errors::{CollectionError, CollectionResult},
6        utils::merge_headers,
7    },
8    Collection, CollectionManager, Method, Request,
9};
10
11impl CollectionManager {
12    /// Get a specific endpoint from a collection
13    pub fn get_endpoint(&self, collection: &str, endpoint: &str) -> CollectionResult<Request> {
14        let col = self.get_collection(collection)?;
15        col.requests
16            .and_then(|requests| requests.into_iter().find(|r| r.name == endpoint))
17            .ok_or_else(|| CollectionError::EndpointNotFound(endpoint.to_string()))
18    }
19
20    /// Get the full URL for an endpoint (base URL + endpoint path)
21    pub fn get_endpoint_url(&self, collection: &str, endpoint: &str) -> CollectionResult<String> {
22        let col = self.get_collection(collection)?;
23        let req = self.get_endpoint(collection, endpoint)?;
24        Ok(format!("{}{}", col.url, req.endpoint))
25    }
26
27    /// Get merged headers for an endpoint (collection headers + endpoint headers)
28    pub fn get_endpoint_headers(
29        &self,
30        collection: &str,
31        endpoint: &str,
32    ) -> CollectionResult<Vec<(String, String)>> {
33        let col = self.get_collection(collection)?;
34        let req = self.get_endpoint(collection, endpoint)?;
35
36        let mut merged: HashMap<String, String> = HashMap::new();
37        for (k, v) in &col.headers {
38            merged.insert(k.clone(), v.clone());
39        }
40        for (k, v) in &req.headers {
41            merged.insert(k.clone(), v.clone());
42        }
43
44        Ok(merged.into_iter().collect())
45    }
46
47    /// Add an endpoint to a collection
48    ///
49    /// If an endpoint with the same name exists, it will be updated.
50    pub fn add_endpoint(
51        &self,
52        collection: &str,
53        name: &str,
54        path: &str,
55        method: Method,
56        headers: Vec<(String, String)>,
57        body: Option<String>,
58    ) -> CollectionResult<()> {
59        let mut collections = self.load_collections()?;
60
61        let col = collections
62            .iter_mut()
63            .find(|c| c.name == collection)
64            .ok_or_else(|| CollectionError::CollectionNotFound(collection.to_string()))?;
65
66        let request = Request {
67            name: name.to_string(),
68            endpoint: path.to_string(),
69            method,
70            headers,
71            body,
72        };
73
74        let mut requests = col.requests.clone().unwrap_or_default();
75        requests.retain(|r| r.name != name);
76        requests.push(request);
77        col.requests = Some(requests);
78
79        self.save_collections(&collections)
80    }
81
82    /// Update an endpoint in a collection
83    pub fn update_endpoint(
84        &self,
85        collection: &str,
86        endpoint: &str,
87        path: Option<&str>,
88        headers: Option<Vec<(String, String)>>,
89        body: Option<String>,
90    ) -> CollectionResult<()> {
91        let mut collections = self.load_collections()?;
92
93        let col = collections
94            .iter_mut()
95            .find(|c| c.name == collection)
96            .ok_or_else(|| CollectionError::CollectionNotFound(collection.to_string()))?;
97
98        if let Some(requests) = col.requests.as_mut() {
99            let req = requests
100                .iter_mut()
101                .find(|r| r.name == endpoint)
102                .ok_or_else(|| CollectionError::EndpointNotFound(endpoint.to_string()))?;
103
104            if let Some(path) = path {
105                req.endpoint = path.to_string();
106            }
107
108            if let Some(new_headers) = headers {
109                req.headers = merge_headers(req.headers.clone(), &new_headers);
110            }
111
112            if let Some(new_body) = body {
113                req.body = if new_body.is_empty() {
114                    None
115                } else {
116                    Some(new_body)
117                };
118            }
119        } else {
120            return Err(CollectionError::EndpointNotFound(endpoint.to_string()));
121        }
122
123        self.save_collections(&collections)
124    }
125
126    /// Copy an endpoint within the same collection or to another collection
127    pub fn copy_endpoint(
128        &self,
129        collection: &str,
130        endpoint: &str,
131        new_name: &str,
132        to_collection: Option<&str>,
133    ) -> CollectionResult<()> {
134        let mut collections = self.load_collections()?;
135
136        // Find the source endpoint
137        let source_col = collections
138            .iter()
139            .find(|c| c.name == collection)
140            .ok_or_else(|| CollectionError::CollectionNotFound(collection.to_string()))?;
141
142        let source_req = source_col
143            .requests
144            .as_ref()
145            .and_then(|r| r.iter().find(|r| r.name == endpoint))
146            .ok_or_else(|| CollectionError::EndpointNotFound(endpoint.to_string()))?;
147
148        let mut new_req = source_req.clone();
149
150        if let Some(target_col_name) = to_collection {
151            // Copy to another collection (keep original name)
152            let target_col = collections
153                .iter_mut()
154                .find(|c| c.name == target_col_name)
155                .ok_or_else(|| CollectionError::CollectionNotFound(target_col_name.to_string()))?;
156
157            let mut requests = target_col.requests.clone().unwrap_or_default();
158            requests.push(new_req);
159            target_col.requests = Some(requests);
160        } else {
161            // Copy within the same collection with a new name
162            new_req.name = new_name.to_string();
163
164            let col = collections
165                .iter_mut()
166                .find(|c| c.name == collection)
167                .ok_or_else(|| CollectionError::CollectionNotFound(collection.to_string()))?;
168
169            let mut requests = col.requests.clone().unwrap_or_default();
170            requests.push(new_req);
171            col.requests = Some(requests);
172        }
173
174        self.save_collections(&collections)
175    }
176
177    /// Delete an endpoint from a collection
178    pub fn delete_endpoint(&self, collection: &str, endpoint: &str) -> CollectionResult<()> {
179        let mut collections = self.load_collections()?;
180
181        let col = collections
182            .iter_mut()
183            .find(|c| c.name == collection)
184            .ok_or_else(|| CollectionError::CollectionNotFound(collection.to_string()))?;
185
186        if let Some(requests) = col.requests.as_mut() {
187            let original_len = requests.len();
188            requests.retain(|r| r.name != endpoint);
189
190            if requests.len() == original_len {
191                return Err(CollectionError::EndpointNotFound(endpoint.to_string()));
192            }
193        } else {
194            return Err(CollectionError::EndpointNotFound(endpoint.to_string()));
195        }
196
197        self.save_collections(&collections)
198    }
199
200    /// List all collections
201    pub fn list_collections(&self) -> CollectionResult<Vec<Collection>> {
202        self.load_collections()
203    }
204}