1
1
/*
2
- Joins and nullable
2
+ Macros and helpers
3
+ Null condition
3
4
*/
4
5
6
+ use super :: * ;
5
7
use diesel:: {
6
8
connection:: SimpleConnection ,
7
9
helper_types:: LeftJoinQuerySource ,
@@ -30,31 +32,12 @@ table! {
30
32
joinable ! ( join_to_test -> test ( test_id) ) ;
31
33
allow_tables_to_appear_in_same_query ! ( test, join_to_test) ;
32
34
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
-
52
35
#[ allow( non_camel_case_types) ]
53
36
enum Condition {
54
37
number_field( NumberFilter < i32 > ) ,
55
38
double_field( NumberFilter < f64 > ) ,
56
39
text_field( StringFilter ) ,
57
- bool_field( bool ) ,
40
+ bool_field( BooleanFilter ) ,
58
41
And ( Vec < Condition > ) ,
59
42
Or ( Vec < Condition > ) ,
60
43
}
@@ -63,64 +46,31 @@ type Source = LeftJoinQuerySource<test::dsl::test, join_to_test::dsl::join_to_te
63
46
// Need this type for common condition expressions
64
47
type BoxedCondition = Box < dyn BoxableExpression < Source , Sqlite , SqlType = Nullable < Bool > > > ;
65
48
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
66
69
fn create_filter ( conditions : Vec < Condition > , and_or : AndOr ) -> Option < BoxedCondition > {
67
70
conditions
68
71
. into_iter ( )
69
72
// 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)
124
74
// Reduce to a boxed_condition1.and(boxed_condition2).and(boxed_condition3)...
125
75
. fold ( None , |boxed_conditions, boxed_condition| {
126
76
Some ( match boxed_conditions {
@@ -240,7 +190,7 @@ fn test() {
240
190
let condition = create__and_filter ( vec ! [
241
191
Condition :: number_field( NumberFilter :: GreaterThen ( 1 ) ) ,
242
192
Condition :: text_field( StringFilter :: Like ( "%4%" . to_string( ) ) ) ,
243
- Condition :: bool_field( true ) ,
193
+ Condition :: bool_field( BooleanFilter :: True ) ,
244
194
] )
245
195
. unwrap ( ) ;
246
196
let result = vec ! [ "4.2" . to_string( ) ] ;
@@ -275,10 +225,10 @@ fn test() {
275
225
let condition = create__and_filter ( vec ! [
276
226
Condition :: number_field( NumberFilter :: Equal ( 5 ) ) ,
277
227
Condition :: Or ( vec![
278
- Condition :: bool_field( true ) ,
228
+ Condition :: bool_field( BooleanFilter :: True ) ,
279
229
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 ) ,
282
232
] ) ,
283
233
] ) ,
284
234
] )
@@ -300,10 +250,10 @@ fn test() {
300
250
Condition :: number_field( NumberFilter :: Equal ( 5 ) ) ,
301
251
Condition :: And ( vec![
302
252
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 ) ,
305
255
] ) ,
306
- Condition :: bool_field( false ) ,
256
+ Condition :: bool_field( BooleanFilter :: False ) ,
307
257
] ) ,
308
258
] )
309
259
. unwrap ( ) ;
@@ -351,4 +301,61 @@ fn test() {
351
301
. load:: <String >( & mut connection)
352
302
. unwrap( )
353
303
) ;
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
+ ) ;
354
361
}
0 commit comments