1- use std:: collections:: HashMap ;
1+ use std:: collections:: { HashMap , HashSet } ;
22use std:: ops:: Deref ;
33use std:: sync:: Arc ;
44
@@ -135,10 +135,22 @@ impl<'a> Builder<'a> {
135135 fragments : & HashMap < & str , & FragmentDefinition > ,
136136 ) -> Vec < Field < Value > > {
137137 let mut fields = vec ! [ ] ;
138+ let mut fragments_fields = vec ! [ ] ;
139+ let mut visited = HashSet :: new ( ) ;
138140
139141 for selection in & selection. items {
140142 match & selection. node {
141143 Selection :: Field ( Positioned { node : gql_field, .. } ) => {
144+ let field_name = gql_field. name . node . as_str ( ) ;
145+ let output_name = gql_field
146+ . alias
147+ . as_ref ( )
148+ . map ( |a| a. node . as_str ( ) )
149+ . unwrap_or ( field_name) ;
150+ if visited. contains ( output_name) {
151+ continue ;
152+ }
153+ visited. insert ( output_name) ;
142154 let conditions = self . include ( & gql_field. directives ) ;
143155
144156 // Skip fields based on GraphQL's skip/include conditions
@@ -163,7 +175,6 @@ impl<'a> Builder<'a> {
163175 }
164176
165177 let ( include, skip) = conditions. into_variable_tuple ( ) ;
166- let field_name = gql_field. name . node . as_str ( ) ;
167178 let request_args = gql_field
168179 . arguments
169180 . iter ( )
@@ -229,11 +240,7 @@ impl<'a> Builder<'a> {
229240 selection : child_fields,
230241 parent_fragment,
231242 name : field_name. to_string ( ) ,
232- output_name : gql_field
233- . alias
234- . as_ref ( )
235- . map ( |a| a. node . to_string ( ) )
236- . unwrap_or ( field_name. to_owned ( ) ) ,
243+ output_name : output_name. to_string ( ) ,
237244 ir,
238245 is_enum : self . index . type_is_enum ( type_of. name ( ) ) ,
239246 type_of,
@@ -251,10 +258,10 @@ impl<'a> Builder<'a> {
251258 let typename_field = Field {
252259 id : FieldId :: new ( self . field_id . next ( ) ) ,
253260 name : field_name. to_string ( ) ,
254- output_name : field_name . to_string ( ) ,
261+ output_name : output_name . to_string ( ) ,
255262 ir : None ,
256263 type_of : Type :: Named { name : "String" . to_owned ( ) , non_null : true } ,
257- type_condition : None ,
264+ type_condition : Some ( type_condition . to_string ( ) ) ,
258265 skip,
259266 include,
260267 args : Vec :: new ( ) ,
@@ -273,7 +280,7 @@ impl<'a> Builder<'a> {
273280 if let Some ( fragment) =
274281 fragments. get ( fragment_spread. fragment_name . node . as_str ( ) )
275282 {
276- fields . extend ( self . iter (
283+ fragments_fields . extend ( self . iter (
277284 Some ( fragment. type_condition . node . on . node . as_str ( ) ) ,
278285 & fragment. selection_set . node ,
279286 fragment. type_condition . node . on . node . as_str ( ) ,
@@ -287,7 +294,7 @@ impl<'a> Builder<'a> {
287294 . as_ref ( )
288295 . map ( |cond| cond. node . on . node . as_str ( ) )
289296 . unwrap_or ( type_condition) ;
290- fields . extend ( self . iter (
297+ fragments_fields . extend ( self . iter (
291298 Some ( type_of) ,
292299 & fragment. selection_set . node ,
293300 type_of,
@@ -296,7 +303,13 @@ impl<'a> Builder<'a> {
296303 }
297304 }
298305 }
299-
306+ for field in fragments_fields {
307+ if visited. contains ( field. output_name . as_str ( ) ) {
308+ continue ;
309+ }
310+ fields. push ( field) ;
311+ }
312+ fields. sort_by ( |a, b| a. id . cmp ( & b. id ) ) ;
300313 fields
301314 }
302315 #[ inline( always) ]
0 commit comments