@@ -551,39 +551,7 @@ impl Operation {
551
551
& ' doc self ,
552
552
document : & ' doc ExecutableDocument ,
553
553
) -> impl Iterator < Item = & ' doc Node < Field > > {
554
- let mut stack = vec ! [ self . selection_set. selections. iter( ) ] ;
555
- let mut fragments_seen = HashSet :: default ( ) ;
556
- std:: iter:: from_fn ( move || {
557
- while let Some ( selection_set_iter) = stack. last_mut ( ) {
558
- match selection_set_iter. next ( ) {
559
- Some ( Selection :: Field ( field) ) => {
560
- // Yield one item from the `root_fields()` iterator
561
- // but ignore its sub-selections in `field.selection_set`
562
- return Some ( field) ;
563
- }
564
- Some ( Selection :: InlineFragment ( inline) ) => {
565
- stack. push ( inline. selection_set . selections . iter ( ) )
566
- }
567
- Some ( Selection :: FragmentSpread ( spread) ) => {
568
- if let Some ( def) = document. fragments . get ( & spread. fragment_name ) {
569
- let new = fragments_seen. insert ( & spread. fragment_name ) ;
570
- if new {
571
- stack. push ( def. selection_set . selections . iter ( ) )
572
- }
573
- } else {
574
- // Undefined fragments are silently ignored.
575
- // They should never happen in a valid document.
576
- }
577
- }
578
- None => {
579
- // Remove an empty iterator from the stack
580
- // and continue with the parent selection set
581
- stack. pop ( ) ;
582
- }
583
- }
584
- }
585
- None
586
- } )
554
+ self . selection_set . root_fields ( document)
587
555
}
588
556
589
557
/// Returns an iterator of all field selections in this operation.
@@ -602,42 +570,7 @@ impl Operation {
602
570
& ' doc self ,
603
571
document : & ' doc ExecutableDocument ,
604
572
) -> impl Iterator < Item = & ' doc Node < Field > > {
605
- let mut stack = vec ! [ self . selection_set. selections. iter( ) ] ;
606
- let mut fragments_seen = HashSet :: default ( ) ;
607
- std:: iter:: from_fn ( move || {
608
- while let Some ( selection_set_iter) = stack. last_mut ( ) {
609
- match selection_set_iter. next ( ) {
610
- Some ( Selection :: Field ( field) ) => {
611
- if !field. selection_set . is_empty ( ) {
612
- // Will be considered for the next call
613
- stack. push ( field. selection_set . selections . iter ( ) )
614
- }
615
- // Yield one item from the `all_fields()` iterator
616
- return Some ( field) ;
617
- }
618
- Some ( Selection :: InlineFragment ( inline) ) => {
619
- stack. push ( inline. selection_set . selections . iter ( ) )
620
- }
621
- Some ( Selection :: FragmentSpread ( spread) ) => {
622
- if let Some ( def) = document. fragments . get ( & spread. fragment_name ) {
623
- let new = fragments_seen. insert ( & spread. fragment_name ) ;
624
- if new {
625
- stack. push ( def. selection_set . selections . iter ( ) )
626
- }
627
- } else {
628
- // Undefined fragments are silently ignored.
629
- // They should never happen in a valid document.
630
- }
631
- }
632
- None => {
633
- // Remove an empty iterator from the stack
634
- // and continue with the parent selection set
635
- stack. pop ( ) ;
636
- }
637
- }
638
- }
639
- None
640
- } )
573
+ self . selection_set . all_fields ( document)
641
574
}
642
575
643
576
serialize_method ! ( ) ;
@@ -707,6 +640,113 @@ impl SelectionSet {
707
640
self . selections . iter ( ) . filter_map ( |sel| sel. as_field ( ) )
708
641
}
709
642
643
+ /// Returns an iterator of field selections that are at the root of the response.
644
+ /// That is, inline fragments and fragment spreads at the root are traversed,
645
+ /// but field sub-selections are not.
646
+ ///
647
+ /// See also [`all_fields`][Self::all_fields].
648
+ ///
649
+ /// `document` is used to look up fragment definitions.
650
+ ///
651
+ /// This does **not** perform [field merging],
652
+ /// so multiple items in this iterator may have the same response key
653
+ /// or point to the same field definition.
654
+ /// Named fragments however are only traversed once even if spread multiple times.
655
+ ///
656
+ /// [field merging]: https://spec.graphql.org/draft/#sec-Field-Selection-Merging
657
+ pub fn root_fields < ' doc > (
658
+ & ' doc self ,
659
+ document : & ' doc ExecutableDocument ,
660
+ ) -> impl Iterator < Item = & ' doc Node < Field > > {
661
+ let mut stack = vec ! [ self . selections. iter( ) ] ;
662
+ let mut fragments_seen = HashSet :: default ( ) ;
663
+ std:: iter:: from_fn ( move || {
664
+ while let Some ( selection_set_iter) = stack. last_mut ( ) {
665
+ match selection_set_iter. next ( ) {
666
+ Some ( Selection :: Field ( field) ) => {
667
+ // Yield one item from the `root_fields()` iterator
668
+ // but ignore its sub-selections in `field.selection_set`
669
+ return Some ( field) ;
670
+ }
671
+ Some ( Selection :: InlineFragment ( inline) ) => {
672
+ stack. push ( inline. selection_set . selections . iter ( ) )
673
+ }
674
+ Some ( Selection :: FragmentSpread ( spread) ) => {
675
+ if let Some ( def) = document. fragments . get ( & spread. fragment_name ) {
676
+ let new = fragments_seen. insert ( & spread. fragment_name ) ;
677
+ if new {
678
+ stack. push ( def. selection_set . selections . iter ( ) )
679
+ }
680
+ } else {
681
+ // Undefined fragments are silently ignored.
682
+ // They should never happen in a valid document.
683
+ }
684
+ }
685
+ None => {
686
+ // Remove an empty iterator from the stack
687
+ // and continue with the parent selection set
688
+ stack. pop ( ) ;
689
+ }
690
+ }
691
+ }
692
+ None
693
+ } )
694
+ }
695
+
696
+ /// Returns an iterator of all field selections in this operation.
697
+ ///
698
+ /// See also [`root_fields`][Self::root_fields].
699
+ ///
700
+ /// `document` is used to look up fragment definitions.
701
+ ///
702
+ /// This does **not** perform [field merging],
703
+ /// so multiple items in this iterator may have the same response key
704
+ /// or point to the same field definition.
705
+ /// Named fragments however are only traversed once even if spread multiple times.
706
+ ///
707
+ /// [field merging]: https://spec.graphql.org/draft/#sec-Field-Selection-Merging
708
+ pub fn all_fields < ' doc > (
709
+ & ' doc self ,
710
+ document : & ' doc ExecutableDocument ,
711
+ ) -> impl Iterator < Item = & ' doc Node < Field > > {
712
+ let mut stack = vec ! [ self . selections. iter( ) ] ;
713
+ let mut fragments_seen = HashSet :: default ( ) ;
714
+ std:: iter:: from_fn ( move || {
715
+ while let Some ( selection_set_iter) = stack. last_mut ( ) {
716
+ match selection_set_iter. next ( ) {
717
+ Some ( Selection :: Field ( field) ) => {
718
+ if !field. selection_set . is_empty ( ) {
719
+ // Will be considered for the next call
720
+ stack. push ( field. selection_set . selections . iter ( ) )
721
+ }
722
+ // Yield one item from the `all_fields()` iterator
723
+ return Some ( field) ;
724
+ }
725
+ Some ( Selection :: InlineFragment ( inline) ) => {
726
+ stack. push ( inline. selection_set . selections . iter ( ) )
727
+ }
728
+ Some ( Selection :: FragmentSpread ( spread) ) => {
729
+ if let Some ( def) = document. fragments . get ( & spread. fragment_name ) {
730
+ let new = fragments_seen. insert ( & spread. fragment_name ) ;
731
+ if new {
732
+ stack. push ( def. selection_set . selections . iter ( ) )
733
+ }
734
+ } else {
735
+ // Undefined fragments are silently ignored.
736
+ // They should never happen in a valid document.
737
+ }
738
+ }
739
+ None => {
740
+ // Remove an empty iterator from the stack
741
+ // and continue with the parent selection set
742
+ stack. pop ( ) ;
743
+ }
744
+ }
745
+ }
746
+ None
747
+ } )
748
+ }
749
+
710
750
serialize_method ! ( ) ;
711
751
}
712
752
0 commit comments