iyzipay_rust/requests/
request.rs

1use 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}