@@ -41,11 +41,35 @@ impl SelectionItem {
41
41
pub struct Selection ( pub Vec < SelectionItem > ) ;
42
42
43
43
impl 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 ,
47
47
) -> 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 ( ) )
49
73
}
50
74
}
51
75
@@ -93,12 +117,44 @@ mod tests {
93
117
94
118
#[ test]
95
119
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 ( ) ;
98
122
99
123
assert ! ( selection. extract_typename( & context) . is_none( ) ) ;
100
124
}
101
125
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
+
102
158
#[ test]
103
159
fn selection_from_graphql_parser_selection_set ( ) {
104
160
let query = r##"
0 commit comments