format_sql_query/
predicates.rs

1use itertools::Itertools;
2use std::fmt::{self, Display};
3
4/// SQL statment with boolean logic.
5pub struct PredicateStatement<'s> {
6    statement: &'static str,
7    predicates: &'s [Box<dyn Display>],
8}
9
10impl fmt::Display for PredicateStatement<'_> {
11    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
12        write!(
13            f,
14            "{} {}",
15            self.statement,
16            self.predicates.iter().join("\nAND ")
17        )
18    }
19}
20
21/// Collection of boolean predicates.
22pub struct Predicates(Vec<Box<dyn Display>>);
23
24impl IntoIterator for Predicates {
25    type Item = Box<dyn Display>;
26    type IntoIter = std::vec::IntoIter<Box<dyn Display>>;
27
28    fn into_iter(self) -> Self::IntoIter {
29        self.0.into_iter()
30    }
31}
32
33impl Predicates {
34    /// Create empty collection.
35    pub fn new() -> Predicates {
36        Predicates(Vec::new())
37    }
38
39    /// Creates collection containing given predicate.
40    pub fn from<S: Display + 'static>(predicate: S) -> Predicates {
41        Predicates::new().and(predicate)
42    }
43
44    /// Crates collection containing given predicates.
45    pub fn from_all<S, I, IT>(predicates: I) -> Self
46    where
47        S: Display + 'static,
48        I: IntoIterator<Item = S, IntoIter = IT>,
49        IT: Iterator<Item = S>,
50    {
51        Predicates::new().and_all(predicates)
52    }
53
54    /// Gets WHERE statement with predicates.
55    pub fn as_where<'s>(&'s self) -> PredicateStatement<'s> {
56        PredicateStatement {
57            statement: "WHERE",
58            predicates: &self.0,
59        }
60    }
61
62    /// Appends predicate.
63    pub fn and_push<S: Display + 'static>(&mut self, predicate: S) {
64        self.and_extend(Some(predicate))
65    }
66
67    /// Appends all predicates.
68    pub fn and_extend<S, I, IT>(&mut self, predicates: I) -> ()
69    where
70        S: Display + 'static,
71        I: IntoIterator<Item = S, IntoIter = IT>,
72        IT: Iterator<Item = S>,
73    {
74        self.0.extend(
75            predicates
76                .into_iter()
77                .map(|c| Box::new(c) as Box<dyn Display>),
78        );
79    }
80
81    /// Appends predicate with fluid API.
82    pub fn and<S: Display + 'static>(mut self, predicate: S) -> Self {
83        self.and_push(predicate);
84        self
85    }
86
87    /// Appends all predicates with fluid API.
88    pub fn and_all<S, I, IT>(mut self, predicates: I) -> Self
89    where
90        S: Display + 'static,
91        I: IntoIterator<Item = S, IntoIter = IT>,
92        IT: Iterator<Item = S>,
93    {
94        self.and_extend(predicates);
95        self
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102
103    #[test]
104    fn it_works() {
105        assert_eq!(
106            Predicates::from("foo = 'bar'")
107                .and("baz")
108                .and_all(["hello", "world"].iter())
109                .and_all(Predicates::from_all(["abc", "123"].iter()))
110                .as_where()
111                .to_string(),
112            "WHERE foo = \'bar\'\nAND baz\nAND hello\nAND world\nAND abc\nAND 123"
113        );
114    }
115}