1use std::collections::HashMap;
2use std::fmt;
3
4use serde::Deserialize;
5use url::form_urlencoded;
6
7use super::{Search, SearchResult};
8use crate::users::User;
9use crate::{Future, SortDirection, Stream};
10
11#[derive(Clone, Copy, Debug, PartialEq)]
12pub enum ReposSort {
13 Stars,
15 Forks,
17 Updated,
19}
20
21impl fmt::Display for ReposSort {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 match *self {
24 ReposSort::Stars => "stars",
25 ReposSort::Forks => "forks",
26 ReposSort::Updated => "updated",
27 }
28 .fmt(f)
29 }
30}
31
32pub struct SearchRepos {
35 search: Search,
36}
37
38impl SearchRepos {
39 #[doc(hidden)]
40 pub fn new(search: Search) -> Self {
41 Self { search }
42 }
43
44 fn search_uri<Q>(&self, q: Q, options: &SearchReposOptions) -> String
45 where
46 Q: Into<String>,
47 {
48 let mut uri = vec!["/search/repositories".to_string()];
49 let query_options = options.serialize().unwrap_or_default();
50 let query = form_urlencoded::Serializer::new(query_options)
51 .append_pair("q", &q.into())
52 .finish();
53
54 uri.push(query);
55 uri.join("?")
56 }
57
58 pub fn iter<Q>(&self, q: Q, options: &SearchReposOptions) -> Stream<ReposItem>
62 where
63 Q: Into<String>,
64 {
65 self.search.iter::<ReposItem>(&self.search_uri(q, options))
66 }
67
68 pub fn list<Q>(&self, q: Q, options: &SearchReposOptions) -> Future<SearchResult<ReposItem>>
72 where
73 Q: Into<String>,
74 {
75 self.search
76 .search::<ReposItem>(&self.search_uri(q, options))
77 }
78}
79
80#[derive(Default)]
81pub struct SearchReposOptions {
82 params: HashMap<&'static str, String>,
83}
84
85impl SearchReposOptions {
86 pub fn builder() -> SearchReposOptionsBuilder {
87 SearchReposOptionsBuilder::default()
88 }
89
90 pub fn serialize(&self) -> Option<String> {
91 if self.params.is_empty() {
92 None
93 } else {
94 let encoded: String = form_urlencoded::Serializer::new(String::new())
95 .extend_pairs(&self.params)
96 .finish();
97 Some(encoded)
98 }
99 }
100}
101
102#[derive(Default)]
103pub struct SearchReposOptionsBuilder(SearchReposOptions);
104
105impl SearchReposOptionsBuilder {
106 pub fn per_page(&mut self, n: usize) -> &mut Self {
107 self.0.params.insert("per_page", n.to_string());
108 self
109 }
110
111 pub fn sort(&mut self, sort: ReposSort) -> &mut Self {
112 self.0.params.insert("sort", sort.to_string());
113 self
114 }
115
116 pub fn order(&mut self, direction: SortDirection) -> &mut Self {
117 self.0.params.insert("order", direction.to_string());
118 self
119 }
120
121 pub fn build(&self) -> SearchReposOptions {
122 SearchReposOptions {
123 params: self.0.params.clone(),
124 }
125 }
126}
127
128#[derive(Debug, Deserialize)]
129pub struct ReposItem {
130 pub id: u32,
131 pub name: String,
132 pub full_name: String,
133 pub owner: User,
134 pub private: bool,
135 pub html_url: String,
136 pub description: String,
137 pub fork: bool,
138 pub url: String,
139 pub forks_url: String,
140 pub keys_url: String,
141 pub collaborators_url: String,
142 pub teams_url: String,
143 pub hooks_url: String,
144 pub issue_events_url: String,
145 pub events_url: String,
146 pub assignees_url: String,
147 pub branches_url: String,
148 pub tags_url: String,
149 pub blobs_url: String,
150 pub git_tags_url: String,
151 pub git_refs_url: String,
152 pub trees_url: String,
153 pub statuses_url: String,
154 pub languages_url: String,
155 pub stargazers_url: String,
156 pub contributors_url: String,
157 pub subscribers_url: String,
158 pub subscription_url: String,
159 pub commits_url: String,
160 pub git_commits_url: String,
161 pub comments_url: String,
162 pub issue_comment_url: String,
163 pub contents_url: String,
164 pub compare_url: String,
165 pub merges_url: String,
166 pub archive_url: String,
167 pub downloads_url: String,
168 pub issues_url: String,
169 pub pulls_url: String,
170 pub milestones_url: String,
171 pub notifications_url: String,
172 pub labels_url: String,
173 pub releases_url: String,
174 pub deployments_url: String,
175 pub created_at: String,
176 pub updated_at: String,
177 pub pushed_at: String,
178 pub git_url: String,
179 pub ssh_url: String,
180 pub clone_url: String,
181 pub svn_url: String,
182 pub homepage: String,
183 pub size: u32,
184 pub stargazers_count: u32,
185 pub watchers_count: u32,
186 pub language: String,
187 pub has_issues: bool,
188 pub has_projects: bool,
189 pub has_downloads: bool,
190 pub has_wiki: bool,
191 pub has_pages: bool,
192 pub forks_count: u32,
193 pub mirror_url: Option<String>,
194 pub archived: bool,
195 pub open_issues_count: u32,
196 pub license: License,
197 pub forks: u32,
198 pub open_issues: u32,
199 pub watchers: u32,
200 pub default_branch: String,
201 pub score: f64,
202}
203
204#[derive(Debug, Deserialize)]
205pub struct License {
206 key: String,
207 name: String,
208 spdx_id: String,
209 url: String,
210}