Skip to main content

auraxis/api/request/
builder.rs

1use reqwest::Client;
2
3use super::{CensusRequest, Filter, FilterType, Join, Sort, SortDirection, Tree};
4
5pub struct CensusRequestBuilder {
6    client: Client,
7    collection: String,
8    url: String,
9    show: Option<Vec<String>>,
10    hide: Option<Vec<String>>,
11    sort: Option<Vec<Sort>>,
12    has: Option<Vec<String>>,
13    resolve: Option<Vec<String>>,
14    case: Option<bool>,
15    limit: Option<u32>,
16    limit_per_db: Option<u32>,
17    start: Option<u32>,
18    include_null: Option<bool>,
19    lang: Option<String>,
20    join: Option<Vec<Join>>,
21    tree: Option<Vec<Tree>>,
22    timing: Option<bool>,
23    exact_match_first: Option<bool>,
24    distinct: Option<String>,
25    retry: Option<bool>,
26    filters: Option<Vec<Filter>>,
27}
28
29impl CensusRequestBuilder {
30    pub fn new(client: Client, collection: String, url: String) -> Self {
31        Self {
32            client,
33            collection,
34            url,
35            show: None,
36            hide: None,
37            sort: None,
38            has: None,
39            resolve: None,
40            case: None,
41            limit: None,
42            limit_per_db: None,
43            start: None,
44            include_null: None,
45            lang: None,
46            join: None,
47            tree: None,
48            timing: None,
49            exact_match_first: None,
50            distinct: None,
51            retry: None,
52            filters: None,
53        }
54    }
55
56    pub fn show(mut self, field: impl Into<String>) -> Self {
57        match &mut self.show {
58            None => {
59                self.show = Some(vec![field.into()]);
60            }
61            Some(show) => {
62                show.push(field.into());
63            }
64        }
65
66        self
67    }
68
69    pub fn hide(mut self, field: impl Into<String>) -> Self {
70        match &mut self.hide {
71            None => {
72                self.hide = Some(vec![field.into()]);
73            }
74            Some(hide) => {
75                hide.push(field.into());
76            }
77        }
78
79        self
80    }
81
82    pub fn sort(mut self, field: impl Into<String>, direction: SortDirection) -> Self {
83        match &mut self.sort {
84            None => {
85                self.sort = Some(vec![Sort {
86                    field: field.into(),
87                    direction,
88                }]);
89            }
90            Some(sort) => {
91                sort.push(Sort {
92                    field: field.into(),
93                    direction,
94                });
95            }
96        }
97
98        self
99    }
100
101    pub fn has(mut self, field: impl Into<String>) -> Self {
102        match &mut self.has {
103            None => {
104                self.has = Some(vec![field.into()]);
105            }
106            Some(has) => {
107                has.push(field.into());
108            }
109        }
110
111        self
112    }
113
114    pub fn resolve(mut self, field: impl Into<String>) -> Self {
115        match &mut self.resolve {
116            None => {
117                self.resolve = Some(vec![field.into()]);
118            }
119            Some(resolve) => {
120                resolve.push(field.into());
121            }
122        }
123
124        self
125    }
126
127    pub fn case(mut self, should_case: bool) -> Self {
128        self.case = Some(should_case);
129
130        self
131    }
132
133    pub fn limit(mut self, limit: u32) -> Self {
134        self.limit = Some(limit);
135
136        self
137    }
138
139    pub fn limit_per_db(mut self, limit_per_db: u32) -> Self {
140        self.limit_per_db = Some(limit_per_db);
141
142        self
143    }
144
145    pub fn start(mut self, start: u32) -> Self {
146        self.start = Some(start);
147
148        self
149    }
150
151    pub fn include_null(mut self, include_null: bool) -> Self {
152        self.include_null = Some(include_null);
153
154        self
155    }
156
157    pub fn lang(mut self, lang: impl Into<String>) -> Self {
158        self.lang = Some(lang.into());
159
160        self
161    }
162
163    pub fn join(mut self, join: Join) -> Self {
164        match &mut self.join {
165            None => {
166                self.join = Some(vec![join]);
167            }
168            Some(joins) => {
169                joins.push(join);
170            }
171        }
172
173        self
174    }
175
176    pub fn tree(mut self, tree: Tree) -> Self {
177        match &mut self.tree {
178            None => {
179                self.tree = Some(vec![tree]);
180            }
181            Some(trees) => {
182                trees.push(tree);
183            }
184        }
185
186        self
187    }
188
189    pub fn timing(mut self, value: bool) -> Self {
190        self.timing = Some(value);
191
192        self
193    }
194
195    pub fn exact_match_first(mut self, value: bool) -> Self {
196        self.exact_match_first = Some(value);
197
198        self
199    }
200
201    pub fn distinct(mut self, field: impl Into<String>) -> Self {
202        self.distinct = Some(field.into());
203
204        self
205    }
206
207    pub fn retry(mut self, value: bool) -> Self {
208        self.retry = Some(value);
209
210        self
211    }
212
213    pub fn filter(
214        mut self,
215        field: impl Into<String>,
216        filter: FilterType,
217        value: impl Into<String>,
218    ) -> Self {
219        let filter = Filter {
220            field: field.into(),
221            filter,
222            value: value.into(),
223        };
224
225        match &mut self.filters {
226            None => {
227                self.filters = Some(vec![filter]);
228            }
229            Some(filters) => {
230                filters.push(filter);
231            }
232        }
233
234        self
235    }
236
237    pub fn build(self) -> CensusRequest {
238        let mut query_params = Vec::new();
239
240        match self.filters {
241            None => {}
242            Some(filters) => {
243                for filter in filters {
244                    query_params.push(filter.into_pair());
245                }
246            }
247        }
248
249        match self.show {
250            None => {}
251            Some(show) => {
252                let fields = show.join(",");
253                query_params.push(("c:show".to_string(), fields));
254            }
255        }
256
257        match self.hide {
258            None => {}
259            Some(hide) => {
260                let fields = hide.join(",");
261                query_params.push(("c:hide".to_string(), fields));
262            }
263        }
264
265        match self.sort {
266            None => {}
267            Some(sort) => {
268                let fields: String = sort
269                    .iter()
270                    .map(|field_sort| {
271                        format!(
272                            "{}:{}",
273                            field_sort.field,
274                            <SortDirection as Into<&'static str>>::into(
275                                field_sort.direction.clone()
276                            )
277                        )
278                    })
279                    .collect::<Vec<String>>()
280                    .join(",");
281
282                query_params.push(("c:sort".to_string(), fields));
283            }
284        }
285
286        match self.has {
287            None => {}
288            Some(has) => {
289                query_params.push(("c:has".to_string(), has.join(",")));
290            }
291        }
292
293        match self.resolve {
294            None => {}
295            Some(resolve) => {
296                query_params.push(("c:resolve".to_string(), resolve.join(",")));
297            }
298        }
299
300        match self.case {
301            None => {}
302            Some(case) => {
303                query_params.push(("c:case".to_string(), case.to_string()));
304            }
305        }
306
307        match self.limit {
308            None => {}
309            Some(limit) => {
310                query_params.push(("c:limit".to_string(), limit.to_string()));
311            }
312        }
313
314        match self.limit_per_db {
315            None => {}
316            Some(limit_per_db) => {
317                query_params.push(("c:limitPerDB".to_string(), limit_per_db.to_string()));
318            }
319        }
320
321        match self.start {
322            None => {}
323            Some(start) => {
324                query_params.push(("c:start".to_string(), start.to_string()));
325            }
326        }
327
328        match self.include_null {
329            None => {}
330            Some(include_null) => {
331                query_params.push(("c:includeNull".to_string(), include_null.to_string()));
332            }
333        }
334
335        match self.lang {
336            None => {}
337            Some(lang) => {
338                query_params.push(("c:lang".to_string(), lang));
339            }
340        }
341
342        match self.timing {
343            None => {}
344            Some(timing) => {
345                query_params.push(("c:timing".to_string(), timing.to_string()));
346            }
347        }
348
349        match self.exact_match_first {
350            None => {}
351            Some(exact_match_first) => {
352                query_params.push((
353                    "c:exactMatchFirst".to_string(),
354                    exact_match_first.to_string(),
355                ));
356            }
357        }
358
359        match self.distinct {
360            None => {}
361            Some(distinct) => {
362                query_params.push(("c:distinct".to_string(), distinct));
363            }
364        }
365
366        match self.retry {
367            None => {}
368            Some(retry) => {
369                query_params.push(("c:retry".to_string(), retry.to_string()));
370            }
371        }
372
373        match self.join {
374            None => {}
375            Some(joins) => {
376                let joins: Vec<String> = joins.iter().map(|join| join.into()).collect();
377
378                query_params.push(("c:join".to_string(), joins.join(",")));
379            }
380        }
381
382        // TODO: Add tree
383
384        CensusRequest {
385            client: self.client,
386            collection: self.collection,
387            url: self.url,
388            query_params,
389        }
390    }
391}
392
393#[cfg(test)]
394mod tests {
395    use reqwest::Client;
396
397    use super::CensusRequestBuilder;
398    use crate::api::request::FilterType;
399
400    #[test]
401    fn build_stores_query_params_for_encoded_request_building() {
402        let request = CensusRequestBuilder::new(
403            Client::new(),
404            "character".to_string(),
405            "https://example.com/get/ps2:v2/character".to_string(),
406        )
407        .show("name.first")
408        .filter("name.first_lower", FilterType::StartsWith, "te st")
409        .build();
410
411        let url = request
412            .client
413            .get(request.url.clone())
414            .query(&request.query_params)
415            .build()
416            .expect("request should build")
417            .url()
418            .to_string();
419
420        assert!(url.contains("c%3Ashow=name.first"));
421        assert!(url.contains("name.first_lower=%5Ete+st"));
422    }
423}