igdb_rs/
request_builder.rs1use crate::request_filters::Filter;
2use std::str::FromStr;
3use std::string::ToString;
4use surf::middleware::HttpClient;
5use url::Url;
6
7const HEADER_KEY_NAME: &str = "user-key";
8
9#[derive(Clone)]
10pub struct RequestBuilder {
12 pub(crate) fields: Vec<String>,
13 pub(crate) filters: Vec<Filter>,
14 pub(crate) sort: (String, String),
15 pub(crate) limit: usize,
16 pub(crate) search: String,
17}
18
19impl Default for RequestBuilder {
20 fn default() -> Self {
21 RequestBuilder {
22 fields: Vec::new(),
23 filters: vec![],
24 sort: (String::new(), String::new()),
25 limit: 10,
26 search: String::new(),
27 }
28 }
29}
30
31pub enum OrderBy {
32 Descending,
33 Ascending,
34}
35
36impl ToString for OrderBy {
37 fn to_string(&self) -> String {
38 match self {
39 OrderBy::Ascending => "asc",
40 OrderBy::Descending => "desc",
41 }
42 .into()
43 }
44}
45
46pub enum Equality {
47 Less,
48 LessOrEqual,
49 Greater,
50 GreaterOrEqual,
51 Equal,
52 NotEqual,
53}
54
55impl ToString for Equality {
56 fn to_string(&self) -> String {
57 match self {
58 Equality::Equal => "=",
59 Equality::NotEqual => "!=",
60 Equality::Greater => ">",
61 Equality::Less => "<",
62 Equality::GreaterOrEqual => ">=",
63 Equality::LessOrEqual => "<=",
64 }
65 .into()
66 }
67}
68
69impl RequestBuilder {
70 pub fn new() -> RequestBuilder {
84 RequestBuilder::default()
85 }
86
87 pub(crate) fn build(&self, api_key: &str, url: &str) -> surf::Request<impl HttpClient> {
88 let body = &self.build_body();
89
90 log::debug!("url: {}, body: {}", url, String::from_utf8_lossy(body));
91
92 let mut req =
93 surf::Request::new(http::Method::GET, Url::from_str(url).unwrap()).body_bytes(body);
94
95 req.headers().insert(HEADER_KEY_NAME, api_key);
96 req.headers().insert("content-type", "application/text");
97
98 req
99 }
100
101 pub(crate) fn build_body(&self) -> Vec<u8> {
102 let fields = self
103 .fields
104 .iter()
105 .enumerate()
106 .fold(String::new(), |mut acc, (i, v)| {
107 acc.push_str(v);
108 let separator = match i {
109 _ if i == (self.fields.len() - 1) => ";",
110 _ => ",",
111 };
112 acc.push_str(separator);
113 acc
114 });
115
116 let filter_clause =
117 self.filters
118 .iter()
119 .enumerate()
120 .fold(String::new(), |mut acc, (i, filter)| {
121 if i == 0 {
122 acc.push_str("where ")
123 }
124 if i != 0 {
125 acc.push_str(" & ")
126 };
127
128 acc.push_str(&format!(
129 "{} {} {}",
130 filter.key, filter.symbol, filter.value
131 ));
132
133 if i == (self.filters.len() - 1) {
134 acc.push_str(";");
135 }
136 acc
137 });
138
139 self.format_body_parts(fields, filter_clause)
140 .as_bytes()
141 .to_vec()
142 }
143
144 fn format_body_parts(&self, fields: String, filters: String) -> String {
145 let mut order = String::new();
146
147 let mut body = format!("fields {}", fields);
148
149 if !str::is_empty(&self.search) {
150 body = format!("{} search \"{}\";", body, self.search);
151 }
152
153 if !self.filters.is_empty() {
154 body = format!("{} {}", body, filters);
155 }
156
157 if !str::is_empty(&self.sort.0) {
158 order.push_str(&format!("sort {} {}", self.sort.0, self.sort.1));
159 body = format!("{} {};", body, order);
160 }
161
162 body = format!("{} limit {};", body, self.limit);
163 body
164 }
165}
166
167#[test]
168fn request_builder_with_all_fields() {
169 let mut builder = RequestBuilder::new();
170
171 builder.all_fields();
172
173 let body = builder.build_body();
174
175 assert_eq!(
176 "fields *; limit 10;",
177 String::from_utf8_lossy(&body).to_owned()
178 );
179}
180
181#[test]
182fn request_builder_with_fields_and_where_clause_body_build() {
183 let mut builder = RequestBuilder::new();
184
185 builder
186 .add_field("name")
187 .add_field("involved_companies")
188 .add_where("name", Equality::Equal, "Conan")
189 .add_where("id", Equality::Less, 39047.to_string());
190
191 let body = builder.build_body();
192
193 assert_eq!(
194 "fields name,involved_companies; where name = Conan & id < 39047; limit 10;",
195 String::from_utf8_lossy(&body).to_owned()
196 );
197}
198
199#[test]
200fn request_builder_with_fields_where_clause_and_sort_asc_body_build() {
201 let mut builder = RequestBuilder::new();
202
203 builder
204 .add_field("name")
205 .add_field("involved_companies")
206 .add_where("id", Equality::Equal, 39047.to_string())
207 .add_where("name", Equality::Equal, "Conan")
208 .sort_by("name", OrderBy::Ascending)
209 .limit(2);
210
211 let body = builder.build_body();
212
213 assert_eq!(
214 "fields name,involved_companies; where id = 39047 & name = Conan; sort name asc; limit 2;",
215 String::from_utf8_lossy(&body).to_owned()
216 );
217}