dynamodb_expression/update/remove.rs
1use core::fmt;
2
3use crate::path::Path;
4
5use super::Update;
6
7/// For use an in an update expression to [remove attributes from an
8/// item][1], or [elements from a list][2].
9///
10/// Prefer [`Path::remove`] over this.
11///
12/// See also: [`Update`]
13///
14/// # Examples
15///
16/// ```
17/// # fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
18/// use dynamodb_expression::{Expression, Path, update::{Remove, Update}};
19/// # use pretty_assertions::assert_eq;
20///
21/// let remove = "foo".parse::<Path>()?.remove();
22/// assert_eq!("REMOVE foo", remove.to_string());
23///
24/// let remove = Remove::from("foo[8]".parse::<Path>()?);
25/// assert_eq!("REMOVE foo[8]", remove.to_string());
26///
27/// let remove: Remove = ["foo", "bar", "baz"].into_iter().map(Path::new_name).collect();
28/// assert_eq!("REMOVE foo, bar, baz", remove.to_string());
29///
30/// let remove = remove.and("quux".parse::<Path>()?.remove());
31/// assert_eq!("REMOVE foo, bar, baz, quux", remove.to_string());
32///
33/// // Use in an update expression
34/// let update = Update::from(remove.clone());
35/// # _ = update;
36///
37/// // Use an expression builder
38/// let expression = Expression::builder().with_update(remove).build();
39/// # _ = expression;
40/// #
41/// # Ok(())
42/// # }
43/// ```
44///
45/// [1]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.REMOVE
46/// [2]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.REMOVE.RemovingListElements
47/// [`Update`]: crate::update::Update
48#[must_use = "Use in an update expression with `Update::from(remove)`"]
49#[derive(Debug, Clone, PartialEq, Eq)]
50pub struct Remove {
51 pub(crate) paths: Vec<Path>,
52}
53
54impl Remove {
55 /// Add an additional [`Update`] statement to this expression.
56 ///
57 /// ```
58 /// # fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
59 /// use dynamodb_expression::Path;
60 /// # use pretty_assertions::assert_eq;
61 ///
62 /// let remove = "foo".parse::<Path>()?.remove().and("bar".parse::<Path>()?.remove());
63 /// assert_eq!("REMOVE foo, bar", remove.to_string());
64 ///
65 /// let set_remove = remove.and("baz".parse::<Path>()?.set("a value"));
66 /// assert_eq!(r#"SET baz = "a value" REMOVE foo, bar"#, set_remove.to_string());
67 /// #
68 /// # Ok(())
69 /// # }
70 /// ```
71 pub fn and<T>(self, other: T) -> Update
72 where
73 T: Into<Update>,
74 {
75 Update::from(self).and(other)
76 }
77}
78
79impl fmt::Display for Remove {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 f.write_str("REMOVE ")?;
82
83 let mut first = true;
84 self.paths.iter().try_for_each(|name| {
85 if first {
86 first = false;
87 } else {
88 f.write_str(", ")?;
89 }
90
91 name.fmt(f)
92 })
93 }
94}
95
96impl<T> From<T> for Remove
97where
98 T: Into<Path>,
99{
100 fn from(path: T) -> Self {
101 Self {
102 paths: vec![path.into()],
103 }
104 }
105}
106
107impl<T> FromIterator<T> for Remove
108where
109 T: Into<Path>,
110{
111 fn from_iter<I>(paths: I) -> Self
112 where
113 I: IntoIterator<Item = T>,
114 {
115 Self {
116 paths: paths.into_iter().map(Into::into).collect(),
117 }
118 }
119}
120
121#[cfg(test)]
122mod test {
123 use pretty_assertions::assert_eq;
124
125 use crate::Path;
126
127 #[test]
128 fn sub_attributes() {
129 assert_eq!(
130 "REMOVE foo.bar",
131 "foo.bar".parse::<Path>().unwrap().remove().to_string()
132 );
133 assert_eq!(
134 "REMOVE foo[3].bar",
135 "foo[3].bar".parse::<Path>().unwrap().remove().to_string()
136 );
137 assert_eq!(
138 "REMOVE foo[3][7]",
139 "foo[3][7]".parse::<Path>().unwrap().remove().to_string()
140 );
141 }
142
143 #[test]
144 fn and() {
145 let remove = "foo"
146 .parse::<Path>()
147 .unwrap()
148 .remove()
149 .and("bar".parse::<Path>().unwrap().remove());
150 assert_eq!("REMOVE foo, bar", remove.to_string());
151 }
152}