1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
use core::fmt;
use crate::{
path::Path,
update::Set,
value::{Value, ValueOrRef},
};
/// Represents an update expression to [set an attribute if it doesn't exist][1].
///
/// See also: [`Path::if_not_exists`]
///
/// [1]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.SET.PreventingAttributeOverwrites
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IfNotExists {
pub(crate) dst: Path,
pub(crate) src: Option<Path>,
pub(crate) value: ValueOrRef,
}
impl IfNotExists {
pub fn builder<T>(dst: T) -> Builder
where
T: Into<Path>,
{
Builder {
dst: dst.into(),
src: None,
}
}
/// Add an additional action to this `SET` statement.
///
/// ```
/// use dynamodb_expression::{Num, Path, update::Set};
/// # use pretty_assertions::assert_eq;
///
/// let set = Path::new_name("foo").if_not_exists().assign(Num::new(7))
/// .and(Path::new_name("bar").assign("a value"));
/// assert_eq!(r#"SET foo = if_not_exists(foo, 7), bar = "a value""#, set.to_string());
/// ```
pub fn and<T>(self, action: T) -> Set
where
T: Into<Set>,
{
Set::from(self).and(action)
}
}
impl fmt::Display for IfNotExists {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self { dst, src, value } = self;
// If no source field is specified, default to using the destination.
let src = src.as_ref().unwrap_or(dst);
write!(f, "{dst} = if_not_exists({src}, {value})")
}
}
/// Builds an [`IfNotExists`] instance. Create an instance of this by using [`IfNotExists::builder`].
///
/// See also: [`Path::if_not_exists`]
#[must_use = "Consume this `Builder` by using its `.value()` method"]
#[derive(Debug, Clone)]
pub struct Builder {
dst: Path,
src: Option<Path>,
}
impl Builder {
/// Sets the source [`Path`] to check for existence.
///
/// Defaults to the destination [`Path`].
///
/// ```
/// # use dynamodb_expression::{Num, Path};
/// # use pretty_assertions::assert_eq;
/// #
/// let if_not_exists = Path::new_name("foo")
/// .if_not_exists()
/// .src(Path::new_name("bar"))
/// .assign(Num::new(42));
/// assert_eq!("foo = if_not_exists(bar, 42)", if_not_exists.to_string());
/// ```
///
/// Compare with the default, where the destination [`Path`] is used:
///
/// ```
/// # use dynamodb_expression::{Num, Path};
/// # use pretty_assertions::assert_eq;
/// #
/// let if_not_exists = Path::new_name("foo")
/// .if_not_exists()
/// .assign(Num::new(42));
/// assert_eq!("foo = if_not_exists(foo, 42)", if_not_exists.to_string());
/// ```
pub fn src<T>(mut self, src: T) -> Self
where
T: Into<Path>,
{
self.src = Some(src.into());
self
}
/// The value to conditionally set.
///
/// Consumes this [`Builder`] and creates an [`IfNotExists`] instance.
///
/// See also: [`Path::if_not_exists`]
pub fn assign<T>(self, value: T) -> IfNotExists
where
T: Into<Value>,
{
let Self { dst, src } = self;
IfNotExists {
dst,
src,
value: value.into().into(),
}
}
}