mithril_persistence/sqlite/
condition.rs
1use sqlite::Value;
2use std::iter::repeat_n;
3
4#[derive(Debug, Clone)]
6enum BooleanCondition {
7 None,
9
10 Expression(String),
12
13 And(Box<BooleanCondition>, Box<BooleanCondition>),
15
16 Or(Box<BooleanCondition>, Box<BooleanCondition>),
18}
19
20impl BooleanCondition {
21 pub fn expand(&self) -> String {
23 match self {
24 Self::None => "true".to_string(),
25 Self::Expression(expr) => expr.to_owned(),
26 Self::And(lft, rgt) => match (lft.needs_precedence(), rgt.needs_precedence()) {
27 (true, false) => format!("({}) and {}", lft.expand(), rgt.expand()),
28 (false, true) => format!("{} and ({})", lft.expand(), rgt.expand()),
29 (true, true) => format!("({}) and ({})", lft.expand(), rgt.expand()),
30 (false, false) => format!("{} and {}", lft.expand(), rgt.expand()),
31 },
32 Self::Or(lft, rgt) => format!("{} or {}", lft.expand(), rgt.expand()),
33 }
34 }
35
36 fn is_none(&self) -> bool {
37 matches!(self, Self::None)
38 }
39
40 fn needs_precedence(&self) -> bool {
41 matches!(self, Self::Or(_, _))
42 }
43}
44
45#[derive(Debug, Clone)]
47pub struct WhereCondition {
48 condition: BooleanCondition,
50
51 parameters: Vec<Value>,
53}
54
55impl Default for WhereCondition {
56 fn default() -> Self {
57 Self {
58 condition: BooleanCondition::None,
59 parameters: Vec::new(),
60 }
61 }
62}
63
64impl WhereCondition {
65 pub fn new(expression: &str, parameters: Vec<Value>) -> Self {
67 Self {
68 condition: BooleanCondition::Expression(expression.to_string()),
69 parameters,
70 }
71 }
72
73 pub fn expand(self) -> (String, Vec<Value>) {
75 let expression = self.condition.expand();
76 let parameters = self.parameters;
77 let mut final_expression = "".to_string();
80 for (param_index, sql_part) in expression.split("?*").enumerate() {
81 if param_index > 0 {
82 final_expression.push('?');
83 final_expression.push_str(¶m_index.to_string());
84 }
85 final_expression.push_str(sql_part);
86 }
87
88 (final_expression, parameters)
89 }
90
91 pub fn where_in(field: &str, parameters: Vec<Value>) -> Self {
93 let params: Vec<&str> = repeat_n("?*", parameters.len()).collect();
94 let expression = format!("{} in ({})", field, params.join(", "));
95
96 Self {
97 condition: BooleanCondition::Expression(expression),
98 parameters,
99 }
100 }
101
102 pub fn and_where(mut self, mut condition: WhereCondition) -> Self {
104 if condition.condition.is_none() {
105 return self;
106 }
107
108 if self.condition.is_none() {
109 self.condition = condition.condition;
110 self.parameters = condition.parameters;
111 } else {
112 let temp = BooleanCondition::None;
113 let my_condition = std::mem::replace(&mut self.condition, temp);
114 self.condition =
115 BooleanCondition::And(Box::new(my_condition), Box::new(condition.condition));
116 self.parameters.append(&mut condition.parameters);
117 }
118
119 self
120 }
121
122 pub fn or_where(mut self, mut condition: WhereCondition) -> Self {
124 if condition.condition.is_none() {
125 return self;
126 }
127 if self.condition.is_none() {
128 self.condition = condition.condition;
129 self.parameters = condition.parameters;
130 } else {
131 let temp = BooleanCondition::None;
132 let my_condition = std::mem::replace(&mut self.condition, temp);
133 self.condition =
134 BooleanCondition::Or(Box::new(my_condition), Box::new(condition.condition));
135 self.parameters.append(&mut condition.parameters);
136 }
137
138 self
139 }
140}
141
142pub trait GetAllCondition {
144 fn get_all_condition() -> WhereCondition {
146 WhereCondition::default()
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153
154 #[test]
155 fn boolean_expand_none() {
156 let condition = BooleanCondition::None;
157
158 assert_eq!("true".to_string(), condition.expand());
159 }
160
161 #[test]
162 fn boolean_expand_expression() {
163 let condition = BooleanCondition::Expression("something".to_string());
164
165 assert_eq!("something".to_string(), condition.expand());
166 }
167
168 #[test]
169 fn boolean_expand_and() {
170 let left = BooleanCondition::Expression("left".to_string());
171 let right = BooleanCondition::Expression("right".to_string());
172 let condition = BooleanCondition::And(Box::new(left), Box::new(right));
173
174 assert_eq!("left and right".to_string(), condition.expand());
175 }
176
177 #[test]
178 fn boolean_expand_or() {
179 let left = BooleanCondition::Expression("left".to_string());
180 let right = BooleanCondition::Expression("right".to_string());
181 let condition = BooleanCondition::Or(Box::new(left), Box::new(right));
182
183 assert_eq!("left or right".to_string(), condition.expand());
184 }
185
186 #[test]
187 fn expression_default() {
188 let expression = WhereCondition::default();
189 let (sql, params) = expression.expand();
190
191 assert_eq!("true".to_string(), sql);
192 assert!(params.is_empty());
193 }
194
195 #[test]
196 fn expression_sql() {
197 let expression = WhereCondition::new("something is not null", Vec::new());
198 let (sql, params) = expression.expand();
199
200 assert_eq!("something is not null".to_string(), sql);
201 assert!(params.is_empty());
202 }
203
204 #[test]
205 fn expression_and() {
206 let expression =
207 WhereCondition::new("A", Vec::new()).and_where(WhereCondition::new("B", Vec::new()));
208 let (sql, params) = expression.expand();
209
210 assert_eq!("A and B", &sql);
211 assert!(params.is_empty());
212 }
213
214 #[test]
215 fn expression_and_none() {
216 let expression = WhereCondition::new("A", Vec::new()).and_where(WhereCondition::default());
217 let (sql, params) = expression.expand();
218
219 assert_eq!("A", &sql);
220 assert!(params.is_empty());
221 }
222
223 #[test]
224 fn expression_none_and() {
225 let expression = WhereCondition::default().and_where(WhereCondition::new("A", Vec::new()));
226 let (sql, params) = expression.expand();
227
228 assert_eq!("A", &sql);
229 assert!(params.is_empty());
230 }
231
232 #[test]
233 fn expression_or() {
234 let expression =
235 WhereCondition::new("A", Vec::new()).or_where(WhereCondition::new("B", Vec::new()));
236 let (sql, params) = expression.expand();
237
238 assert_eq!("A or B", &sql);
239 assert!(params.is_empty());
240 }
241
242 #[test]
243 fn expression_or_none() {
244 let expression = WhereCondition::new("A", Vec::new()).or_where(WhereCondition::default());
245 let (sql, params) = expression.expand();
246
247 assert_eq!("A", &sql);
248 assert!(params.is_empty());
249 }
250
251 #[test]
252 fn expression_none_or() {
253 let expression = WhereCondition::default().or_where(WhereCondition::new("A", Vec::new()));
254 let (sql, params) = expression.expand();
255
256 assert_eq!("A", &sql);
257 assert!(params.is_empty());
258 }
259
260 #[test]
261 fn expression_complex_no_precedence() {
262 let expression = WhereCondition::new("A", Vec::new())
263 .and_where(WhereCondition::new("B", Vec::new()))
264 .or_where(WhereCondition::new("C", Vec::new()));
265 let (sql, params) = expression.expand();
266
267 assert_eq!("A and B or C", &sql);
268 assert!(params.is_empty());
269 }
270
271 #[test]
272 fn expression_complex_with_precedence() {
273 let sub_expression =
274 WhereCondition::new("A", Vec::new()).or_where(WhereCondition::new("B", Vec::new()));
275 let expression = WhereCondition::new("C", Vec::new()).and_where(sub_expression);
276 let (sql, params) = expression.expand();
277
278 assert_eq!("C and (A or B)", &sql);
279 assert!(params.is_empty());
280 }
281
282 #[test]
283 fn expression_complex_with_self_precedence() {
284 let sub_expression = WhereCondition::new("C", Vec::new());
285 let expression = WhereCondition::new("A", Vec::new())
286 .or_where(WhereCondition::new("B", Vec::new()))
287 .and_where(sub_expression);
288 let (sql, params) = expression.expand();
289
290 assert_eq!("(A or B) and C", &sql);
291 assert!(params.is_empty());
292 }
293
294 #[test]
295 fn expression_complex_with_both_precedence() {
296 let sub_expression =
297 WhereCondition::new("C", Vec::new()).or_where(WhereCondition::new("D", Vec::new()));
298 let expression = WhereCondition::new("A", Vec::new())
299 .or_where(WhereCondition::new("B", Vec::new()))
300 .and_where(sub_expression);
301 let (sql, params) = expression.expand();
302
303 assert_eq!("(A or B) and (C or D)", &sql);
304 assert!(params.is_empty());
305 }
306
307 #[test]
308 fn expression_sql_with_parameter() {
309 let expression = WhereCondition::new("A > ?*::pg_type", vec![Value::Integer(0)]);
310 let (sql, params) = expression.expand();
311
312 assert_eq!("A > ?1::pg_type", &sql);
313 assert_eq!(1, params.len());
314 }
315
316 #[test]
317 fn expression_sql_with_multiple_parameters() {
318 let expression = WhereCondition::new("A > ?*", vec![Value::Integer(0)])
319 .and_where(WhereCondition::new("B = ?*", vec![Value::Integer(1)]));
320 let (sql, params) = expression.expand();
321
322 assert_eq!("A > ?1 and B = ?2", &sql);
323 assert_eq!(2, params.len());
324 }
325
326 #[test]
327 fn expression_where_in() {
328 let expression = WhereCondition::where_in("A", vec![Value::Integer(0), Value::Integer(1)]);
329 let (sql, params) = expression.expand();
330
331 assert_eq!("A in (?1, ?2)".to_string(), sql);
332 assert_eq!(2, params.len());
333 }
334
335 #[test]
336 fn expression_sql_with_multiple_parameters_and_where_in() {
337 let expression = WhereCondition::new("A > ?*", vec![Value::Integer(0)])
338 .or_where(WhereCondition::new("B", Vec::new()))
339 .and_where(WhereCondition::where_in(
340 "C",
341 vec![
342 Value::Integer(100),
343 Value::Integer(101),
344 Value::Integer(102),
345 ],
346 ));
347
348 let (sql, params) = expression.expand();
349
350 assert_eq!("(A > ?1 or B) and C in (?2, ?3, ?4)", &sql);
351 assert_eq!(4, params.len());
352 }
353
354 #[test]
355 fn parameters_tosql() {
356 let expression = WhereCondition::new("a = ?*", vec![Value::String("whatever".into())]);
357 let (sql, params) = expression.expand();
358
359 assert_eq!("a = ?1", &sql);
360 assert_eq!(1, params.len());
361 }
362
363 #[test]
364 fn expression_get_all_default() {
365 struct Expression;
366 impl GetAllCondition for Expression {}
367
368 let expression = Expression::get_all_condition();
369 let (sql, params) = expression.expand();
370
371 assert_eq!("true".to_string(), sql);
372 assert!(params.is_empty());
373 }
374}