@@ -238,11 +238,15 @@ fn field_filter_input_values(
238238                        // `where: { others: ["some-id", "other-id"] }`. In both cases, 
239239                        // we allow ID strings as the values to be passed to these 
240240                        // filters. 
241-                         field_scalar_filter_input_values ( 
241+                         let   mut  input_values =  field_scalar_filter_input_values ( 
242242                            schema, 
243243                            field, 
244244                            & ScalarType :: new ( String :: from ( "String" ) ) , 
245-                         ) 
245+                         ) ; 
246+ 
247+                         extend_with_child_filter_input_value ( field,  name,  & mut  input_values) ; 
248+ 
249+                         input_values
246250                    } 
247251                } 
248252                TypeDefinition :: Scalar ( ref  t)  => field_scalar_filter_input_values ( schema,  field,  t) , 
@@ -306,6 +310,19 @@ fn field_scalar_filter_input_values(
306310    . collect ( ) 
307311} 
308312
313+ /// Appends a child filter to input values 
314+ fn  extend_with_child_filter_input_value ( 
315+     field :  & Field , 
316+     field_type_name :  & String , 
317+     input_values :  & mut  Vec < InputValue > , 
318+ )  { 
319+     input_values. push ( input_value ( 
320+         & format ! ( "{}_" ,  field. name) , 
321+         "" , 
322+         Type :: NamedType ( format ! ( "{}_filter" ,  field_type_name) ) , 
323+     ) ) ; 
324+ } 
325+ 
309326/// Generates `*_filter` input values for the given enum field. 
310327fn  field_enum_filter_input_values ( 
311328    _schema :  & Document , 
@@ -338,40 +355,51 @@ fn field_list_filter_input_values(
338355        // Decide what type of values can be passed to the filter. In the case 
339356        // one-to-many or many-to-many object or interface fields that are not 
340357        // derived, we allow ID strings to be passed on. 
341-         let  input_field_type = match  typedef { 
342-             TypeDefinition :: Interface ( _ )  |  TypeDefinition :: Object ( _ )  => { 
358+         let  ( input_field_type,  parent_type_name )  = match  typedef { 
359+             TypeDefinition :: Object ( parent )  => { 
343360                if  ast:: get_derived_from_directive ( field) . is_some ( )  { 
344361                    return  None ; 
345362                }  else  { 
346-                     Type :: NamedType ( "String" . into ( ) ) 
363+                     ( Type :: NamedType ( "String" . into ( ) ) ,   Some ( parent . name . clone ( ) ) ) 
347364                } 
348365            } 
349-             TypeDefinition :: Scalar ( ref  t)  => Type :: NamedType ( t. name . to_owned ( ) ) , 
350-             TypeDefinition :: Enum ( ref  t)  => Type :: NamedType ( t. name . to_owned ( ) ) , 
366+             TypeDefinition :: Interface ( parent)  => { 
367+                 if  ast:: get_derived_from_directive ( field) . is_some ( )  { 
368+                     return  None ; 
369+                 }  else  { 
370+                     ( Type :: NamedType ( "String" . into ( ) ) ,  Some ( parent. name . clone ( ) ) ) 
371+                 } 
372+             } 
373+             TypeDefinition :: Scalar ( ref  t)  => ( Type :: NamedType ( t. name . to_owned ( ) ) ,  None ) , 
374+             TypeDefinition :: Enum ( ref  t)  => ( Type :: NamedType ( t. name . to_owned ( ) ) ,  None ) , 
351375            TypeDefinition :: InputObject ( _)  | TypeDefinition :: Union ( _)  => return  None , 
352376        } ; 
353377
354-         Some ( 
355-             vec ! [ 
356-                 "" , 
357-                 "not" , 
358-                 "contains" , 
359-                 "contains_nocase" , 
360-                 "not_contains" , 
361-                 "not_contains_nocase" , 
362-             ] 
363-             . into_iter ( ) 
364-             . map ( |filter_type| { 
365-                 input_value ( 
366-                     & field. name , 
367-                     filter_type, 
368-                     Type :: ListType ( Box :: new ( Type :: NonNullType ( Box :: new ( 
369-                         input_field_type. clone ( ) , 
370-                     ) ) ) ) , 
371-                 ) 
372-             } ) 
373-             . collect ( ) , 
374-         ) 
378+         let  mut  input_values:  Vec < InputValue >  = vec ! [ 
379+             "" , 
380+             "not" , 
381+             "contains" , 
382+             "contains_nocase" , 
383+             "not_contains" , 
384+             "not_contains_nocase" , 
385+         ] 
386+         . into_iter ( ) 
387+         . map ( |filter_type| { 
388+             input_value ( 
389+                 & field. name , 
390+                 filter_type, 
391+                 Type :: ListType ( Box :: new ( Type :: NonNullType ( Box :: new ( 
392+                     input_field_type. clone ( ) , 
393+                 ) ) ) ) , 
394+             ) 
395+         } ) 
396+         . collect ( ) ; 
397+ 
398+         if  let  Some ( parent)  = parent_type_name { 
399+             extend_with_child_filter_input_value ( field,  & parent,  & mut  input_values) ; 
400+         } 
401+ 
402+         Some ( input_values) 
375403    } ) 
376404} 
377405
@@ -916,6 +944,7 @@ mod tests {
916944                "pets_contains_nocase" , 
917945                "pets_not_contains" , 
918946                "pets_not_contains_nocase" , 
947+                 "pets_" , 
919948                "favoriteFurType" , 
920949                "favoriteFurType_not" , 
921950                "favoriteFurType_in" , 
@@ -940,6 +969,7 @@ mod tests {
940969                "favoritePet_ends_with_nocase" , 
941970                "favoritePet_not_ends_with" , 
942971                "favoritePet_not_ends_with_nocase" , 
972+                 "favoritePet_" , 
943973                "_change_block" 
944974            ] 
945975            . iter( ) 
@@ -1170,4 +1200,56 @@ type Gravatar @entity {
11701200        } 
11711201        . expect ( "\" metadata\"  field is missing on Query type" ) ; 
11721202    } 
1203+ 
1204+     #[ test]  
1205+     fn  api_schema_contains_child_entity_filter_on_lists ( )  { 
1206+         let  input_schema = parse_schema ( 
1207+             r#" 
1208+                 type Note @entity { 
1209+                     id: ID! 
1210+                     text: String! 
1211+                     author: User! @derived(field: "id") 
1212+                 } 
1213+                
1214+                 type User @entity { 
1215+                     id: ID! 
1216+                     dateOfBirth: String 
1217+                     country: String 
1218+                     notes: [Note!]! 
1219+                 } 
1220+             "# , 
1221+         ) 
1222+         . expect ( "Failed to parse input schema" ) ; 
1223+         let  schema = api_schema ( & input_schema) . expect ( "Failed to derived API schema" ) ; 
1224+ 
1225+         println ! ( "{}" ,  schema) ; 
1226+ 
1227+         let  user_filter = schema
1228+             . get_named_type ( "User_filter" ) 
1229+             . expect ( "User_filter type is missing in derived API schema" ) ; 
1230+ 
1231+         let  filter_type = match  user_filter { 
1232+             TypeDefinition :: InputObject ( t)  => Some ( t) , 
1233+             _ => None , 
1234+         } 
1235+         . expect ( "User_filter type is not an input object" ) ; 
1236+ 
1237+         let  user_notes_filter_field = filter_type
1238+             . fields 
1239+             . iter ( ) 
1240+             . find_map ( |field| { 
1241+                 if  field. name  == "notes_"  { 
1242+                     Some ( field) 
1243+                 }  else  { 
1244+                     None 
1245+                 } 
1246+             } ) 
1247+             . expect ( "notes_ field is missing in the User_filter input object" ) ; 
1248+ 
1249+         assert_eq ! ( user_notes_filter_field. name,  "notes_" ) ; 
1250+         assert_eq ! ( 
1251+             user_notes_filter_field. value_type, 
1252+             Type :: NamedType ( String :: from( "Note_filter" ) ) 
1253+         ) ; 
1254+     } 
11731255} 
0 commit comments