dynamodb_expression/update/set/
set_action.rs

1use core::fmt;
2
3use crate::update::Update;
4
5use super::{Assign, IfNotExists, ListAppend, Math};
6
7/// Represents an action to take in a [`SET` statement][1] for an update expression.
8///
9/// See also: [`Set`], [`Update`]
10///
11/// [1]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET
12/// [`Set`]: crate::update::Set
13/// [`Update`]: crate::update::Update
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub enum SetAction {
16    /// Assign a value in a `SET` statement for an update expression.
17    ///
18    /// See also: [`Assign`]
19    Assign(Assign),
20
21    /// Perform [math against a value in a `SET` statement][1] for an update expression.
22    ///
23    /// See also: [`Math`]
24    ///
25    /// [1]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.IncrementAndDecrement
26    Math(Math),
27
28    /// [Add values to a list][1] in a `SET` statement for an update expression.
29    ///
30    /// See also: [`ListAppend`]
31    ///
32    /// [1]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.UpdatingListElements
33    ListAppend(ListAppend),
34
35    /// Assign a value [only if it doesn't exist][1].
36    ///
37    /// See also: [`IfNotExists`]
38    ///
39    /// [1]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.PreventingAttributeOverwrites
40    IfNotExists(IfNotExists),
41}
42
43impl SetAction {
44    /// Add an additional [`Update`] statement to this expression.
45    ///
46    /// ```
47    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
48    /// use dynamodb_expression::{Num, Path};
49    /// # use pretty_assertions::assert_eq;
50    ///
51    /// let set = "foo"
52    ///     .parse::<Path>()?
53    ///     .set(Num::new(7))
54    ///     .and("bar".parse::<Path>()?.set("a value"))
55    ///     .and("baz".parse::<Path>()?.remove());
56    /// assert_eq!(r#"SET foo = 7, bar = "a value" REMOVE baz"#, set.to_string());
57    /// #
58    /// # Ok(())
59    /// # }
60    /// ```
61    pub fn and<T>(self, other: T) -> Update
62    where
63        T: Into<Update>,
64    {
65        Update::from(self).and(other)
66    }
67}
68
69impl From<Assign> for SetAction {
70    fn from(assign: Assign) -> Self {
71        Self::Assign(assign)
72    }
73}
74
75impl From<Math> for SetAction {
76    fn from(math: Math) -> Self {
77        Self::Math(math)
78    }
79}
80
81impl From<ListAppend> for SetAction {
82    fn from(append: ListAppend) -> Self {
83        Self::ListAppend(append)
84    }
85}
86
87impl From<IfNotExists> for SetAction {
88    fn from(if_not_exists: IfNotExists) -> Self {
89        Self::IfNotExists(if_not_exists)
90    }
91}
92
93impl fmt::Display for SetAction {
94    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95        match self {
96            SetAction::Assign(action) => action.fmt(f),
97            SetAction::Math(action) => action.fmt(f),
98            SetAction::ListAppend(action) => action.fmt(f),
99            SetAction::IfNotExists(action) => action.fmt(f),
100        }
101    }
102}
103
104#[cfg(test)]
105mod test {
106    use std::error::Error;
107
108    use pretty_assertions::assert_eq;
109
110    use crate::{
111        update::{Assign, IfNotExists, ListAppend, Math, Set},
112        Num, Path,
113    };
114
115    use super::SetAction;
116
117    #[test]
118    fn from() -> Result<(), Box<dyn Error>> {
119        let assign: Assign = "foo".parse::<Path>()?.set(Num::new(8));
120        let if_not_exists: IfNotExists = "bar".parse::<Path>()?.if_not_exists().set(Num::new(7));
121        let math: Math = "baz".parse::<Path>()?.math().add(1);
122        let list_append: ListAppend = "quux".parse::<Path>()?.list_append().list(["d", "e", "f"]);
123
124        let _set_actions = [
125            SetAction::from(assign),
126            SetAction::from(if_not_exists),
127            SetAction::from(math),
128            SetAction::from(list_append),
129        ];
130
131        Ok(())
132    }
133
134    #[test]
135    fn and() -> Result<(), Box<dyn Error>> {
136        let assign: Assign = "bar".parse::<Path>()?.set(Num::new(8));
137        let set_action: SetAction = "foo".parse::<Path>()?.set("a value").into();
138
139        // Should be able to concatenate anything that can be turned into a SetAction.
140
141        let combined = set_action.clone().and(assign.clone());
142        assert_eq!(r#"SET foo = "a value", bar = 8"#, combined.to_string());
143
144        // Should be able to concatenate a SetAction instance.
145
146        let combined = set_action.clone().and(SetAction::from(assign.clone()));
147        assert_eq!(r#"SET foo = "a value", bar = 8"#, combined.to_string());
148
149        // Should be able to concatenate a Set instance
150
151        let set: Set = [
152            SetAction::from(assign),
153            SetAction::from("baz".parse::<Path>()?.if_not_exists().set(Num::new(7))),
154        ]
155        .into_iter()
156        .collect();
157        let combined = set_action.clone().and(set);
158        assert_eq!(
159            r#"SET foo = "a value", bar = 8, baz = if_not_exists(baz, 7)"#,
160            combined.to_string()
161        );
162
163        // Should be able to concatenate a Remove instance
164
165        let combined = set_action.clone().and("quux".parse::<Path>()?.remove());
166        assert_eq!(r#"SET foo = "a value" REMOVE quux"#, combined.to_string());
167
168        // Should be able to concatenate a SetRemove instance
169
170        let combined = set_action.and("quux".parse::<Path>()?.remove());
171        assert_eq!(r#"SET foo = "a value" REMOVE quux"#, combined.to_string());
172
173        Ok(())
174    }
175}