1+ use darling:: usage:: { GenericsExt , Purpose , UsesTypeParams } ;
2+ use syn:: { parse_quote, Token , WhereClause } ;
3+
14use {
25 proc_macro2:: { Span , TokenStream } ,
36 quote:: { quote, quote_spanned} ,
@@ -28,6 +31,7 @@ pub struct FragmentImpl<'schema, 'a> {
2831 variables_fields : syn:: Type ,
2932 graphql_type_name : String ,
3033 schema_type_path : syn:: Path ,
34+ additional_where : Option < syn:: WhereClause > ,
3135}
3236
3337#[ allow( clippy:: large_enum_variant) ]
@@ -83,6 +87,14 @@ impl<'schema, 'a: 'schema> FragmentImpl<'schema, 'a> {
8387 let variables_fields = variables_fields_path ( variables) ;
8488 let variables_fields = variables_fields. as_ref ( ) ;
8589
90+ let additional_where = additional_where_clause (
91+ generics,
92+ fields,
93+ schema,
94+ & field_module_path,
95+ variables_fields,
96+ ) ;
97+
8698 let selections = fields
8799 . iter ( )
88100 . map ( |( field, schema_field) | {
@@ -111,6 +123,7 @@ impl<'schema, 'a: 'schema> FragmentImpl<'schema, 'a> {
111123 variables_fields,
112124 graphql_type_name : graphql_type_name. to_string ( ) ,
113125 schema_type_path,
126+ additional_where,
114127 } )
115128 }
116129}
@@ -167,6 +180,64 @@ fn process_field<'a>(
167180 } ) )
168181}
169182
183+ fn additional_where_clause (
184+ generics : & syn:: Generics ,
185+ fields : & [ ( FragmentDeriveField , Option < Field < ' _ > > ) ] ,
186+ schema : & Schema < ' _ , Unvalidated > ,
187+ field_module_path : & syn:: Path ,
188+ variables_fields : Option < & syn:: Path > ,
189+ ) -> Option < WhereClause > {
190+ let all_params = generics. declared_type_params ( ) ;
191+ if all_params. is_empty ( ) {
192+ return None ;
193+ }
194+ let options = Purpose :: BoundImpl . into ( ) ;
195+
196+ let mut predicates: Vec < syn:: WherePredicate > = vec ! [ ] ;
197+
198+ for ( field, schema_field) in fields {
199+ let Some ( schema_field) = schema_field else {
200+ continue ;
201+ } ;
202+ let inner_type = schema_field. field_type . inner_type ( schema) ;
203+ if !inner_type. is_composite ( ) {
204+ // We only care about generics on composite types.
205+ continue ;
206+ }
207+ if field. ty . uses_type_params ( & options, & all_params) . is_empty ( ) {
208+ // If this field uses no type params we skip it
209+ continue ;
210+ }
211+
212+ let ty = & field. ty ;
213+ let marker_ty = schema_field. marker_ident ( ) . to_path ( field_module_path) ;
214+ predicates. push ( parse_quote ! {
215+ #ty: cynic:: QueryFragment <SchemaType = <#marker_ty as cynic:: schema:: Field >:: Type >
216+ } ) ;
217+ match variables_fields {
218+ Some ( variables_fields) => {
219+ predicates. push ( parse_quote ! {
220+ #variables_fields: cynic:: queries:: VariableMatch <<#ty as cynic:: QueryFragment >:: VariablesFields >
221+ } ) ;
222+ }
223+ None => {
224+ predicates. push ( parse_quote ! {
225+ ( ) : cynic:: queries:: VariableMatch <<#ty as cynic:: QueryFragment >:: VariablesFields >
226+ } ) ;
227+ }
228+ }
229+ }
230+
231+ if predicates. is_empty ( ) {
232+ return None ;
233+ }
234+
235+ Some ( WhereClause {
236+ where_token : <Token ! [ where ] >:: default ( ) ,
237+ predicates : predicates. into_iter ( ) . collect ( ) ,
238+ } )
239+ }
240+
170241impl quote:: ToTokens for FragmentImpl < ' _ , ' _ > {
171242 fn to_tokens ( & self , tokens : & mut TokenStream ) {
172243 use quote:: TokenStreamExt ;
@@ -179,6 +250,17 @@ impl quote::ToTokens for FragmentImpl<'_, '_> {
179250 let fragment_name = proc_macro2:: Literal :: string ( & target_struct. to_string ( ) ) ;
180251 let ( impl_generics, ty_generics, where_clause) = self . generics . split_for_impl ( ) ;
181252
253+ let where_clause = match ( where_clause, & self . additional_where ) {
254+ ( None , None ) => None ,
255+ ( Some ( lhs) , None ) => Some ( quote ! { #lhs } ) ,
256+ ( None , Some ( rhs) ) => Some ( quote ! { #rhs } ) ,
257+ ( Some ( lhs) , Some ( rhs) ) => {
258+ let mut new = lhs. clone ( ) ;
259+ new. predicates . extend ( rhs. predicates . clone ( ) ) ;
260+ Some ( quote ! { #new } )
261+ }
262+ } ;
263+
182264 tokens. append_all ( quote ! {
183265 #[ automatically_derived]
184266 impl #impl_generics cynic:: QueryFragment for #target_struct #ty_generics #where_clause {
@@ -383,6 +465,13 @@ impl quote::ToTokens for SpreadSelection {
383465}
384466
385467impl OutputType < ' _ > {
468+ fn is_composite ( & self ) -> bool {
469+ matches ! (
470+ self ,
471+ OutputType :: Object ( _) | OutputType :: Interface ( _) | OutputType :: Union ( _)
472+ )
473+ }
474+
386475 fn as_kind ( & self ) -> FieldKind {
387476 match self {
388477 OutputType :: Scalar ( _) => FieldKind :: Scalar ,
0 commit comments