silent_db/core/
query.rs

1use std::ops::{Add, BitAnd, BitOr};
2
3#[derive(Debug)]
4pub struct QueryBuilder {
5    field: String,
6    action: String,
7    value: String,
8}
9
10impl QueryBuilder {
11    pub fn get_sql(&self) -> String {
12        let field = if self.field.is_empty() || self.field.starts_with('(') {
13            self.field.clone()
14        } else {
15            format!("`{}`", self.field)
16        };
17        let action = if self.action.is_empty() {
18            self.action.clone()
19        } else {
20            format!("{} ", self.action)
21        };
22        format!("{} {}{}", field, action, self.value)
23    }
24}
25
26#[derive(Debug)]
27pub struct QueryBuilderGroup {
28    group: Vec<QueryBuilder>,
29}
30
31impl QueryBuilderGroup {
32    pub fn get_sql(&self) -> String {
33        self.group
34            .iter()
35            .map(|builder| builder.get_sql())
36            .collect::<Vec<String>>()
37            .join(" AND ")
38    }
39
40    pub fn get_query(&self) -> String {
41        format!("WHERE {}", self.get_sql())
42    }
43}
44
45impl Add for QueryBuilderGroup {
46    type Output = QueryBuilderGroup;
47
48    fn add(self, other: QueryBuilderGroup) -> QueryBuilderGroup {
49        let QueryBuilderGroup { mut group } = self;
50        group.extend(other.group);
51        QueryBuilderGroup { group }
52    }
53}
54
55impl BitAnd for QueryBuilderGroup {
56    type Output = QueryBuilderGroup;
57
58    fn bitand(self, other: QueryBuilderGroup) -> QueryBuilderGroup {
59        let builder = QueryBuilder {
60            field: format!("({})", self.get_sql()),
61            action: "AND".to_string(),
62            value: format!("({})", other.get_sql()),
63        };
64        QueryBuilderGroup {
65            group: vec![builder],
66        }
67    }
68}
69
70impl BitOr for QueryBuilderGroup {
71    type Output = QueryBuilderGroup;
72
73    fn bitor(self, other: QueryBuilderGroup) -> QueryBuilderGroup {
74        let builder = QueryBuilder {
75            field: format!("({})", self.get_sql()),
76            action: "OR".to_string(),
77            value: format!("({})", other.get_sql()),
78        };
79        QueryBuilderGroup {
80            group: vec![builder],
81        }
82    }
83}
84
85pub trait Query {
86    fn get_field() -> String;
87    #[inline]
88    fn parse<T>(value: T) -> String
89    where
90        T: ToString,
91    {
92        match value.to_string().parse::<f64>().map(|_| value.to_string()) {
93            Ok(value) => value,
94            Err(_) => format!("'{}'", value.to_string()),
95        }
96    }
97    fn query_eq<T>(value: T) -> QueryBuilderGroup
98    where
99        T: ToString,
100    {
101        QueryBuilderGroup {
102            group: vec![QueryBuilder {
103                field: Self::get_field(),
104                action: "=".to_string(),
105                value: Self::parse(value),
106            }],
107        }
108    }
109    fn query_ne<T>(value: T) -> QueryBuilderGroup
110    where
111        T: ToString,
112    {
113        QueryBuilderGroup {
114            group: vec![QueryBuilder {
115                field: Self::get_field(),
116                action: "!=".to_string(),
117                value: Self::parse(value),
118            }],
119        }
120    }
121    fn query_gt<T>(value: T) -> QueryBuilderGroup
122    where
123        T: ToString,
124    {
125        QueryBuilderGroup {
126            group: vec![QueryBuilder {
127                field: Self::get_field(),
128                action: ">".to_string(),
129                value: Self::parse(value),
130            }],
131        }
132    }
133    fn gte<T>(value: T) -> QueryBuilderGroup
134    where
135        T: ToString,
136    {
137        QueryBuilderGroup {
138            group: vec![QueryBuilder {
139                field: Self::get_field(),
140                action: ">=".to_string(),
141                value: Self::parse(value),
142            }],
143        }
144    }
145    fn query_lt<T>(value: T) -> QueryBuilderGroup
146    where
147        T: ToString,
148    {
149        QueryBuilderGroup {
150            group: vec![QueryBuilder {
151                field: Self::get_field(),
152                action: "<".to_string(),
153                value: Self::parse(value),
154            }],
155        }
156    }
157    fn lte<T>(value: T) -> QueryBuilderGroup
158    where
159        T: ToString,
160    {
161        QueryBuilderGroup {
162            group: vec![QueryBuilder {
163                field: Self::get_field(),
164                action: "<=".to_string(),
165                value: Self::parse(value),
166            }],
167        }
168    }
169    fn like<T>(value: T) -> QueryBuilderGroup
170    where
171        T: ToString,
172    {
173        QueryBuilderGroup {
174            group: vec![QueryBuilder {
175                field: Self::get_field(),
176                action: "LIKE".to_string(),
177                value: format!("'%{}%'", value.to_string()),
178            }],
179        }
180    }
181    fn starts_with<T>(value: T) -> QueryBuilderGroup
182    where
183        T: ToString,
184    {
185        QueryBuilderGroup {
186            group: vec![QueryBuilder {
187                field: Self::get_field(),
188                action: "LIKE".to_string(),
189                value: format!("'{}%'", value.to_string()),
190            }],
191        }
192    }
193    fn ends_with<T>(value: T) -> QueryBuilderGroup
194    where
195        T: ToString,
196    {
197        QueryBuilderGroup {
198            group: vec![QueryBuilder {
199                field: Self::get_field(),
200                action: "LIKE".to_string(),
201                value: format!("'%{}'", value.to_string()),
202            }],
203        }
204    }
205
206    fn between<T>(value: (T, T)) -> QueryBuilderGroup
207    where
208        T: ToString,
209    {
210        QueryBuilderGroup {
211            group: vec![QueryBuilder {
212                field: Self::get_field(),
213                action: "BETWEEN".to_string(),
214                value: format!("{} AND {}", Self::parse(value.0), Self::parse(value.1)),
215            }],
216        }
217    }
218    fn r#in<T>(value: Vec<T>) -> QueryBuilderGroup
219    where
220        T: ToString,
221    {
222        QueryBuilderGroup {
223            group: vec![QueryBuilder {
224                field: Self::get_field(),
225                action: "IN".to_string(),
226                value: format!(
227                    "({})",
228                    value
229                        .iter()
230                        .map(|v| format!("'{}'", v.to_string()))
231                        .collect::<Vec<String>>()
232                        .join(", ")
233                ),
234            }],
235        }
236    }
237    fn is_null() -> QueryBuilderGroup {
238        QueryBuilderGroup {
239            group: vec![QueryBuilder {
240                field: Self::get_field(),
241                action: "IS".to_string(),
242                value: "NULL".to_string(),
243            }],
244        }
245    }
246    fn not_null() -> QueryBuilderGroup {
247        QueryBuilderGroup {
248            group: vec![QueryBuilder {
249                field: Self::get_field(),
250                action: "IS NOT".to_string(),
251                value: "NULL".to_string(),
252            }],
253        }
254    }
255    fn raw<T>(value: T) -> QueryBuilderGroup
256    where
257        T: ToString,
258    {
259        QueryBuilderGroup {
260            group: vec![QueryBuilder {
261                field: "".to_string(),
262                action: "".to_string(),
263                value: value.to_string(),
264            }],
265        }
266    }
267}
268
269#[cfg(test)]
270mod tests {
271    use super::*;
272
273    type User = String;
274    impl Query for User {
275        fn get_field() -> String {
276            "user".to_string()
277        }
278    }
279
280    type Age = u16;
281    impl Query for Age {
282        fn get_field() -> String {
283            "age".to_string()
284        }
285    }
286
287    #[test]
288    fn test_query_builder() {
289        let query = User::query_eq("zhangsan") & Age::query_gt(18)
290            | User::query_eq("lisi") & Age::query_lt(30);
291        assert_eq!(
292            query.get_sql(),
293            "((`user` = 'zhangsan') AND (`age` > 18)) OR ((`user` = 'lisi') AND (`age` < 30))"
294        );
295        let query = (User::query_eq("zhangsan") + Age::query_gt(18))
296            | User::query_eq("lisi") & Age::query_lt(30);
297        assert_eq!(
298            query.get_sql(),
299            "(`user` = 'zhangsan' AND `age` > 18) OR ((`user` = 'lisi') AND (`age` < 30))"
300        );
301        let query = User::query_eq("zhangsan") + Age::query_gt(18) + Age::query_lt(30);
302        assert_eq!(
303            query.get_sql(),
304            "`user` = 'zhangsan' AND `age` > 18 AND `age` < 30"
305        );
306        let query = User::query_eq("zhangsan") & Age::gte(18) & Age::lte(30);
307        assert_eq!(
308            query.get_sql(),
309            "((`user` = 'zhangsan') AND (`age` >= 18)) AND (`age` <= 30)"
310        );
311        let query = User::like("zhangsan") + Age::between((18, 30));
312        assert_eq!(
313            query.get_sql(),
314            "`user` LIKE '%zhangsan%' AND `age` BETWEEN 18 AND 30"
315        );
316        let query = User::r#in(vec!["zhangsan", "lisi"]) + Age::query_ne(18);
317        assert_eq!(
318            query.get_sql(),
319            "`user` IN ('zhangsan', 'lisi') AND `age` != 18"
320        );
321        let query = User::is_null() + Age::not_null();
322        assert_eq!(query.get_sql(), "`user` IS NULL AND `age` IS NOT NULL");
323        let query = User::starts_with("zhang") + User::ends_with("san");
324        assert_eq!(
325            query.get_sql(),
326            "`user` LIKE 'zhang%' AND `user` LIKE '%san'"
327        );
328    }
329}