github_stats/search/
query.rs1use std::fmt;
2
3use crate::Repo;
4
5#[derive(Default)]
6pub struct Query {
7 author: Vec<String>,
8 repo: Vec<String>,
9 repos: Vec<String>,
10 is: Vec<String>,
11 r#in: Vec<In>,
12 assignee: Vec<String>,
13 user: Vec<String>,
14 org: Vec<String>,
15 fullname: Vec<FullName>,
16 label: Vec<String>,
17 r#type: Vec<String>,
18 state: Vec<String>,
19 no: Vec<String>,
20 language: Vec<String>,
21}
22
23impl Query {
24 pub fn new() -> Self {
25 Query {
26 ..Default::default()
27 }
28 }
29
30 pub fn from_repo(repo: Repo) -> Self {
31 let repo = vec![String::from(repo.full_name())];
32 Query {
33 repo,
34 ..Default::default()
35 }
36 }
37
38 pub fn author(mut self, username: &str) -> Self {
42 self.author.push(username.to_owned());
43 self
44 }
45
46 pub fn repo(mut self, user: &str, repo: &str) -> Self {
50 self.repo.push(format!("{}/{}", user, repo));
51 self
52 }
53
54 pub fn repos(mut self, n: &str) -> Self {
60 self.repos.push(n.to_owned());
62 self
63 }
64
65 pub fn is(mut self, statement: &str) -> Self {
69 self.is.push(String::from(statement));
70 self
71 }
72
73 pub fn r#in(mut self, keyword: &str, field: &str) -> Self {
77 self.r#in.push(In(String::from(keyword), String::from(field)));
78 self
79 }
80
81 pub fn assignee(mut self, username: &str) -> Self {
85 self.assignee.push(username.to_owned());
86 self
87 }
88
89 pub fn user(mut self, statement: &str) -> Self {
93 self.user.push(String::from(statement));
94 self
95 }
96
97 pub fn org(mut self, statement: &str) -> Self {
101 self.org.push(String::from(statement));
102 self
103 }
104
105 pub fn fullname(mut self, first_name: &str, last_name: &str) -> Self {
109 self.fullname.push(FullName::new(first_name, last_name));
110 self
111 }
112
113 pub fn label(mut self, statement: &str) -> Self {
117 self.label.push(String::from(statement));
118 self
119 }
120
121 pub fn r#type(mut self, statement: &str) -> Self {
127 self.r#type.push(String::from(statement));
128 self
129 }
130
131 pub fn no(mut self, statement: &str) -> Self {
135 self.no.push(String::from(statement));
136 self
137 }
138
139 pub fn language(mut self, statement: &str) -> Self {
143 self.language.push(String::from(statement));
144 self
145 }
146}
147
148impl fmt::Display for Query {
149 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
150 let queries = {
151 let mut author: Vec<_> = self.author.iter().map(|s| format!("author:{}", s)).collect();
152 let mut repo: Vec<String> = self.repo.iter().map(|s| format!("repo:{}", s)).collect();
153 let mut repos: Vec<String> = self.repos.iter().map(|s| format!("repos:{}", s)).collect();
154 let mut is: Vec<String> = self.is.iter().map(|s| format!("is:{}", s)).collect();
155 let mut r#in: Vec<String> = self.r#in.iter().map(|s| s.to_string()).collect();
156 let mut user: Vec<String> = self.user.iter().map(|s| format!("user:{}", s)).collect();
157 let mut assignee: Vec<String> = self.assignee.iter().map(|s| format!("assignee:{}", s)).collect();
158 let mut org: Vec<String> = self.org.iter().map(|s| format!("org:{}", s)).collect();
159 let mut fullname: Vec<String> = self.fullname.iter().map(|s| s.to_string()).collect();
160 let mut label: Vec<String> = self.label.iter().map(|s| format!("label:{}", s)).collect();
161 let mut r#type: Vec<String> =
162 self.r#type.iter().map(|s| format!("type:{}", s)).collect();
163 let mut state: Vec<String> =
164 self.state.iter().map(|s| format!("state:{}", s)).collect();
165 let mut no: Vec<String> =
166 self.no.iter().map(|s| format!("no:{}", s)).collect();
167 let mut language: Vec<String> =
168 self.language.iter().map(|s| format!("language:{}", s)).collect();
169
170 let mut queries: Vec<String> =
171 Vec::with_capacity(
172 author.len()
173 + repo.len()
174 + repos.len()
175 + is.len()
176 + r#in.len()
177 + assignee.len()
178 + user.len()
179 + org.len()
180 + fullname.len()
181 + label.len()
182 + r#type.len()
183 + state.len()
184 + no.len()
185 + language.len()
186 );
187
188 queries.append(&mut repo);
189 queries.append(&mut repos);
190 queries.append(&mut is);
191 queries.append(&mut r#in);
192 queries.append(&mut author);
193 queries.append(&mut assignee);
194 queries.append(&mut user);
195 queries.append(&mut org);
196 queries.append(&mut fullname);
197 queries.append(&mut label);
198 queries.append(&mut r#type);
199 queries.append(&mut state);
200 queries.append(&mut no);
201 queries.append(&mut language);
202 queries
203 };
204
205 let queries = queries.join("+");
206
207 write!(f, "{}", queries)
208 }
209}
210
211struct In(String, String);
212
213impl fmt::Display for In {
214 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
215 write!(f, "{} in:{}", self.0, self.1)
216 }
217}
218
219struct FullName(String, String);
220
221impl FullName {
222 fn new(first_name: &str, last_name: &str) -> Self {
223 FullName(String::from(first_name), String::from(last_name))
224 }
225}
226
227impl fmt::Display for FullName {
228 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
229 write!(f, "fullname:{} {}", self.0, self.1)
230 }
231}
232
233#[cfg(test)]
234mod tests {
235 use super::*;
236
237 #[test]
238 fn built_query() {
239 let query = Query::new()
240 .repo("rust-lang", "rust")
241 .r#type("pr")
242 .is("merged")
243 .label("hacktoberfest")
244 .no("assignee")
245 .r#in("[BUG]", "name")
246 .assignee("spenserblack")
247 .user("spenserblack")
248 .author("spenserblack")
249 .language("rust")
250 .to_string();
251
252 assert_eq!(
253 "repo:rust-lang/rust+is:merged+[BUG] in:name+author:spenserblack+assignee:spenserblack+user:spenserblack+label:hacktoberfest+type:pr+no:assignee+language:rust",
254 query
255 );
256 }
257
258 #[test]
259 fn org_query() {
260 let query = Query::new()
261 .org("rust-lang")
262 .to_string();
263
264 assert_eq!(
265 "org:rust-lang",
266 query
267 );
268 }
269
270 #[test]
271 fn in_string() {
272 let r#in = In(
273 String::from("Users"),
274 String::from("title"),
275 );
276
277 assert_eq!("Users in:title", r#in.to_string());
278 }
279
280 #[test]
281 fn repos_query() {
282 let query = Query::new()
283 .repos("<0")
284 .to_string();
285
286 assert_eq!("repos:<0", query);
287 }
288
289 #[test]
290 fn fullname_string() {
291 let fullname = FullName::new(
292 "Octo",
293 "Cat",
294 );
295
296 assert_eq!("fullname:Octo Cat", fullname.to_string());
297 }
298}