@@ -497,31 +497,8 @@ fn apply_expect(view: &ResponseView, expect: &QueryExpect, label: &str) {
497497 for ( field, expected) in & ne. filters {
498498 let expected = expected. clone ( ) ;
499499 let field_name = field. clone ( ) ;
500- view. assert_filter ( entity, field, move |n| match & expected {
501- serde_json:: Value :: Object ( m) if m. contains_key ( "starts_with" ) => {
502- let prefix = m[ "starts_with" ] . as_str ( ) . unwrap ( ) ;
503- n. prop_str ( & field_name)
504- . is_some_and ( |v| v. starts_with ( prefix) )
505- }
506- serde_json:: Value :: Object ( m) if m. contains_key ( "contains" ) => {
507- let sub = m[ "contains" ] . as_str ( ) . unwrap ( ) ;
508- n. prop_str ( & field_name) . is_some_and ( |v| v. contains ( sub) )
509- }
510- serde_json:: Value :: Object ( m) if m. contains_key ( "ends_with" ) => {
511- let suffix = m[ "ends_with" ] . as_str ( ) . unwrap ( ) ;
512- n. prop_str ( & field_name) . is_some_and ( |v| v. ends_with ( suffix) )
513- }
514- serde_json:: Value :: Object ( m) if m. contains_key ( "in" ) => {
515- let vals = m[ "in" ] . as_array ( ) . unwrap ( ) ;
516- n. prop ( & field_name) . is_some_and ( |p| vals. contains ( p) )
517- }
518- serde_json:: Value :: Object ( m) if m. contains_key ( "gte" ) => {
519- let threshold = m[ "gte" ] . as_i64 ( ) . unwrap ( ) ;
520- n. prop_i64 ( & field_name)
521- . or_else ( || n. prop_str ( & field_name) . and_then ( |s| s. parse ( ) . ok ( ) ) )
522- . is_some_and ( |v| v >= threshold)
523- }
524- _ => n. prop ( & field_name) == Some ( & expected) ,
500+ view. assert_filter ( entity, field, move |n| {
501+ eval_filter_predicate ( n, & field_name, & expected)
525502 } ) ;
526503 }
527504 }
@@ -646,6 +623,79 @@ fn apply_expect(view: &ResponseView, expect: &QueryExpect, label: &str) {
646623 }
647624}
648625
626+ fn eval_filter_predicate (
627+ n : & query_engine:: formatters:: GraphNode ,
628+ field : & str ,
629+ expected : & serde_json:: Value ,
630+ ) -> bool {
631+ match expected {
632+ serde_json:: Value :: Object ( m) if m. contains_key ( "starts_with" ) => n
633+ . prop_str ( field)
634+ . is_some_and ( |v| v. starts_with ( m[ "starts_with" ] . as_str ( ) . unwrap ( ) ) ) ,
635+ serde_json:: Value :: Object ( m) if m. contains_key ( "contains" ) => n
636+ . prop_str ( field)
637+ . is_some_and ( |v| v. contains ( m[ "contains" ] . as_str ( ) . unwrap ( ) ) ) ,
638+ serde_json:: Value :: Object ( m) if m. contains_key ( "ends_with" ) => n
639+ . prop_str ( field)
640+ . is_some_and ( |v| v. ends_with ( m[ "ends_with" ] . as_str ( ) . unwrap ( ) ) ) ,
641+ serde_json:: Value :: Object ( m) if m. contains_key ( "in" ) => {
642+ let vals = m[ "in" ] . as_array ( ) . unwrap ( ) ;
643+ n. prop ( field) . is_some_and ( |p| vals. contains ( p) )
644+ }
645+ serde_json:: Value :: Object ( m)
646+ if m. get ( "is_null" ) == Some ( & serde_json:: Value :: Bool ( true ) ) =>
647+ {
648+ !n. properties . is_empty ( ) && !n. has_prop ( field)
649+ }
650+ serde_json:: Value :: Object ( m)
651+ if m. get ( "is_not_null" ) == Some ( & serde_json:: Value :: Bool ( true ) ) =>
652+ {
653+ n. has_prop ( field)
654+ }
655+ serde_json:: Value :: Object ( m) if m. contains_key ( "gte" ) => {
656+ let threshold = & m[ "gte" ] ;
657+ if let Some ( t) = threshold. as_i64 ( ) {
658+ n. prop_i64 ( field)
659+ . or_else ( || n. prop_str ( field) . and_then ( |s| s. parse ( ) . ok ( ) ) )
660+ . is_some_and ( |v| v >= t)
661+ } else {
662+ let t = threshold. as_str ( ) . unwrap ( ) ;
663+ n. prop_str ( field) . is_some_and ( |v| v >= t)
664+ }
665+ }
666+ serde_json:: Value :: Object ( m) if m. contains_key ( "lte" ) => {
667+ let t = m[ "lte" ] . as_str ( ) . unwrap ( ) ;
668+ n. prop_str ( field) . is_some_and ( |v| v <= t)
669+ }
670+ serde_json:: Value :: Object ( m) if m. contains_key ( "lt" ) => {
671+ let t = m[ "lt" ] . as_str ( ) . unwrap ( ) ;
672+ n. prop_str ( field) . is_some_and ( |v| v < t)
673+ }
674+ serde_json:: Value :: Object ( m) if m. contains_key ( "eq" ) => {
675+ let val = & m[ "eq" ] ;
676+ n. prop ( field) == Some ( val)
677+ || match val {
678+ serde_json:: Value :: Number ( num) => {
679+ n. prop_str ( field) . is_some_and ( |s| s == num. to_string ( ) )
680+ }
681+ serde_json:: Value :: String ( s) => n. prop_str ( field) == Some ( s. as_str ( ) ) ,
682+ _ => false ,
683+ }
684+ }
685+ // Compound filter: all sub-predicates must pass
686+ serde_json:: Value :: Object ( m) if m. len ( ) > 1 => m. iter ( ) . all ( |( op, val) | {
687+ let sub =
688+ serde_json:: Value :: Object ( std:: iter:: once ( ( op. clone ( ) , val. clone ( ) ) ) . collect ( ) ) ;
689+ eval_filter_predicate ( n, field, & sub)
690+ } ) ,
691+ serde_json:: Value :: Object ( m) if m. len ( ) == 1 => {
692+ let op = m. keys ( ) . next ( ) . unwrap ( ) ;
693+ panic ! ( "unsupported filter operator '{op}' on field '{field}'" )
694+ }
695+ _ => n. prop ( field) == Some ( expected) ,
696+ }
697+ }
698+
649699fn assert_property (
650700 node : & dyn NodeExt ,
651701 prop : & str ,
0 commit comments