1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
use crate::{prelude::BuilderTrait, value::ToSqlValue};
#[derive(Clone, Debug)]
pub enum Filter {
Column(Column),
Builder(Box<dyn BuilderTrait>),
}
#[derive(Clone, Debug)]
pub struct Column {
pub table: String,
pub name: String,
pub values: Vec<Box<dyn ToSqlValue>>,
pub operator: &'static str,
pub preload: bool,
}
impl Filter {
pub fn to_sql(&self, bind_index: usize) -> (String, usize) {
match self {
Filter::Column(column) => match column.operator {
"(" => ("(".to_string(), 0),
")" => (")".to_string(), 0),
"IN" => {
let len = column.values.len();
if len == 0 {
("1 = 2".to_string(), 0)
} else {
(
format!(
"{}.{} IN ({})",
&column.table,
&column.name,
(0..len)
.map(|i| format!("${}", i + bind_index))
.collect::<Vec<_>>()
.join(", ")
),
len,
)
}
}
"NOT IN" => {
let len = column.values.len();
if len == 0 {
("1 = 2".to_string(), 0)
} else {
(
format!(
"{}.{} NOT IN ({})",
&column.table,
&column.name,
(0..len)
.map(|i| format!("${}", i + bind_index))
.collect::<Vec<_>>()
.join(", ")
),
len,
)
}
}
"OR" => ("OR".to_string(), 0),
"IS NULL" => (format!("{}.{} IS NULL", &column.table, &column.name), 0),
"IS NOT NULL" => (format!("{}.{} IS NOT NULL", &column.table, &column.name), 0),
"BETWEEN" => (
format!(
"{}.{} {} ${} AND ${}",
&column.table,
&column.name,
&column.operator,
bind_index,
bind_index + 1
),
2,
),
"LITERAL" => {
let mut bind_index_delta = 0;
let re = regex::Regex::new(r"\$\d+").unwrap();
let sql = re.replace_all(&column.name, |caps: ®ex::Captures| {
let n: usize = caps[0][1..].parse().unwrap();
bind_index_delta += 1;
format!("${}", n - 1 + bind_index)
});
(sql.to_string(), bind_index_delta)
}
_ => (
format!(
"{}.{} {} ${}",
&column.table, &column.name, &column.operator, bind_index
),
1,
),
},
Filter::Builder(builder) => {
let mut index: usize = bind_index;
let mut filters: Vec<String> = vec![];
for filter in builder.query_filters().iter() {
let (s, i) = filter.to_sql(index);
filters.push(s);
index += i;
}
(filters.join(" AND "), index - bind_index)
}
}
}
}