dynamodb_expression/condition/
begins_with.rs

1use core::fmt::{self, Write};
2
3use crate::{
4    path::Path,
5    value::{StringOrRef, ValueOrRef},
6};
7
8/// The [DynamoDB `begins_with` function][1]. True if the attribute specified by
9///  the [`Path`] begins with a particular substring.
10///
11/// See also: [`Path::begins_with`], [`Key::begins_with`]
12///
13/// ```
14/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
15/// use dynamodb_expression::{condition::BeginsWith, Path};
16/// # use pretty_assertions::assert_eq;
17///
18/// let begins_with = "foo".parse::<Path>()?.begins_with("T");
19/// assert_eq!(r#"begins_with(foo, "T")"#, begins_with.to_string());
20///
21/// let begins_with = "foo".parse::<Path>()?.key().begins_with("T");
22/// assert_eq!(r#"begins_with(foo, "T")"#, begins_with.to_string());
23/// #
24/// # Ok(())
25/// # }
26/// ```
27///
28/// [1]: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions
29/// [`Key::begins_with`]: crate::key::Key::begins_with
30/// [`Ref`]: crate::value::Ref
31#[derive(Debug, Clone, PartialEq, Eq)]
32pub struct BeginsWith {
33    // `Path` is correct here
34    // https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Syntax
35    pub(crate) path: Path,
36    pub(crate) substr: ValueOrRef,
37}
38
39impl BeginsWith {
40    /// Allows for manually constructing a `BeginsWith` instance.
41    ///
42    /// The `substr` argument can be a string or a reference to an expression
43    /// attribute value. Here's an example.
44    ///
45    /// See also: [`Path::begins_with`], [`Key::begins_with`], [`Ref`]
46    ///
47    /// ```
48    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
49    /// use dynamodb_expression::{condition::BeginsWith, value::Ref, Path};
50    /// # use pretty_assertions::assert_eq;
51    ///
52    /// let begins_with = BeginsWith::new("foo".parse::<Path>()?, "T");
53    /// assert_eq!(r#"begins_with(foo, "T")"#, begins_with.to_string());
54    ///
55    /// let begins_with = BeginsWith::new("foo".parse::<Path>()?, Ref::new("prefix"));
56    /// assert_eq!(r#"begins_with(foo, :prefix)"#, begins_with.to_string());
57    /// #
58    /// # Ok(())
59    /// # }
60    /// ```
61    ///
62    /// [`Key::begins_with`]: crate::key::Key::begins_with
63    /// [`Ref`]: crate::value::Ref
64    pub fn new<P, S>(path: P, substr: S) -> Self
65    where
66        P: Into<Path>,
67        // Per the docs below, this can be a string or a reference to an expression attribute value.
68        //
69        // > True if the attribute specified by path begins with a particular substring.
70        // >
71        // > Example: Check whether the first few characters of the front view picture URL are http://.
72        // >
73        // > begins_with (Pictures.FrontView, :v_sub)
74        // >
75        // > The expression attribute value :v_sub is a placeholder for http://.
76        //
77        // Source: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions
78        S: Into<StringOrRef>,
79    {
80        Self {
81            path: path.into(),
82            substr: substr.into().into(),
83        }
84    }
85}
86
87impl fmt::Display for BeginsWith {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        f.write_str("begins_with(")?;
90        self.path.fmt(f)?;
91        f.write_str(", ")?;
92        self.substr.fmt(f)?;
93        f.write_char(')')
94    }
95}
96
97#[cfg(test)]
98mod test {
99    use std::error::Error;
100
101    use pretty_assertions::assert_eq;
102
103    use crate::{value::Ref, Path};
104
105    use super::BeginsWith;
106
107    #[test]
108    fn string() -> Result<(), Box<dyn Error>> {
109        let begins_with = BeginsWith::new("foo[3]".parse::<Path>()?, "foo");
110        assert_eq!(r#"begins_with(foo[3], "foo")"#, begins_with.to_string());
111
112        let begins_with = BeginsWith::new("foo[3]".parse::<Path>()?, String::from("foo"));
113        assert_eq!(r#"begins_with(foo[3], "foo")"#, begins_with.to_string());
114
115        #[allow(clippy::needless_borrows_for_generic_args)]
116        let begins_with = BeginsWith::new("foo[3]".parse::<Path>()?, &String::from("foo"));
117        assert_eq!(r#"begins_with(foo[3], "foo")"#, begins_with.to_string());
118
119        #[allow(clippy::needless_borrows_for_generic_args)]
120        let begins_with = BeginsWith::new("foo[3]".parse::<Path>()?, &"foo");
121        assert_eq!(r#"begins_with(foo[3], "foo")"#, begins_with.to_string());
122
123        Ok(())
124    }
125
126    #[test]
127    fn value_ref() {
128        let begins_with = BeginsWith::new("foo[3]".parse::<Path>().unwrap(), Ref::from("prefix"));
129        assert_eq!("begins_with(foo[3], :prefix)", begins_with.to_string());
130    }
131}