@@ -504,23 +504,25 @@ type EnumParser = fn(&str) -> Option<i64>;
504504/// Static map from column names to enum parsers
505505static ENUM_PARSERS : Map < & ' static str , EnumParser > = phf_map ! {
506506 "scan_state" => ScanState :: from_token,
507- "item_type" => ItemType :: from_token,
508- "change_type" => ChangeType :: from_token,
509- "alert_type" => AlertType :: from_token,
510- "alert_status" => AlertStatus :: from_token,
511- "val" => ValidationState :: from_token,
512- "val_old" => ValidationState :: from_token,
513- "val_new" => ValidationState :: from_token,
514- "access" => Access :: from_token,
515- "access_old" => Access :: from_token,
516- "access_new" => Access :: from_token,
507+ "item_type" => ItemType :: from_token,
508+ "change_type" => ChangeType :: from_token,
509+ "alert_type" => AlertType :: from_token,
510+ "alert_status" => AlertStatus :: from_token,
511+ "val" => ValidationState :: from_token,
512+ "val_old" => ValidationState :: from_token,
513+ "val_new" => ValidationState :: from_token,
514+ "access" => Access :: from_token,
515+ "access_old" => Access :: from_token,
516+ "access_new" => Access :: from_token,
517517} ;
518518
519519/// Filter for integer-backed enums (like scan_state)
520520#[ derive( Debug ) ]
521521pub struct EnumFilter {
522522 enum_col_db : & ' static str ,
523523 enum_vals : Vec < i64 > ,
524+ match_null : bool ,
525+ match_not_null : bool ,
524526}
525527
526528impl Filter for EnumFilter {
@@ -529,10 +531,32 @@ impl Filter for EnumFilter {
529531 let mut pred_vec: Vec < Box < dyn ToSql > > = Vec :: new ( ) ;
530532 let mut first = true ;
531533
532- if self . enum_vals . len ( ) > 1 {
534+ let mut pred_count = self . enum_vals . len ( ) ;
535+ if self . match_null {
536+ pred_count += 1
537+ } ;
538+ if self . match_not_null {
539+ pred_count += 1
540+ } ;
541+
542+ if pred_count > 1 {
533543 pred_str. push ( '(' ) ;
534544 }
535545
546+ // if match_null is true, it will always be first
547+ if self . match_null {
548+ first = false ;
549+ pred_str. push_str ( & format ! ( "({} IS NULL)" , & self . enum_col_db) ) ;
550+ }
551+
552+ if self . match_not_null {
553+ match first {
554+ true => first = false ,
555+ false => pred_str. push_str ( " OR " ) ,
556+ }
557+ pred_str. push_str ( & format ! ( "({} IS NOT NULL)" , & self . enum_col_db) ) ;
558+ }
559+
536560 for enum_val in & self . enum_vals {
537561 match first {
538562 true => first = false ,
@@ -543,7 +567,7 @@ impl Filter for EnumFilter {
543567 pred_vec. push ( Box :: new ( * enum_val) ) ;
544568 }
545569
546- if self . enum_vals . len ( ) > 1 {
570+ if pred_count > 1 {
547571 pred_str. push ( ')' ) ;
548572 }
549573
@@ -556,6 +580,8 @@ impl EnumFilter {
556580 EnumFilter {
557581 enum_col_db,
558582 enum_vals : Vec :: new ( ) ,
583+ match_null : false ,
584+ match_not_null : false ,
559585 }
560586 }
561587
@@ -583,14 +609,20 @@ impl EnumFilter {
583609
584610 // Parse each enum value using the parser
585611 for enum_val_pair in iter {
586- let token = enum_val_pair. as_str ( ) ;
587- match parser ( token) {
588- Some ( db_val) => enum_filter. enum_vals . push ( db_val) ,
589- None => {
590- return Err ( FsPulseError :: CustomParsingError ( format ! (
591- "Invalid {} value: '{}'" ,
592- enum_col, token
593- ) ) )
612+ match enum_val_pair. as_rule ( ) {
613+ Rule :: null => enum_filter. match_null = true ,
614+ Rule :: not_null => enum_filter. match_not_null = true ,
615+ _ => {
616+ let token_str = enum_val_pair. as_str ( ) ;
617+ match parser ( token_str) {
618+ Some ( db_val) => enum_filter. enum_vals . push ( db_val) ,
619+ None => {
620+ return Err ( FsPulseError :: CustomParsingError ( format ! (
621+ "Invalid {} value: '{}'" ,
622+ enum_col, token_str
623+ ) ) )
624+ }
625+ }
594626 }
595627 }
596628 }
@@ -1525,6 +1557,8 @@ mod tests {
15251557 let filter = EnumFilter {
15261558 enum_col_db : "state" ,
15271559 enum_vals : vec ! [ 1 ] ,
1560+ match_null : false ,
1561+ match_not_null : false ,
15281562 } ;
15291563
15301564 let result = filter. to_predicate_parts ( ) ;
@@ -1539,6 +1573,8 @@ mod tests {
15391573 let filter = EnumFilter {
15401574 enum_col_db : "state" ,
15411575 enum_vals : vec ! [ 1 , 4 , 6 ] ,
1576+ match_null : false ,
1577+ match_not_null : false ,
15421578 } ;
15431579
15441580 let result = filter. to_predicate_parts ( ) ;
@@ -1548,6 +1584,58 @@ mod tests {
15481584 assert_eq ! ( pred_vec. len( ) , 3 ) ;
15491585 }
15501586
1587+ #[ test]
1588+ fn test_enum_filter_predicate_null_only ( ) {
1589+ let filter = EnumFilter {
1590+ enum_col_db : "state" ,
1591+ enum_vals : vec ! [ ] ,
1592+ match_null : true ,
1593+ match_not_null : false ,
1594+ } ;
1595+ let ( pred_str, pred_vec) = filter. to_predicate_parts ( ) . unwrap ( ) ;
1596+ assert_eq ! ( pred_str, "(state IS NULL)" ) ;
1597+ assert_eq ! ( pred_vec. len( ) , 0 ) ;
1598+ }
1599+
1600+ #[ test]
1601+ fn test_enum_filter_predicate_not_null_only ( ) {
1602+ let filter = EnumFilter {
1603+ enum_col_db : "state" ,
1604+ enum_vals : vec ! [ ] ,
1605+ match_null : false ,
1606+ match_not_null : true ,
1607+ } ;
1608+ let ( pred_str, pred_vec) = filter. to_predicate_parts ( ) . unwrap ( ) ;
1609+ assert_eq ! ( pred_str, "(state IS NOT NULL)" ) ;
1610+ assert_eq ! ( pred_vec. len( ) , 0 ) ;
1611+ }
1612+
1613+ #[ test]
1614+ fn test_enum_filter_predicate_null_with_values ( ) {
1615+ let filter = EnumFilter {
1616+ enum_col_db : "state" ,
1617+ enum_vals : vec ! [ 1 , 2 ] ,
1618+ match_null : true ,
1619+ match_not_null : false ,
1620+ } ;
1621+ let ( pred_str, pred_vec) = filter. to_predicate_parts ( ) . unwrap ( ) ;
1622+ assert_eq ! ( pred_str, "((state IS NULL) OR (state = ?) OR (state = ?))" ) ;
1623+ assert_eq ! ( pred_vec. len( ) , 2 ) ;
1624+ }
1625+
1626+ #[ test]
1627+ fn test_enum_filter_predicate_null_and_not_null ( ) {
1628+ let filter = EnumFilter {
1629+ enum_col_db : "state" ,
1630+ enum_vals : vec ! [ ] ,
1631+ match_null : true ,
1632+ match_not_null : true ,
1633+ } ;
1634+ let ( pred_str, pred_vec) = filter. to_predicate_parts ( ) . unwrap ( ) ;
1635+ assert_eq ! ( pred_str, "((state IS NULL) OR (state IS NOT NULL))" ) ;
1636+ assert_eq ! ( pred_vec. len( ) , 0 ) ;
1637+ }
1638+
15511639 // ==================================================================================
15521640 // Int Filter Tests
15531641 // ==================================================================================
0 commit comments