dynamodb_expression/update/
mod.rs

1//! Types related to [DynamoDB update expressions][1]. For more, see [`Update`].
2//!
3//! [1]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html
4
5mod add;
6mod delete;
7mod remove;
8mod set;
9
10use core::fmt;
11
12pub use self::{
13    add::{Add, AddAction, AddValue},
14    delete::{Delete, DeleteAction},
15    remove::Remove,
16    set::{
17        if_not_exists, list_append, math, Assign, IfNotExists, ListAppend, Math, Set, SetAction,
18    },
19};
20
21/// Represents a [DynamoDB update expression][1].
22///
23/// See also: [`Expression`], [`Set`], [`Remove`], [`Add`], [`Delete`]
24///
25/// # Examples
26///
27/// ```
28/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
29/// use dynamodb_expression::{update::Update, Expression, Path};
30/// # use pretty_assertions::assert_eq;
31///
32/// let update = Update::from("foo".parse::<Path>()?.math().add(7));
33/// assert_eq!("SET foo = foo + 7", update.to_string());
34///
35/// let update = Update::from("foo".parse::<Path>()?.if_not_exists().set("a value"));
36/// assert_eq!(
37///     r#"SET foo = if_not_exists(foo, "a value")"#,
38///     update.to_string()
39/// );
40///
41/// let update = Update::from("foo".parse::<Path>()?.remove());
42/// assert_eq!(r#"REMOVE foo"#, update.to_string());
43/// #
44/// # // TODO: Examples for `Add` and `Delete`.
45///
46/// // To use an `Update`, build an `Expression`.
47/// let expression = Expression::builder().with_update(update).build();
48/// # _ = expression;
49/// #
50/// # Ok(())
51/// # }
52/// ```
53///
54/// [1]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html
55/// [`Expression`]: crate::Expression
56#[must_use = "Use in a DynamoDB expression with `Expression::builder().with_update(update)`"]
57#[derive(Debug, Clone, PartialEq, Eq)]
58pub struct Update {
59    pub(crate) set: Option<Set>,
60    pub(crate) remove: Option<Remove>,
61    pub(crate) add: Option<Add>,
62    pub(crate) delete: Option<Delete>,
63}
64
65impl Update {
66    /// A new update expression for a [`Set`] statement.
67    pub fn new_set<T>(set: T) -> Self
68    where
69        T: Into<Set>,
70    {
71        set.into().into()
72    }
73
74    /// A new update expression for a [`Remove`] statement.
75    pub fn new_remove<T>(remove: T) -> Self
76    where
77        T: Into<Remove>,
78    {
79        remove.into().into()
80    }
81
82    /// A new update expression for an [`Add`] statement.
83    pub fn new_add<T>(add: T) -> Self
84    where
85        T: Into<Add>,
86    {
87        add.into().into()
88    }
89
90    /// A new update expression for a [`Delete`] statement.
91    pub fn new_delete<T>(delete: T) -> Self
92    where
93        T: Into<Delete>,
94    {
95        delete.into().into()
96    }
97
98    /// Combine this [`Update`] statement with another.
99    pub fn and<T>(mut self, other: T) -> Self
100    where
101        T: Into<Update>,
102    {
103        let other = other.into();
104
105        if let Some(mut other) = other.set {
106            if let Some(current) = &mut self.set {
107                current.actions.append(&mut other.actions);
108            } else {
109                self.set = Some(other);
110            }
111        }
112
113        if let Some(mut other) = other.remove {
114            if let Some(current) = &mut self.remove {
115                current.paths.append(&mut other.paths);
116            } else {
117                self.remove = Some(other);
118            }
119        }
120
121        if let Some(mut other) = other.add {
122            if let Some(current) = &mut self.add {
123                current.actions.append(&mut other.actions);
124            } else {
125                self.add = Some(other);
126            }
127        }
128
129        if let Some(mut other) = other.delete {
130            if let Some(current) = &mut self.delete {
131                current.actions.append(&mut other.actions);
132            } else {
133                self.delete = Some(other);
134            }
135        }
136
137        self
138    }
139}
140
141impl fmt::Display for Update {
142    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143        let mut first = true;
144        if let Some(set) = &self.set {
145            first = false;
146            set.fmt(f)?;
147        }
148
149        if let Some(remove) = &self.remove {
150            if first {
151                first = false;
152            } else {
153                f.write_str(" ")?;
154            }
155
156            remove.fmt(f)?;
157        }
158
159        if let Some(add) = &self.add {
160            if first {
161                first = false;
162            } else {
163                f.write_str(" ")?;
164            }
165
166            add.fmt(f)?;
167        }
168
169        if let Some(delete) = &self.delete {
170            if !first {
171                f.write_str(" ")?;
172            }
173
174            delete.fmt(f)?;
175        }
176
177        Ok(())
178    }
179}
180
181impl From<Set> for Update {
182    fn from(value: Set) -> Self {
183        Self {
184            set: Some(value),
185            remove: None,
186            add: None,
187            delete: None,
188        }
189    }
190}
191
192impl From<SetAction> for Update {
193    fn from(value: SetAction) -> Self {
194        Self {
195            set: Some(value.into()),
196            remove: None,
197            add: None,
198            delete: None,
199        }
200    }
201}
202
203impl From<Assign> for Update {
204    fn from(value: Assign) -> Self {
205        Self {
206            set: Some(value.into()),
207            remove: None,
208            add: None,
209            delete: None,
210        }
211    }
212}
213
214impl From<Math> for Update {
215    fn from(value: Math) -> Self {
216        Self {
217            set: Some(value.into()),
218            remove: None,
219            add: None,
220            delete: None,
221        }
222    }
223}
224
225impl From<ListAppend> for Update {
226    fn from(value: ListAppend) -> Self {
227        Self {
228            set: Some(value.into()),
229            remove: None,
230            add: None,
231            delete: None,
232        }
233    }
234}
235
236impl From<IfNotExists> for Update {
237    fn from(value: IfNotExists) -> Self {
238        Self {
239            set: Some(value.into()),
240            remove: None,
241            add: None,
242            delete: None,
243        }
244    }
245}
246
247impl From<Remove> for Update {
248    fn from(value: Remove) -> Self {
249        Self {
250            set: None,
251            remove: Some(value),
252            add: None,
253            delete: None,
254        }
255    }
256}
257
258impl From<Add> for Update {
259    fn from(value: Add) -> Self {
260        Self {
261            set: None,
262            remove: None,
263            add: Some(value),
264            delete: None,
265        }
266    }
267}
268
269impl From<AddAction> for Update {
270    fn from(value: AddAction) -> Self {
271        Self {
272            set: None,
273            remove: None,
274            add: Some(value.into()),
275            delete: None,
276        }
277    }
278}
279
280impl From<Delete> for Update {
281    fn from(value: Delete) -> Self {
282        Self {
283            set: None,
284            remove: None,
285            add: None,
286            delete: Some(value),
287        }
288    }
289}
290
291impl From<DeleteAction> for Update {
292    fn from(value: DeleteAction) -> Self {
293        Self {
294            set: None,
295            remove: None,
296            add: None,
297            delete: Some(value.into()),
298        }
299    }
300}
301
302#[cfg(test)]
303mod examples {
304    #[test]
305    fn example() -> Result<(), Box<dyn std::error::Error>> {
306        use crate::{update::Update, Path};
307        use pretty_assertions::assert_eq;
308
309        let update = Update::from("foo".parse::<Path>()?.math().add(7));
310        assert_eq!("SET foo = foo + 7", update.to_string());
311
312        let update = Update::from("foo".parse::<Path>()?.if_not_exists().set("a value"));
313        assert_eq!(
314            r#"SET foo = if_not_exists(foo, "a value")"#,
315            update.to_string()
316        );
317
318        let update = Update::from("foo".parse::<Path>()?.remove());
319        assert_eq!(r#"REMOVE foo"#, update.to_string());
320
321        // TODO: Examples for `Add` and `Delete`.
322
323        Ok(())
324    }
325}