@@ -41,11 +41,35 @@ impl SelectionItem {
4141pub struct Selection ( pub Vec < SelectionItem > ) ;
4242
4343impl Selection {
44- pub ( crate ) fn extract_typename (
45- & self ,
46- context : & crate :: query:: QueryContext ,
44+ pub ( crate ) fn extract_typename < ' s , ' context : ' s > (
45+ & ' s self ,
46+ context : & ' context crate :: query:: QueryContext ,
4747 ) -> Option < & SelectionField > {
48- self . 0 . iter ( ) . filter_map ( |f| f. as_typename ( ) ) . next ( )
48+ // __typename is selected directly
49+ if let Some ( field) = self . 0 . iter ( ) . filter_map ( |f| f. as_typename ( ) ) . next ( ) {
50+ return Some ( field) ;
51+ } ;
52+
53+ // typename is selected through a fragment
54+ self . 0
55+ . iter ( )
56+ . filter_map ( |f| match f {
57+ SelectionItem :: FragmentSpread ( SelectionFragmentSpread { fragment_name } ) => {
58+ Some ( fragment_name)
59+ }
60+ _ => None ,
61+ } )
62+ . filter_map ( |fragment_name| {
63+ let fragment = context. fragments . get ( fragment_name) ;
64+
65+ fragment. and_then ( |fragment| fragment. selection . extract_typename ( context) )
66+ } )
67+ . next ( )
68+ }
69+
70+ #[ cfg( test) ]
71+ pub ( crate ) fn new_empty ( ) -> Selection {
72+ Selection ( Vec :: new ( ) )
4973 }
5074}
5175
@@ -93,12 +117,44 @@ mod tests {
93117
94118 #[ test]
95119 fn selection_extract_typename_simple_case ( ) {
96- let mut selection = Selection ( Vec :: new ( ) ) ;
97- let context = query:: QueryContext :: new_empty ( ) ;
120+ let selection = Selection :: new_empty ( ) ;
121+ let context = crate :: query:: QueryContext :: new_empty ( ) ;
98122
99123 assert ! ( selection. extract_typename( & context) . is_none( ) ) ;
100124 }
101125
126+ #[ test]
127+ fn selection_extract_typename_in_fragemnt ( ) {
128+ let mut selection = Selection :: new_empty ( ) ;
129+ selection
130+ . 0
131+ . push ( SelectionItem :: FragmentSpread ( SelectionFragmentSpread {
132+ fragment_name : "MyFragment" . to_owned ( ) ,
133+ } ) ) ;
134+
135+ let mut fragment_selection = Selection :: new_empty ( ) ;
136+ fragment_selection
137+ . 0
138+ . push ( SelectionItem :: Field ( SelectionField {
139+ alias : None ,
140+ name : "__typename" . to_string ( ) ,
141+ fields : Selection :: new_empty ( ) ,
142+ } ) ) ;
143+
144+ let mut context = crate :: query:: QueryContext :: new_empty ( ) ;
145+ context. fragments . insert (
146+ "MyFragment" . to_string ( ) ,
147+ crate :: fragments:: GqlFragment {
148+ name : "MyFragment" . to_string ( ) ,
149+ on : "something" . into ( ) ,
150+ selection : fragment_selection,
151+ is_required : std:: cell:: Cell :: new ( false ) ,
152+ } ,
153+ ) ;
154+
155+ assert ! ( selection. extract_typename( & context) . is_some( ) ) ;
156+ }
157+
102158 #[ test]
103159 fn selection_from_graphql_parser_selection_set ( ) {
104160 let query = r##"
0 commit comments