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}