Skip to content

Commit 9c938ae

Browse files
committed
Add macros
1 parent 0213409 commit 9c938ae

File tree

2 files changed

+155
-82
lines changed

2 files changed

+155
-82
lines changed

src/dynamic_filters.rs

+89-82
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
/*
2-
Joins and nullable
2+
Macros and helpers
3+
Null condition
34
*/
45

6+
use super::*;
57
use diesel::{
68
connection::SimpleConnection,
79
helper_types::LeftJoinQuerySource,
@@ -30,31 +32,12 @@ table! {
3032
joinable!(join_to_test -> test (test_id));
3133
allow_tables_to_appear_in_same_query!(test, join_to_test);
3234

33-
// Filters for "numbers"
34-
enum NumberFilter<T> {
35-
Equal(T),
36-
NotEqual(T),
37-
GreaterThen(T),
38-
LowerThen(T),
39-
}
40-
// Filters for "strings"
41-
enum StringFilter {
42-
Equal(String),
43-
NotEqual(String),
44-
Like(String),
45-
}
46-
47-
enum AndOr {
48-
And,
49-
Or,
50-
}
51-
5235
#[allow(non_camel_case_types)]
5336
enum Condition {
5437
number_field(NumberFilter<i32>),
5538
double_field(NumberFilter<f64>),
5639
text_field(StringFilter),
57-
bool_field(bool),
40+
bool_field(BooleanFilter),
5841
And(Vec<Condition>),
5942
Or(Vec<Condition>),
6043
}
@@ -63,64 +46,31 @@ type Source = LeftJoinQuerySource<test::dsl::test, join_to_test::dsl::join_to_te
6346
// Need this type for common condition expressions
6447
type BoxedCondition = Box<dyn BoxableExpression<Source, Sqlite, SqlType = Nullable<Bool>>>;
6548

49+
impl Condition {
50+
fn to_boxed_condition(self) -> Option<BoxedCondition> {
51+
Some(match self {
52+
Condition::number_field(f) => number_filter!(f, test::dsl::number_field),
53+
Condition::double_field(f) => number_filter!(f, join_to_test::dsl::double_field),
54+
Condition::text_field(f) => string_filter!(f, test::dsl::text_field),
55+
Condition::bool_field(value) => boolean_filter!(value, test::dsl::bool_field),
56+
Condition::And(conditions) => match create_filter(conditions, AndOr::And) {
57+
Some(boxed_condition) => boxed_condition,
58+
None => return None,
59+
},
60+
Condition::Or(conditions) => match create_filter(conditions, AndOr::Or) {
61+
Some(boxed_condition) => boxed_condition,
62+
None => return None,
63+
},
64+
})
65+
}
66+
}
67+
68+
// This method can also be made into a macro, but it should be fine to just duplicate
6669
fn create_filter(conditions: Vec<Condition>, and_or: AndOr) -> Option<BoxedCondition> {
6770
conditions
6871
.into_iter()
6972
// Map into array of boxed conditions
70-
.filter_map::<BoxedCondition, _>(|condition| {
71-
Some(match condition {
72-
Condition::number_field(f) => match f {
73-
NumberFilter::Equal(value) => {
74-
Box::new(test::dsl::number_field.eq(value).nullable())
75-
}
76-
NumberFilter::NotEqual(value) => {
77-
Box::new(test::dsl::number_field.ne(value).nullable())
78-
}
79-
NumberFilter::GreaterThen(value) => {
80-
Box::new(test::dsl::number_field.gt(value).nullable())
81-
}
82-
NumberFilter::LowerThen(value) => {
83-
Box::new(test::dsl::number_field.lt(value).nullable())
84-
}
85-
},
86-
Condition::double_field(f) => match f {
87-
NumberFilter::Equal(value) => {
88-
Box::new(join_to_test::dsl::double_field.eq(value).nullable())
89-
}
90-
NumberFilter::NotEqual(value) => {
91-
Box::new(join_to_test::dsl::double_field.ne(value).nullable())
92-
}
93-
NumberFilter::GreaterThen(value) => {
94-
Box::new(join_to_test::dsl::double_field.gt(value).nullable())
95-
}
96-
NumberFilter::LowerThen(value) => {
97-
Box::new(join_to_test::dsl::double_field.lt(value).nullable())
98-
}
99-
},
100-
Condition::text_field(f) => match f {
101-
StringFilter::Equal(value) => {
102-
Box::new(test::dsl::text_field.eq(value).nullable())
103-
}
104-
StringFilter::NotEqual(value) => {
105-
Box::new(test::dsl::text_field.ne(value).nullable())
106-
}
107-
StringFilter::Like(value) => {
108-
Box::new(test::dsl::text_field.like(value).nullable())
109-
}
110-
},
111-
Condition::bool_field(value) => {
112-
Box::new(test::dsl::bool_field.eq(value).nullable())
113-
}
114-
Condition::And(conditions) => match create_filter(conditions, AndOr::And) {
115-
Some(boxed_condition) => boxed_condition,
116-
None => return None,
117-
},
118-
Condition::Or(conditions) => match create_filter(conditions, AndOr::Or) {
119-
Some(boxed_condition) => boxed_condition,
120-
None => return None,
121-
},
122-
})
123-
})
73+
.filter_map::<BoxedCondition, _>(Condition::to_boxed_condition)
12474
// Reduce to a boxed_condition1.and(boxed_condition2).and(boxed_condition3)...
12575
.fold(None, |boxed_conditions, boxed_condition| {
12676
Some(match boxed_conditions {
@@ -240,7 +190,7 @@ fn test() {
240190
let condition = create__and_filter(vec![
241191
Condition::number_field(NumberFilter::GreaterThen(1)),
242192
Condition::text_field(StringFilter::Like("%4%".to_string())),
243-
Condition::bool_field(true),
193+
Condition::bool_field(BooleanFilter::True),
244194
])
245195
.unwrap();
246196
let result = vec!["4.2".to_string()];
@@ -275,10 +225,10 @@ fn test() {
275225
let condition = create__and_filter(vec![
276226
Condition::number_field(NumberFilter::Equal(5)),
277227
Condition::Or(vec![
278-
Condition::bool_field(true),
228+
Condition::bool_field(BooleanFilter::True),
279229
Condition::And(vec![
280-
Condition::bool_field(true),
281-
Condition::bool_field(false),
230+
Condition::bool_field(BooleanFilter::True),
231+
Condition::bool_field(BooleanFilter::False),
282232
]),
283233
]),
284234
])
@@ -300,10 +250,10 @@ fn test() {
300250
Condition::number_field(NumberFilter::Equal(5)),
301251
Condition::And(vec![
302252
Condition::Or(vec![
303-
Condition::bool_field(true),
304-
Condition::bool_field(true),
253+
Condition::bool_field(BooleanFilter::True),
254+
Condition::bool_field(BooleanFilter::True),
305255
]),
306-
Condition::bool_field(false),
256+
Condition::bool_field(BooleanFilter::False),
307257
]),
308258
])
309259
.unwrap();
@@ -351,4 +301,61 @@ fn test() {
351301
.load::<String>(&mut connection)
352302
.unwrap()
353303
);
304+
305+
connection
306+
.batch_execute(
307+
r#"
308+
INSERT INTO test
309+
(id, number_field)
310+
VALUES
311+
('7.1', 7);
312+
313+
INSERT INTO test
314+
(id, number_field)
315+
VALUES
316+
('7.2', 7);
317+
318+
INSERT INTO join_to_test
319+
(id, test_id, double_field)
320+
VALUES
321+
('7', '7.1', 0);
322+
"#,
323+
)
324+
.unwrap();
325+
326+
let condition = create__and_filter(vec![
327+
Condition::double_field(NumberFilter::IsNull),
328+
Condition::number_field(NumberFilter::Equal(7)),
329+
])
330+
.unwrap();
331+
332+
let result = vec!["7.2".to_string()];
333+
334+
assert_eq!(
335+
result,
336+
test::dsl::test
337+
.left_join(join_to_test::dsl::join_to_test)
338+
.filter(condition)
339+
.select(test::dsl::id)
340+
.load::<String>(&mut connection)
341+
.unwrap()
342+
);
343+
344+
let condition = create__and_filter(vec![
345+
Condition::double_field(NumberFilter::IsNotNull),
346+
Condition::number_field(NumberFilter::Equal(7)),
347+
])
348+
.unwrap();
349+
350+
let result = vec!["7.1".to_string()];
351+
352+
assert_eq!(
353+
result,
354+
test::dsl::test
355+
.left_join(join_to_test::dsl::join_to_test)
356+
.filter(condition)
357+
.select(test::dsl::id)
358+
.load::<String>(&mut connection)
359+
.unwrap()
360+
);
354361
}

src/lib.rs

+66
Original file line numberDiff line numberDiff line change
@@ -1 +1,67 @@
11
mod dynamic_filters;
2+
3+
// Filters for "numbers"
4+
enum NumberFilter<T> {
5+
Equal(T),
6+
NotEqual(T),
7+
GreaterThen(T),
8+
LowerThen(T),
9+
IsNull,
10+
IsNotNull,
11+
}
12+
13+
macro_rules! number_filter {
14+
($filter:ident, $dsl_field:expr ) => {{
15+
match $filter {
16+
NumberFilter::Equal(value) => Box::new($dsl_field.eq(value).nullable()),
17+
NumberFilter::NotEqual(value) => Box::new($dsl_field.ne(value).nullable()),
18+
NumberFilter::GreaterThen(value) => Box::new($dsl_field.gt(value).nullable()),
19+
NumberFilter::LowerThen(value) => Box::new($dsl_field.lt(value).nullable()),
20+
NumberFilter::IsNull => Box::new($dsl_field.is_null().nullable()),
21+
NumberFilter::IsNotNull => Box::new($dsl_field.is_not_null().nullable()),
22+
}
23+
}};
24+
}
25+
26+
enum StringFilter {
27+
Equal(String),
28+
NotEqual(String),
29+
Like(String),
30+
}
31+
32+
macro_rules! string_filter {
33+
($filter:ident, $dsl_field:expr ) => {{
34+
match $filter {
35+
StringFilter::Equal(value) => Box::new($dsl_field.eq(value).nullable()),
36+
StringFilter::NotEqual(value) => Box::new($dsl_field.ne(value).nullable()),
37+
StringFilter::Like(value) => Box::new($dsl_field.like(value).nullable()),
38+
}
39+
}};
40+
}
41+
42+
enum BooleanFilter {
43+
True,
44+
False,
45+
IsNull,
46+
IsNotNull,
47+
}
48+
49+
macro_rules! boolean_filter {
50+
($filter:ident, $dsl_field:expr ) => {{
51+
match $filter {
52+
BooleanFilter::True => Box::new($dsl_field.eq(true).nullable()),
53+
BooleanFilter::False => Box::new($dsl_field.eq(false).nullable()),
54+
BooleanFilter::IsNull => Box::new($dsl_field.is_null().nullable()),
55+
BooleanFilter::IsNotNull => Box::new($dsl_field.is_not_null().nullable()),
56+
}
57+
}};
58+
}
59+
60+
enum AndOr {
61+
And,
62+
Or,
63+
}
64+
65+
use boolean_filter;
66+
use number_filter;
67+
use string_filter;

0 commit comments

Comments
 (0)