conduit_cli/core/modrinth/
search.rs1use super::client::ModrinthAPI;
2use super::models::SearchResult;
3use reqwest::Url;
4
5impl ModrinthAPI {
6 pub async fn search(
7 &self,
8 query: &str,
9 limit: i32,
10 offset: i32,
11 index: &str,
12 facets: Option<String>,
13 ) -> Result<SearchResult, reqwest::Error> {
14 let mod_filter = "\"project_type:mod\"";
15
16 let final_facets = match facets {
17 Some(f) => {
18 if f.starts_with('[') && f.ends_with(']') {
19 let inner = &f[1..f.len() - 1];
20 format!("[{inner},[{mod_filter}]]")
21 } else {
22 format!("[[{mod_filter}]]")
23 }
24 }
25 None => format!("[[{mod_filter}]]"),
26 };
27
28 let params = vec![
29 ("query", query.to_string()),
30 ("limit", limit.to_string()),
31 ("offset", offset.to_string()),
32 ("index", index.to_string()),
33 ("facets", final_facets),
34 ];
35
36 let url = Url::parse_with_params(&format!("{}/search", self.base_url), ¶ms)
37 .expect("Critical: Failed to build Modrinth search URL");
38
39 self.client
40 .get(url)
41 .send()
42 .await?
43 .error_for_status()?
44 .json::<SearchResult>()
45 .await
46 }
47
48 pub async fn get_suggestions(&self, input: &str) -> Vec<(String, String)> {
49 let query = input.split('@').next().unwrap_or(input);
50
51 match self.search(query, 5, 0, "relevance", None).await {
52 Ok(results) => results
53 .hits
54 .into_iter()
55 .map(|hit| (hit.title, hit.slug))
56 .collect(),
57 Err(_) => Vec::new(),
58 }
59 }
60}