11use std:: borrow:: Cow ;
2+ use std:: collections:: { HashMap , HashSet } ;
23use std:: convert:: Infallible ;
34use std:: fmt:: { Debug , Display } ;
45use std:: marker:: PhantomData ;
@@ -20,18 +21,25 @@ impl<A> GraphQL<A> {
2021 }
2122}
2223
23- fn compute_selection_set < A : Display + Debug + JsonLikeOwned > ( base_field : & mut [ Field < A > ] ) {
24+ fn compute_selection_set < A : Display + Debug + JsonLikeOwned > (
25+ base_field : & mut [ Field < A > ] ,
26+ interfaces : & HashSet < String > ,
27+ ) {
2428 for field in base_field. iter_mut ( ) {
2529 if let Some ( ir) = field. ir . as_mut ( ) {
2630 ir. modify_io ( & mut |io| {
2731 if let IO :: GraphQL { req_template, .. } = io {
28- if let Some ( v) = format_selection_set ( field. selection . iter ( ) ) {
32+ if let Some ( v) = format_selection_set (
33+ field. selection . iter ( ) ,
34+ interfaces,
35+ interfaces. contains ( field. type_of . name ( ) ) ,
36+ ) {
2937 req_template. selection = Some ( Mustache :: parse ( & v) . into ( ) ) ;
3038 }
3139 }
3240 } ) ;
3341 }
34- compute_selection_set ( field. selection . as_mut ( ) ) ;
42+ compute_selection_set ( field. selection . as_mut ( ) , interfaces ) ;
3543 }
3644}
3745
@@ -40,15 +48,24 @@ impl<A: Display + Debug + JsonLikeOwned + Clone> Transform for GraphQL<A> {
4048 type Error = Infallible ;
4149
4250 fn transform ( & self , mut plan : Self :: Value ) -> Valid < Self :: Value , Self :: Error > {
43- compute_selection_set ( & mut plan. selection ) ;
51+ let interfaces = match plan. interfaces {
52+ Some ( ref interfaces) => interfaces,
53+ None => & HashSet :: new ( ) ,
54+ } ;
55+ compute_selection_set ( & mut plan. selection , interfaces) ;
4456
4557 Valid :: succeed ( plan)
4658 }
4759}
4860
4961fn format_selection_set < ' a , A : ' a + Display + JsonLikeOwned > (
5062 selection_set : impl Iterator < Item = & ' a Field < A > > ,
63+ interfaces : & HashSet < String > ,
64+ is_parent_interface : bool ,
5165) -> Option < String > {
66+ let mut fragments_fields = HashMap :: new ( ) ;
67+ let mut normal_fields = vec ! [ ] ;
68+ let mut is_typename_requested = false ;
5269 let set = selection_set
5370 . filter ( |field| !matches ! ( & field. ir, Some ( IR :: IO ( _) ) | Some ( IR :: Dynamic ( _) ) ) )
5471 . map ( |field| {
@@ -58,20 +75,52 @@ fn format_selection_set<'a, A: 'a + Display + JsonLikeOwned>(
5875 } else {
5976 field. name . to_string ( )
6077 } ;
61- format_selection_field ( field, & field_name)
78+ let is_this_field_interface = interfaces. contains ( field. type_of . name ( ) ) ;
79+ let formatted_selection_fields =
80+ format_selection_field ( field, & field_name, interfaces, is_this_field_interface) ;
81+ is_typename_requested = is_typename_requested || field_name == "__typename" ;
82+ match & field. parent_fragment {
83+ Some ( fragment) if is_parent_interface => {
84+ fragments_fields
85+ . entry ( fragment. to_owned ( ) )
86+ . or_insert_with ( Vec :: new)
87+ . push ( formatted_selection_fields) ;
88+ }
89+ _ => {
90+ normal_fields. push ( formatted_selection_fields) ;
91+ }
92+ }
6293 } )
6394 . collect :: < Vec < _ > > ( ) ;
6495
6596 if set. is_empty ( ) {
6697 return None ;
6798 }
6899
69- Some ( format ! ( "{{ {} }}" , set. join( " " ) ) )
100+ let fragments_set: Vec < String > = fragments_fields
101+ . into_iter ( )
102+ . map ( |( fragment_name, fields) | {
103+ format ! ( "... on {} {{ {} }}" , fragment_name, fields. join( " " ) )
104+ } )
105+ . collect ( ) ;
106+
107+ //Don't force user to query the type and get it automatically
108+ if is_parent_interface && !is_typename_requested {
109+ normal_fields. push ( "__typename" . to_owned ( ) ) ;
110+ }
111+ normal_fields. extend ( fragments_set) ;
112+ Some ( format ! ( "{{ {} }}" , normal_fields. join( " " ) ) )
70113}
71114
72- fn format_selection_field < A : Display + JsonLikeOwned > ( field : & Field < A > , name : & str ) -> String {
115+ fn format_selection_field < A : Display + JsonLikeOwned > (
116+ field : & Field < A > ,
117+ name : & str ,
118+ interfaces : & HashSet < String > ,
119+ is_parent_interface : bool ,
120+ ) -> String {
73121 let arguments = format_selection_field_arguments ( field) ;
74- let selection_set = format_selection_set ( field. selection . iter ( ) ) ;
122+ let selection_set =
123+ format_selection_set ( field. selection . iter ( ) , interfaces, is_parent_interface) ;
75124
76125 let mut output = format ! ( "{}{}" , name, arguments) ;
77126
0 commit comments