iyzipay_rust/requests/
request.rs1use std::ops::Deref;
2use std::str;
3
4use bigdecimal::BigDecimal;
5
6const DOT: &'static str = ".";
7const ZERO: &'static str = "0";
8const COMMA: &'static str = ",";
9
10pub trait PKISerialize {
11 fn serialize(&self) -> Option<String>;
12}
13
14impl<T> PKISerialize for Vec<T>
15where
16 T: PKISerialize,
17{
18 fn serialize(&self) -> Option<String> {
19 let mut ser = RequestStringBuilder::new();
20 for val in self {
21 let serialized: Option<String> = val.serialize();
22 if serialized.is_some() {
23 ser.append_raw(format!("{}, ", serialized.unwrap()));
24 }
25 }
26 Option::from(ser.build(true))
27 }
28}
29
30impl PKISerialize for Vec<u8> {
31 fn serialize(&self) -> Option<String> {
32 let mut ser = RequestStringBuilder::new();
33 for val in self {
34 ser.append_raw(format!("{}, ", val.to_string()));
35 }
36 Option::from(ser.build(true))
37 }
38}
39
40impl<T> PKISerialize for Option<T>
41where
42 T: PKISerialize,
43{
44 fn serialize(&self) -> Option<String> {
45 match self.as_ref() {
46 Some(val) => val.serialize(),
47 None => None,
48 }
49 }
50}
51
52pub trait RequestQueryParams {
53 fn get_query_params(&self) -> String;
54}
55
56#[derive(Debug, Default, Serialize, Deserialize)]
57#[serde(rename_all = "camelCase")]
58pub struct Request {
59 locale: Option<String>,
60
61 conversation_id: Option<String>,
62}
63
64impl Request {
65 pub fn new<T: Into<String>>(conversation_id: T, locale: T) -> Self {
66 Request {
67 conversation_id: Some(conversation_id.into()),
68 locale: Some(locale.into()),
69 }
70 }
71
72 pub fn set_conversation_id<T: Into<String>>(&mut self, conversation_id: T) {
73 self.conversation_id = Some(conversation_id.into());
74 }
75
76 pub fn conversation_id(&self) -> Option<&String> {
77 self.conversation_id.as_ref()
78 }
79
80 pub fn set_locale<T: Into<String>>(&mut self, locale: T) {
81 self.locale = Some(locale.into());
82 }
83
84 pub fn locale(&self) -> Option<&String> {
85 self.locale.as_ref()
86 }
87}
88
89impl PKISerialize for Request {
90 fn serialize(&self) -> Option<String> {
91 let mut ser = RequestStringBuilder::new();
92 ser.append_option("locale", self.locale.as_ref());
93 ser.append_option("conversationId", self.conversation_id.as_ref());
94 Option::from(ser.build(false))
95 }
96}
97
98impl RequestQueryParams for Request {
99 fn get_query_params(&self) -> String {
100 let mut str = String::new();
101
102 if self.conversation_id().is_some() {
103 let val = self.conversation_id().unwrap();
104 if !val.is_empty() {
105 str.push_str(format!("{}={}", "?conversationId", val.as_str()).as_str());
106 }
107 }
108
109 if self.conversation_id().is_some() {
110 let val = self.locale().unwrap();
111 if !val.is_empty() {
112 str.push_str(format!("{}={}", "&locale", val.as_str()).as_str());
113 }
114 }
115 str
116 }
117}
118
119#[derive(Debug, Default, Serialize, Deserialize)]
120#[serde(rename_all = "camelCase")]
121pub struct PagingRequest {
122 page: Option<u8>,
123
124 count: Option<u8>,
125
126 #[serde(flatten)]
127 request: Request,
128}
129
130impl PagingRequest {
131 pub fn new() -> Self {
132 PagingRequest::default()
133 }
134
135 pub fn set_page<S: Into<Option<u8>>>(&mut self, page: S) {
136 self.page = page.into();
137 }
138
139 pub fn page(&self) -> &Option<u8> {
140 &self.page
141 }
142
143 pub fn set_count<S: Into<Option<u8>>>(&mut self, count: S) {
144 self.count = count.into();
145 }
146
147 pub fn count(&self) -> &Option<u8> {
148 &self.count
149 }
150}
151
152impl PKISerialize for PagingRequest {
153 fn serialize(&self) -> Option<String> {
154 let mut ser = RequestStringBuilder::new();
155 ser.append_option_val(self.request.serialize());
156 ser.append(
157 "page",
158 str::from_utf8(&[self.page.unwrap_or_default()]).unwrap(),
159 );
160 ser.append(
161 "count",
162 str::from_utf8(&[self.count.unwrap_or_default()]).unwrap(),
163 );
164 Option::from(ser.build(true))
165 }
166}
167
168impl RequestQueryParams for PagingRequest {
169 fn get_query_params(&self) -> String {
170 let parent_query_params = &self.deref().get_query_params();
171 let mut str = String::new();
172
173 if !parent_query_params.is_empty() {
174 str.push_str(parent_query_params);
175 }
176
177 if self.page().is_some() {
178 str.push_str(format!("{}={}", "&page", format!("{}", self.page.unwrap())).as_str());
179 }
180
181 if self.count().is_some() {
182 str.push_str(format!("{}={}", "&count", format!("{}", self.count.unwrap())).as_str());
183 }
184
185 str
186 }
187}
188
189impl std::ops::Deref for PagingRequest {
190 type Target = Request;
191 fn deref(&self) -> &Self::Target {
192 &self.request
193 }
194}
195
196impl std::ops::DerefMut for PagingRequest {
197 fn deref_mut(&mut self) -> &mut Self::Target {
198 &mut self.request
199 }
200}
201
202#[derive(Debug, Default)]
203pub struct RequestStringBuilder(String);
204
205impl RequestStringBuilder {
206 pub fn new() -> Self {
207 RequestStringBuilder::default()
208 }
209
210 pub fn append_raw<T: Into<String>>(&mut self, value: T) -> &mut Self {
211 &mut self.0.push_str(value.into().as_str());
212 self
213 }
214
215 pub fn append_raw_option<T: ::std::string::ToString>(&mut self, value: Option<T>) -> &mut Self {
216 let val: Option<T> = value.into();
217 if val.is_some() {
218 self.append_raw(val.unwrap().to_string());
219 }
220 self
221 }
222
223 pub fn append_option_val<T: ::std::string::ToString>(&mut self, value: Option<T>) -> &mut Self {
224 let val: Option<T> = value.into();
225 if val.is_some() {
226 self.append_raw(format!("{},", val.unwrap().to_string()).as_str());
227 }
228 self
229 }
230
231 pub fn append<T: Into<String>>(&mut self, key: T, value: T) -> &mut Self {
232 let val = value.into();
233 if !val.is_empty() {
234 self.append_raw(format!("{}={},", key.into(), val).as_str());
235 }
236 self
237 }
238
239 pub fn append_option<T: Into<String>, S: ::std::string::ToString>(
240 &mut self,
241 key: T,
242 value: Option<S>,
243 ) -> &mut Self {
244 let val: Option<S> = value.into();
245 if val.is_some() {
246 self.append_raw(format!("{}={},", key.into(), val.unwrap().to_string()).as_str());
247 }
248 self
249 }
250
251 pub fn append_price_option<T: Into<String>>(
252 &mut self,
253 key: T,
254 value: Option<&BigDecimal>,
255 ) -> &mut Self {
256 let val: Option<&BigDecimal> = value.into();
257 if val.is_some() {
258 self.append_raw(
259 format!(
260 "{}={},",
261 key.into(),
262 RequestFormatter::format_price(val.unwrap())
263 )
264 .as_str(),
265 );
266 }
267 self
268 }
269
270 pub fn build(&mut self, prefix: bool) -> String {
271 self.0 = self.0.trim().to_string();
272 self.remove_prefix_comma();
273 self.remove_trailing_comma();
274 if prefix {
275 self.append_prefix();
276 }
277 self.0.to_owned()
278 }
279
280 fn append_prefix(&mut self) {
281 self.0 = format!("[{}]", self.0);
282 }
283
284 fn remove_trailing_comma(&mut self) {
285 if self.0.ends_with(COMMA) {
286 self.0.truncate(self.0.len() - 1);
287 }
288 }
289
290 fn remove_prefix_comma(&mut self) {
291 if self.0.starts_with(COMMA) {
292 self.0.remove(0);
293 }
294 }
295}
296
297pub struct RequestFormatter;
298
299impl RequestFormatter {
300 pub fn format_price(price: &BigDecimal) -> String {
301 let price_str = price.to_string();
302 let mut formatted_price = String::from(price_str);
303
304 if !formatted_price.contains(DOT) {
305 formatted_price = format!("{}{}{}", formatted_price, DOT, 0);
306 }
307
308 formatted_price = String::from(formatted_price.trim_end_matches(ZERO));
309 if formatted_price.ends_with(DOT) {
310 formatted_price = format!("{}{}", formatted_price, 0);
311 }
312
313 formatted_price
314 }
315}