tarantool_rs/client/dmo/
response.rs

1use rmpv::Value;
2use serde::de::DeserializeOwned;
3
4use crate::{errors::DecodingError, utils::extract_iproto_data};
5
6// TODO: unify with call_response.rs
7
8/// Tuple, returned from all data-manipulation operations (insert, update, upsert, replace, delete).
9#[derive(Clone, Debug, PartialEq)]
10pub struct DmoResponse(pub(crate) rmpv::Value);
11
12impl DmoResponse {
13    /// Decode row into type.
14    ///
15    /// Raises error if no rows returned.
16    pub fn decode<T>(self) -> Result<T, DecodingError>
17    where
18        T: DeserializeOwned,
19    {
20        let first = self
21            .into_data_tuple()?
22            .into_iter()
23            .next()
24            .ok_or_else(|| DecodingError::invalid_tuple_length(1, 0))?;
25        Ok(rmpv::ext::from_value(first)?)
26    }
27
28    /// Decode row into type or return `None` if no rows returned.
29    pub fn decode_opt<T>(self) -> Result<Option<T>, DecodingError>
30    where
31        T: DeserializeOwned,
32    {
33        self.into_data_tuple()?
34            .into_iter()
35            .next()
36            .map(rmpv::ext::from_value::<T>)
37            .transpose()
38            .map_err(Into::into)
39    }
40
41    fn into_data_tuple(self) -> Result<Vec<Value>, DecodingError> {
42        match extract_iproto_data(self.0)? {
43            Value::Array(x) => Ok(x),
44            rest => Err(DecodingError::type_mismatch("array", rest.to_string())),
45        }
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use assert_matches::assert_matches;
52
53    use crate::codec::consts::keys::DATA;
54
55    use super::*;
56
57    fn build_tuple_response(data: Vec<Value>) -> Value {
58        Value::Map(vec![(DATA.into(), Value::Array(data))])
59    }
60
61    #[test]
62    fn decode() {
63        let resp = build_tuple_response(vec![Value::Boolean(true)]);
64        assert_matches!(DmoResponse(resp).decode(), Ok(true));
65    }
66
67    #[test]
68    fn decode_err_len() {
69        let resp = build_tuple_response(vec![]);
70        assert_matches!(DmoResponse(resp).decode::<()>(), Err(_));
71    }
72
73    #[test]
74    fn decode_opt() {
75        let resp = build_tuple_response(vec![Value::Boolean(true)]);
76        assert_matches!(DmoResponse(resp).decode_opt(), Ok(Some(true)));
77    }
78
79    #[test]
80    fn decode_opt_none() {
81        let resp = build_tuple_response(vec![]);
82        assert_matches!(DmoResponse(resp).decode_opt::<()>(), Ok(None));
83    }
84}