transistor/types/
response.rs

1use crate::types::error::CruxError;
2use chrono::prelude::*;
3use edn_rs::{Deserialize, Edn, EdnError};
4use std::collections::BTreeSet;
5use std::str::FromStr;
6
7#[derive(Debug, PartialEq, Clone)]
8#[allow(non_snake_case)]
9/// Definition for the response of a `POST` at `tx-log` endpoint
10pub struct TxLogResponse {
11    pub tx___tx_id: usize,
12    #[cfg(feature = "time_as_str")]
13    pub tx___tx_time: String,
14    #[cfg(not(feature = "time_as_str"))]
15    pub tx___tx_time: DateTime<FixedOffset>,
16    pub tx__event___tx_events: Option<Vec<Vec<String>>>,
17}
18
19impl Deserialize for TxLogResponse {
20    fn deserialize(edn: &Edn) -> Result<Self, EdnError> {
21        #[cfg(not(feature = "time_as_str"))]
22        let tx_time: String = edn_rs::from_edn(&edn[":crux.tx/tx-time"])?;
23
24        Ok(Self {
25            tx___tx_id: edn_rs::from_edn(&edn[":crux.tx/tx-id"]).unwrap_or(0usize),
26            #[cfg(feature = "time_as_str")]
27            tx___tx_time: edn_rs::from_edn(&edn[":crux.tx/tx-time"])?,
28            #[cfg(not(feature = "time_as_str"))]
29            tx___tx_time: tx_time
30                .parse::<DateTime<FixedOffset>>()
31                .map_err(|_| EdnError::Deserialize("Unable to deserialize `:crux.tx/tx-time`, verify if the transaction time you're sending is correct".to_string()))?,
32            tx__event___tx_events: edn_rs::from_edn(&edn[":crux.tx.event/tx-events"])?,
33        })
34    }
35}
36
37impl TxLogResponse {
38    #[cfg(test)]
39    pub fn default() -> Self {
40        Self {
41            tx___tx_id: 8usize,
42            tx___tx_time: "2020-07-16T21:53:14.628-00:00"
43                .parse::<DateTime<FixedOffset>>()
44                .unwrap(),
45            tx__event___tx_events: None,
46        }
47    }
48}
49
50#[derive(Debug, PartialEq, Clone)]
51#[allow(non_snake_case)]
52/// Definition for the response of a `GET` at `tx-log` endpoint
53pub struct TxLogsResponse {
54    pub tx_events: Vec<TxLogResponse>,
55}
56
57impl FromStr for TxLogsResponse {
58    type Err = CruxError;
59    fn from_str(resp: &str) -> Result<Self, CruxError> {
60        let clean_edn = resp.replace("#crux/id", "").replace("#inst", "");
61        edn_rs::from_str(&clean_edn).map_err(|e| e.into())
62    }
63}
64
65impl Deserialize for TxLogsResponse {
66    fn deserialize(edn: &Edn) -> Result<Self, EdnError> {
67        Ok(Self {
68            tx_events: edn
69                .iter()
70                .ok_or(EdnError::Deserialize(format!(
71                    "The following Edn cannot be deserialized to TxLogs: {:?}",
72                    edn
73                )))?
74                .map(edn_rs::from_edn)
75                .collect::<Result<Vec<TxLogResponse>, EdnError>>()?,
76        })
77    }
78}
79
80#[derive(Debug, PartialEq, Clone)]
81#[allow(non_snake_case)]
82/// Definition for the response of a `POST` at `/entity-tx` endpoint
83pub struct EntityTxResponse {
84    pub db___id: String,
85    pub db___content_hash: String,
86    #[cfg(feature = "time_as_str")]
87    pub db___valid_time: String,
88    #[cfg(not(feature = "time_as_str"))]
89    pub db___valid_time: DateTime<FixedOffset>,
90    pub tx___tx_id: usize,
91    #[cfg(feature = "time_as_str")]
92    pub tx___tx_time: String,
93    #[cfg(not(feature = "time_as_str"))]
94    pub tx___tx_time: DateTime<FixedOffset>,
95}
96
97impl FromStr for EntityTxResponse {
98    type Err = CruxError;
99    fn from_str(resp: &str) -> Result<Self, CruxError> {
100        let clean_edn = resp.replace("#crux/id", "");
101        edn_rs::from_str(&clean_edn).map_err(|e| e.into())
102    }
103}
104
105impl EntityTxResponse {
106    #[cfg(test)]
107    pub fn default() -> Self {
108        Self {
109            db___id: "d72ccae848ce3a371bd313865cedc3d20b1478ca".to_string(),
110            db___content_hash: "1828ebf4466f98ea3f5252a58734208cd0414376".to_string(),
111            db___valid_time: "2020-07-19T04:12:13.788-00:00"
112                .parse::<DateTime<FixedOffset>>()
113                .unwrap(),
114            tx___tx_id: 28usize,
115            tx___tx_time: "2020-07-19T04:12:13.788-00:00"
116                .parse::<DateTime<FixedOffset>>()
117                .unwrap(),
118        }
119    }
120}
121
122impl Deserialize for EntityTxResponse {
123    fn deserialize(edn: &Edn) -> Result<Self, EdnError> {
124        #[cfg(not(feature = "time_as_str"))]
125        let valid_time: String = edn_rs::from_edn(&edn[":crux.db/valid-time"])?;
126        #[cfg(not(feature = "time_as_str"))]
127        let tx_time: String = edn_rs::from_edn(&edn[":crux.tx/tx-time"])?;
128
129        Ok(Self {
130            db___id: edn_rs::from_edn(&edn[":crux.db/id"])?,
131            db___content_hash: edn_rs::from_edn(&edn[":crux.db/content-hash"])?,
132            #[cfg(feature = "time_as_str")]
133            db___valid_time: edn_rs::from_edn(&edn[":crux.db/valid-time"]),
134            #[cfg(not(feature = "time_as_str"))]
135            db___valid_time: valid_time.parse::<DateTime<FixedOffset>>().unwrap(),
136            tx___tx_id: edn_rs::from_edn(&edn[":crux.tx/tx-id"]).unwrap_or(0usize),
137            #[cfg(feature = "time_as_str")]
138            tx___tx_time: edn_rs::from_edn(&edn[":crux.tx/tx-time"]),
139            #[cfg(not(feature = "time_as_str"))]
140            tx___tx_time: tx_time.parse::<DateTime<FixedOffset>>().unwrap(),
141        })
142    }
143}
144
145#[doc(hidden)]
146#[cfg(not(feature = "async"))]
147pub(crate) struct QueryResponse(pub(crate) BTreeSet<Vec<String>>);
148
149#[cfg(not(feature = "async"))]
150impl Deserialize for QueryResponse {
151    fn deserialize(edn: &Edn) -> Result<Self, EdnError> {
152        if edn.set_iter().is_some() {
153            Ok(Self(
154                edn.set_iter()
155                    .ok_or(EdnError::Deserialize(format!(
156                        "The following Edn cannot be deserialized to BTreeSet: {:?}",
157                        edn
158                    )))?
159                    .map(|e| {
160                        e.to_vec().ok_or(EdnError::Deserialize(format!(
161                            "The following Edn cannot be deserialized to Vec: {:?}",
162                            edn
163                        )))
164                    })
165                    .collect::<Result<BTreeSet<Vec<String>>, EdnError>>()?,
166            ))
167        } else {
168            Ok(Self(
169                edn.iter()
170                    .ok_or(EdnError::Deserialize(format!(
171                        "The following Edn cannot be deserialized to BTreeSet: {:?}",
172                        edn
173                    )))?
174                    .map(|e| {
175                        e.to_vec().ok_or(EdnError::Deserialize(format!(
176                            "The following Edn cannot be deserialized to Vec: {:?}",
177                            edn
178                        )))
179                    })
180                    .collect::<Result<BTreeSet<Vec<String>>, EdnError>>()?,
181            ))
182        }
183    }
184}
185
186#[cfg(feature = "async")]
187#[derive(Clone, Debug, PartialEq)]
188/// When feature `async` is enabled this is the response type for endpoint `/query`.
189pub struct QueryAsyncResponse(pub(crate) BTreeSet<Vec<String>>);
190
191#[cfg(feature = "async")]
192impl Deserialize for QueryAsyncResponse {
193    fn deserialize(edn: &Edn) -> Result<Self, EdnError> {
194        if edn.set_iter().is_some() {
195            Ok(Self {
196                0: edn
197                    .set_iter()
198                    .ok_or(EdnError::Deserialize(format!(
199                        "The following Edn cannot be deserialize to BTreeSet: {:?}",
200                        edn
201                    )))?
202                    .map(|e| {
203                        e.to_vec().ok_or(EdnError::Deserialize(format!(
204                            "The following Edn cannot be deserialized to Vec: {:?}",
205                            edn
206                        )))
207                    })
208                    .collect::<Result<BTreeSet<Vec<String>>, EdnError>>()?,
209            })
210        } else {
211            Ok(Self {
212                0: edn
213                    .iter()
214                    .ok_or(EdnError::Deserialize(format!(
215                        "The following Edn cannot be deserialize to BTreeSet: {:?}",
216                        edn
217                    )))?
218                    .map(|e| {
219                        e.to_vec().ok_or(EdnError::Deserialize(format!(
220                            "The following Edn cannot be deserialized to Vec: {:?}",
221                            edn
222                        )))
223                    })
224                    .collect::<Result<BTreeSet<Vec<String>>, EdnError>>()?,
225            })
226        }
227    }
228}
229
230#[derive(Debug, PartialEq, Clone)]
231#[allow(non_snake_case)]
232pub struct EntityHistoryElement {
233    #[cfg(feature = "time_as_str")]
234    pub db___valid_time: String,
235    #[cfg(not(feature = "time_as_str"))]
236    pub db___valid_time: DateTime<FixedOffset>,
237    pub tx___tx_id: usize,
238    #[cfg(feature = "time_as_str")]
239    pub tx___tx_time: String,
240    #[cfg(not(feature = "time_as_str"))]
241    pub tx___tx_time: DateTime<FixedOffset>,
242    pub db___content_hash: String,
243    pub db__doc: Option<Edn>,
244}
245
246impl Deserialize for EntityHistoryElement {
247    fn deserialize(edn: &Edn) -> Result<Self, EdnError> {
248        #[cfg(not(feature = "time_as_str"))]
249        let valid_time: String = edn_rs::from_edn(&edn[":crux.db/valid-time"])?;
250        #[cfg(not(feature = "time_as_str"))]
251        let tx_time: String = edn_rs::from_edn(&edn[":crux.tx/tx-time"])?;
252
253        Ok(Self {
254            db___content_hash: edn_rs::from_edn(&edn[":crux.db/content-hash"])?,
255            #[cfg(feature = "time_as_str")]
256            db___valid_time: edn_rs::from_edn(&edn[":crux.db/valid-time"])?,
257            #[cfg(not(feature = "time_as_str"))]
258            db___valid_time: valid_time.parse::<DateTime<FixedOffset>>().unwrap(),
259            tx___tx_id: edn_rs::from_edn(&edn[":crux.tx/tx-id"]).unwrap_or(0usize),
260            #[cfg(feature = "time_as_str")]
261            tx___tx_time: edn_rs::from_edn(&edn[":crux.tx/tx-time"])?,
262            #[cfg(not(feature = "time_as_str"))]
263            tx___tx_time: tx_time.parse::<DateTime<FixedOffset>>().unwrap(),
264            db__doc: edn.get(":crux.db/doc").map(|d| d.to_owned()),
265        })
266    }
267}
268
269#[cfg(test)]
270impl EntityHistoryElement {
271    pub fn default() -> Self {
272        Self {
273            db___content_hash: "1828ebf4466f98ea3f5252a58734208cd0414376".to_string(),
274            db___valid_time: "2020-07-19T04:12:13.788-00:00"
275                .parse::<DateTime<FixedOffset>>()
276                .unwrap(),
277            tx___tx_id: 28usize,
278            tx___tx_time: "2020-07-19T04:12:13.788-00:00"
279                .parse::<DateTime<FixedOffset>>()
280                .unwrap(),
281            db__doc: None,
282        }
283    }
284
285    pub fn default_docs() -> Self {
286        Self {
287            db___content_hash: "1828ebf4466f98ea3f5252a58734208cd0414376".to_string(),
288            db___valid_time: "2020-07-19T04:12:13.788-00:00"
289                .parse::<DateTime<FixedOffset>>()
290                .unwrap(),
291            tx___tx_id: 28usize,
292            tx___tx_time: "2020-07-19T04:12:13.788-00:00"
293                .parse::<DateTime<FixedOffset>>()
294                .unwrap(),
295            db__doc: Some(Edn::Key(":docs".to_string())),
296        }
297    }
298}
299
300/// Definition for the response of a `GET` at `/entity-history` endpoint. This returns a Vec of  `EntityHistoryElement`.
301#[derive(Debug, PartialEq, Clone)]
302pub struct EntityHistoryResponse {
303    pub history: Vec<EntityHistoryElement>,
304}
305
306impl FromStr for EntityHistoryResponse {
307    type Err = CruxError;
308    fn from_str(resp: &str) -> Result<Self, CruxError> {
309        let clean_edn = resp.replace("#crux/id", "").replace("#inst", "");
310        edn_rs::from_str(&clean_edn).map_err(|e| e.into())
311    }
312}
313
314impl Deserialize for EntityHistoryResponse {
315    fn deserialize(edn: &Edn) -> Result<Self, EdnError> {
316        Ok(Self {
317            history: edn
318                .iter()
319                .ok_or(EdnError::Deserialize(format!(
320                    "The following Edn cannot be deserialize to entity-history: {:?}",
321                    edn
322                )))?
323                .map(edn_rs::from_edn)
324                .collect::<Result<Vec<EntityHistoryElement>, EdnError>>()?,
325        })
326    }
327}