Skip to main content

lastfm_client/
url_builder.rs

1use std::collections::HashMap;
2
3/// Query parameter map for URL construction
4pub type QueryParams = HashMap<String, String>;
5
6/// URL builder for constructing API request URLs
7#[derive(Debug, Clone)]
8pub struct Url {
9    base: String,
10    query_params: QueryParams,
11}
12
13impl Url {
14    /// Create a new URL builder with the given base URL
15    #[must_use]
16    pub fn new(base: &str) -> Self {
17        Self {
18            base: base.to_string(),
19            query_params: HashMap::new(),
20        }
21    }
22
23    /// Add query parameters to the URL
24    #[must_use]
25    pub fn add_args(mut self, args: QueryParams) -> Self {
26        self.query_params.extend(args);
27
28        self
29    }
30
31    /// Build the final URL string with all query parameters
32    #[must_use]
33    pub fn build(&self) -> String {
34        if self.query_params.is_empty() {
35            return self.base.clone();
36        }
37
38        let query_string: Vec<String> = self
39            .query_params
40            .iter()
41            .map(|(k, v)| format!("{k}={v}"))
42            .collect();
43
44        format!("{}?{}", self.base, query_string.join("&"))
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51
52    #[test]
53    fn test_basic_url() {
54        let url = Url::new("https://www.google.com");
55        assert_eq!(url.build(), "https://www.google.com");
56    }
57
58    #[test]
59    fn test_single_query_param() {
60        let mut params = HashMap::new();
61        params.insert("q".to_string(), "rust".to_string());
62
63        let url = Url::new("https://www.google.com").add_args(params);
64        assert_eq!(url.build(), "https://www.google.com?q=rust");
65    }
66
67    #[test]
68    fn test_multiple_query_params() {
69        let mut params = HashMap::new();
70        params.insert("q".to_string(), "rust".to_string());
71        params.insert("lang".to_string(), "en".to_string());
72
73        let url = Url::new("https://www.google.com").add_args(params);
74        let built_url = url.build();
75        assert!(
76            built_url == "https://www.google.com?q=rust&lang=en"
77                || built_url == "https://www.google.com?lang=en&q=rust"
78        );
79    }
80
81    #[test]
82    fn test_chained_param_addition() {
83        let url = Url::new("https://www.example.com")
84            .add_args(HashMap::from([("page".to_string(), "1".to_string())]))
85            .add_args(HashMap::from([("limit".to_string(), "10".to_string())]));
86
87        let built_url = url.build();
88        assert!(
89            built_url == "https://www.example.com?page=1&limit=10"
90                || built_url == "https://www.example.com?limit=10&page=1"
91        );
92    }
93
94    #[test]
95    fn test_param_overwrite() {
96        let mut params1 = HashMap::new();
97        params1.insert("key".to_string(), "value1".to_string());
98
99        let mut params2 = HashMap::new();
100        params2.insert("key".to_string(), "value2".to_string());
101
102        let url = Url::new("https://www.example.com")
103            .add_args(params1)
104            .add_args(params2);
105
106        assert_eq!(url.build(), "https://www.example.com?key=value2");
107    }
108}