dynamodb_expression/value/
list.rs

1use core::fmt::{self, Write};
2
3use aws_sdk_dynamodb::types::AttributeValue;
4
5use super::{Scalar, Value};
6
7/// A collection of DynamoDB values that may not all be of the same type.
8/// Represents a [DynamoDB list][1].
9///
10/// [1]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes.Document.List
11#[derive(Clone, PartialEq, Eq, Hash)]
12pub struct List {
13    list: Vec<Value>,
14}
15
16impl List {
17    pub fn new<T>(list: T) -> Self
18    where
19        T: Into<List>,
20    {
21        list.into()
22    }
23
24    // Intentionally not using `impl From<ScalarValue> for AttributeValue` because
25    // I don't want to make this a public API people rely on. The purpose of this
26    // crate is not to make creating `AttributeValues` easier. They should try
27    // `serde_dynamo`.
28    pub(super) fn into_attribute_value(self) -> AttributeValue {
29        AttributeValue::L(
30            self.list
31                .into_iter()
32                .map(Value::into_attribute_value)
33                .collect(),
34        )
35    }
36}
37
38impl fmt::Debug for List {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        f.debug_list().entries(self.list.iter()).finish()
41    }
42}
43
44impl fmt::Display for List {
45    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46        f.write_char('[')?;
47
48        let mut first = true;
49        self.list.iter().try_for_each(|v| {
50            if first {
51                first = false;
52            } else {
53                f.write_str(", ")?;
54            }
55
56            if let Value::Scalar(Scalar::String(s)) = v {
57                serde_json::to_string(s).unwrap().fmt(f)
58            } else {
59                v.fmt(f)
60            }
61        })?;
62
63        f.write_char(']')
64    }
65}
66
67impl<T> FromIterator<T> for List
68where
69    T: Into<Value>,
70{
71    fn from_iter<I>(iter: I) -> Self
72    where
73        I: IntoIterator<Item = T>,
74    {
75        Self {
76            list: iter.into_iter().map(Into::into).collect(),
77        }
78    }
79}
80
81impl<I, T> From<I> for List
82where
83    I: IntoIterator<Item = T>,
84    T: Into<Value>,
85{
86    fn from(iter: I) -> Self {
87        Self::from_iter(iter)
88    }
89}
90
91#[cfg(test)]
92mod test {
93    use pretty_assertions::assert_str_eq;
94
95    use super::List;
96    use crate::value::Value;
97
98    #[test]
99    fn display() {
100        let list = List::from(["a"]);
101        assert_str_eq!(r#"["a"]"#, list.to_string());
102
103        let list = List::from([Value::new_string("a"), Value::new_num(42)]);
104        assert_str_eq!(r#"["a", 42]"#, list.to_string());
105    }
106}