Skip to main content

dynamodb_expression/value/
list.rs

1use core::fmt::{self, Write};
2
3use aws_sdk_dynamodb::types::AttributeValue;
4
5use super::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    /// Creates a value to use as a DynamoDB [list value][1].
18    ///
19    /// See also: [`Value::new_list`]
20    ///
21    /// # Examples
22    ///
23    /// ```rust
24    /// # use pretty_assertions::assert_eq;
25    /// #
26    /// use dynamodb_expression::value::{List, Num, Value};
27    ///
28    /// let list = List::from(["a"]);
29    /// assert_eq!(r#"["a"]"#, list.to_string());
30    ///
31    /// let list = List::from([Num::new(1), Num::new(2)]);
32    /// assert_eq!("[1, 2]", list.to_string());
33    ///
34    /// let list = List::from([Value::new_string("a"), Value::new_num(42)]);
35    /// assert_eq!(r#"["a", 42]"#, list.to_string());
36    /// ```
37    ///
38    /// [1]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html#HowItWorks.DataTypes.Document.List
39    pub fn new<T>(list: T) -> Self
40    where
41        T: Into<List>,
42    {
43        list.into()
44    }
45
46    // Intentionally not using `impl From<ScalarValue> for AttributeValue` because
47    // I don't want to make this a public API people rely on. The purpose of this
48    // crate is not to make creating `AttributeValues` easier. They should try
49    // `serde_dynamo`.
50    pub(super) fn into_attribute_value(self) -> AttributeValue {
51        AttributeValue::L(
52            self.list
53                .into_iter()
54                .map(Value::into_attribute_value)
55                .collect(),
56        )
57    }
58}
59
60impl fmt::Debug for List {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        f.debug_list().entries(self.list.iter()).finish()
63    }
64}
65
66impl fmt::Display for List {
67    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68        f.write_char('[')?;
69
70        let mut first = true;
71        self.list.iter().try_for_each(|v| {
72            if first {
73                first = false;
74            } else {
75                f.write_str(", ")?;
76            }
77
78            v.fmt(f)
79        })?;
80
81        f.write_char(']')
82    }
83}
84
85impl<T> FromIterator<T> for List
86where
87    T: Into<Value>,
88{
89    fn from_iter<I>(iter: I) -> Self
90    where
91        I: IntoIterator<Item = T>,
92    {
93        Self {
94            list: iter.into_iter().map(Into::into).collect(),
95        }
96    }
97}
98
99impl<I, T> From<I> for List
100where
101    I: IntoIterator<Item = T>,
102    T: Into<Value>,
103{
104    fn from(iter: I) -> Self {
105        Self::from_iter(iter)
106    }
107}
108
109#[cfg(test)]
110mod test {
111    use pretty_assertions::assert_eq;
112
113    use super::List;
114    use crate::value::{Num, Value};
115
116    #[test]
117    fn display() {
118        let list = List::from(["a"]);
119        assert_eq!(r#"["a"]"#, list.to_string());
120
121        let list = List::from([Num::new(1), Num::new(2)]);
122        assert_eq!("[1, 2]", list.to_string());
123
124        let list = List::from([Value::new_string("a"), Value::new_num(42)]);
125        assert_eq!(r#"["a", 42]"#, list.to_string());
126    }
127}