sqlx_query_dsl/
builder.rs1
2use sqlx::{MySql, QueryBuilder};
3use crate::params::{FilterExpr, Op, ExistsValue};
4use crate::whitelist::FieldWhitelist;
5
6pub fn build_filter<'a>(
13 qb: &mut QueryBuilder<'a, MySql>,
14 expr: &'a FilterExpr,
15 whitelist: &FieldWhitelist,
16) -> Result<(), String> {
17 match expr {
18 FilterExpr::And { and } => {
19 qb.push("(");
20 for (i, e) in and.iter().enumerate() {
21 if i > 0 { qb.push(" AND "); }
22 build_filter(qb, e, whitelist)?;
23 }
24 qb.push(")");
25 }
26 FilterExpr::Or { or } => {
27 qb.push("(");
28 for (i, e) in or.iter().enumerate() {
29 if i > 0 { qb.push(" OR "); }
30 build_filter(qb, e, whitelist)?;
31 }
32 qb.push(")");
33 }
34 FilterExpr::Cond(c) => match c.op {
35 Op::IsNull => {
36 let f = c.field.as_ref().unwrap();
37 whitelist.check(f)?;
38 qb.push(f).push(" IS NULL");
39 }
40 Op::IsNotNull => {
41 let f = c.field.as_ref().unwrap();
42 whitelist.check(f)?;
43 qb.push(f).push(" IS NOT NULL");
44 }
45 Op::Exists | Op::NotExists => {
46 let v: ExistsValue =
47 serde_json::from_value(c.value.clone().unwrap()).unwrap();
48 qb.push(if matches!(c.op, Op::Exists) { "EXISTS (" } else { "NOT EXISTS (" });
49 qb.push(&v.sql);
50 if let Some(bind) = v.bind {
51 for b in bind {
52 qb.push_bind(b);
53 }
54 }
55 qb.push(")");
56 }
57 _ => {
58 let f = c.field.as_ref().unwrap();
59 whitelist.check(f)?;
60 qb.push(f);
61 match c.op {
62 Op::Eq => { qb.push(" = "); qb.push_bind(c.value.as_ref().unwrap()); }
63 Op::Ne => { qb.push(" != "); qb.push_bind(c.value.as_ref().unwrap()); }
64 Op::Like => {
65 qb.push(" LIKE ");
66 qb.push_bind(format!("%{}%", c.value.as_ref().unwrap().as_str().unwrap()));
67 }
68 Op::Gt => { qb.push(" > "); qb.push_bind(c.value.as_ref().unwrap()); }
69 Op::Lt => { qb.push(" < "); qb.push_bind(c.value.as_ref().unwrap()); }
70 Op::Gte => { qb.push(" >= "); qb.push_bind(c.value.as_ref().unwrap()); }
71 Op::Lte => { qb.push(" <= "); qb.push_bind(c.value.as_ref().unwrap()); }
72 Op::In | Op::NotIn => {
73 let arr = c.value.as_ref().unwrap().as_array().unwrap();
74 qb.push(if matches!(c.op, Op::In) { " IN (" } else { " NOT IN (" });
75 for (i, v) in arr.iter().enumerate() {
76 if i > 0 { qb.push(", "); }
77 qb.push_bind(v);
78 }
79 qb.push(")");
80 }
81 Op::Between => {
82 let arr = c.value.as_ref().unwrap().as_array().unwrap();
83 qb.push(" BETWEEN ");
84 qb.push_bind(&arr[0]);
85 qb.push(" AND ");
86 qb.push_bind(&arr[1]);
87 }
88 Op::FindInSet => {
89 qb.push(" FIND_IN_SET(");
90 qb.push_bind(c.value.as_ref().unwrap());
91 qb.push(", ").push(f).push(")");
92 }
93 Op::JsonContains => {
94 qb.push(" JSON_CONTAINS(");
95 qb.push(f).push(", ");
96 qb.push_bind(c.value.as_ref().unwrap().to_string());
97 qb.push(")");
98 }
99 _ => {}
100 }
101 }
102 },
103 }
104 Ok(())
105}