1use crate::{
2 condition::ConditionKind,
3 group::{Conjunction, Node},
4 query::Query,
5 value::Value,
6};
7
8pub fn build_conditions(query: &Query, start: usize) -> (String, Vec<Value>) {
9 let mut values: Vec<Value> = vec![];
10 let mut n = start;
11 let parts: Vec<String> = query.nodes.iter()
12 .map(|node| build_node(node, &mut n, &mut values))
13 .collect();
14 (parts.join(" AND "), values)
15}
16
17fn build_node(node: &Node, n: &mut usize, values: &mut Vec<Value>) -> String {
18 match node {
19 Node::Cond(c) => build_cond(&c.kind, &c.values, n, values),
20 Node::Group(g) => {
21 let sep = match g.conjunction {
22 Conjunction::And => " AND ",
23 Conjunction::Or => " OR ",
24 };
25 let parts: Vec<String> = g.nodes.iter()
26 .map(|node| build_node(node, n, values))
27 .collect();
28 format!("({})", parts.join(sep))
29 }
30 }
31}
32
33fn build_cond(kind: &ConditionKind, vals: &[Value], n: &mut usize, values: &mut Vec<Value>) -> String {
34 match kind {
35 ConditionKind::Eq(col) => { let s = format!("{} = ?{}", col, n); values.push(vals[0].clone()); *n += 1; s }
36 ConditionKind::Ne(col) => { let s = format!("{} != ?{}", col, n); values.push(vals[0].clone()); *n += 1; s }
37 ConditionKind::Gt(col) => { let s = format!("{} > ?{}", col, n); values.push(vals[0].clone()); *n += 1; s }
38 ConditionKind::Gte(col) => { let s = format!("{} >= ?{}", col, n); values.push(vals[0].clone()); *n += 1; s }
39 ConditionKind::Lt(col) => { let s = format!("{} < ?{}", col, n); values.push(vals[0].clone()); *n += 1; s }
40 ConditionKind::Lte(col) => { let s = format!("{} <= ?{}", col, n); values.push(vals[0].clone()); *n += 1; s }
41 ConditionKind::IsNull(col) => format!("{} IS NULL", col),
42 ConditionKind::IsNotNull(col) => format!("{} IS NOT NULL", col),
43 ConditionKind::FilterOptional(col) => {
44 let s = format!("(?{0} IS NULL OR {1} = ?{0})", n, col);
45 values.push(vals[0].clone()); *n += 1; s
46 }
47 ConditionKind::FilterOptionalGte(col) => {
48 let s = format!("(?{0} IS NULL OR {1} >= ?{0})", n, col);
49 values.push(vals[0].clone()); *n += 1; s
50 }
51 ConditionKind::FilterOptionalLte(col) => {
52 let s = format!("(?{0} IS NULL OR {1} <= ?{0})", n, col);
53 values.push(vals[0].clone()); *n += 1; s
54 }
55 ConditionKind::In(col) => {
56 let phs: Vec<String> = (0..vals.len()).map(|i| format!("?{}", *n + i)).collect();
57 let s = format!("{} IN ({})", col, phs.join(", "));
58 values.extend(vals.iter().cloned());
59 *n += vals.len();
60 s
61 }
62 ConditionKind::NotIn(col) => {
63 let phs: Vec<String> = (0..vals.len()).map(|i| format!("?{}", *n + i)).collect();
64 let s = format!("{} NOT IN ({})", col, phs.join(", "));
65 values.extend(vals.iter().cloned());
66 *n += vals.len();
67 s
68 }
69 ConditionKind::Like(col) => { let s = format!("{} LIKE ?{}", col, n); values.push(vals[0].clone()); *n += 1; s }
70 ConditionKind::NotLike(col) => { let s = format!("{} NOT LIKE ?{}", col, n); values.push(vals[0].clone()); *n += 1; s }
71 ConditionKind::Between(col) => {
72 let s = format!("{} BETWEEN ?{} AND ?{}", col, *n, *n + 1);
73 values.push(vals[0].clone());
74 values.push(vals[1].clone());
75 *n += 2;
76 s
77 }
78 }
79}
80
81pub fn build_tail(query: &Query) -> String {
82 let mut sql = String::new();
83 if let Some((col, dir)) = &query.order {
84 sql.push_str(&format!(" ORDER BY {} {}", col, dir.as_sql()));
85 }
86 if let Some(l) = query.limit {
87 sql.push_str(&format!(" LIMIT {}", l));
88 }
89 if let Some(o) = query.offset {
90 sql.push_str(&format!(" OFFSET {}", o));
91 }
92 sql
93}