rootle_github/client/
search.rs1use super::{API, GitHubClient, urlencoding};
4use crate::types::{OrgRepoItem, SearchReposResponse, SearchUsersResponse};
5use rootle_provider::{ErrorKind, ProviderError, ProviderResult, SearchItem};
6
7impl GitHubClient {
8 pub fn search(&self, query: &str) -> ProviderResult<Vec<SearchItem>> {
11 let q = urlencoding(query);
12 let mut out = Vec::new();
13
14 let orgs: SearchUsersResponse =
15 self.get(&format!("{API}/search/users?q={q}+type:org&per_page=5"))?;
16 out.extend(orgs.items.into_iter().map(|u| SearchItem::Org(u.login)));
17
18 let repos: SearchReposResponse =
19 self.get(&format!("{API}/search/repositories?q={q}&per_page=20"))?;
20 out.extend(
21 repos
22 .items
23 .into_iter()
24 .map(|r| SearchItem::Repo(r.full_name)),
25 );
26
27 Ok(out)
28 }
29
30 pub fn org_repos(&self, org: &str) -> ProviderResult<Vec<rootle_provider::RepoInfo>> {
31 let repos: Vec<OrgRepoItem> =
32 self.get(&format!("{API}/orgs/{org}/repos?per_page=100&sort=updated"))?;
33 Ok(repos
34 .into_iter()
35 .map(|r| rootle_provider::RepoInfo {
36 name: r.name,
37 description: r.description,
38 private: r.private,
39 archived: r.archived,
40 pushed_at: r.pushed_at,
41 })
42 .collect())
43 }
44
45 pub fn search_code(&self, q: &str) -> ProviderResult<(Vec<crate::types::CodeItem>, bool)> {
50 let (items, total) = self.search_code_page(q, 1)?;
51 Ok((items, total > 1000))
54 }
55
56 pub fn search_code_page(
60 &self,
61 q: &str,
62 page: u32,
63 ) -> ProviderResult<(Vec<crate::types::CodeItem>, u64)> {
64 if self.is_anonymous() {
65 return Err(ProviderError::new(
66 ErrorKind::Auth,
67 "code search needs a token — set ROOTLE_TOKEN or log in with `gh`",
68 ));
69 }
70 let url = format!(
71 "{API}/search/code?q={}&per_page=100&page={page}",
72 urlencoding(q)
73 );
74 let resp: crate::types::SearchCodeResponse =
75 self.get_accept(&url, "application/vnd.github.text-match+json")?;
76 Ok((resp.items, resp.total_count))
77 }
78}