apollo_smith/
selection_set.rs1use crate::field::Field;
2use crate::fragment::FragmentSpread;
3use crate::fragment::InlineFragment;
4use crate::name::Name;
5use crate::DocumentBuilder;
6use apollo_compiler::ast;
7use apollo_compiler::Node;
8use arbitrary::Result as ArbitraryResult;
9use indexmap::IndexSet;
10
11#[derive(Debug, Clone)]
18pub struct SelectionSet {
19 pub(crate) selections: Vec<Selection>,
20}
21
22impl From<SelectionSet> for Vec<ast::Selection> {
23 fn from(sel_set: SelectionSet) -> Self {
24 sel_set.selections.into_iter().map(Into::into).collect()
25 }
26}
27
28impl SelectionSet {
29 pub(crate) fn collect_fragment_spreads(&self, into: &mut IndexSet<Name>) {
30 for selection in &self.selections {
31 match selection {
32 Selection::Field(field) => {
33 if let Some(inner) = &field.selection_set {
34 inner.collect_fragment_spreads(into);
35 }
36 }
37 Selection::FragmentSpread(spread) => {
38 into.insert(spread.name.clone());
39 }
40 Selection::InlineFragment(inline) => {
41 inline.selection_set.collect_fragment_spreads(into);
42 }
43 }
44 }
45 }
46}
47
48impl TryFrom<apollo_parser::cst::SelectionSet> for SelectionSet {
49 type Error = crate::FromError;
50
51 fn try_from(selection_set: apollo_parser::cst::SelectionSet) -> Result<Self, Self::Error> {
52 Ok(Self {
53 selections: selection_set
54 .selections()
55 .map(Selection::try_from)
56 .collect::<Result<_, _>>()?,
57 })
58 }
59}
60
61#[derive(Debug, Clone)]
67pub enum Selection {
68 Field(Field),
70 FragmentSpread(FragmentSpread),
72 InlineFragment(InlineFragment),
74}
75
76impl From<Selection> for ast::Selection {
77 fn from(selection: Selection) -> Self {
78 match selection {
79 Selection::Field(field) => Self::Field(Node::new(field.into())),
80 Selection::FragmentSpread(fragment_spread) => {
81 Self::FragmentSpread(Node::new(fragment_spread.into()))
82 }
83 Selection::InlineFragment(inline_fragment) => {
84 Self::InlineFragment(Node::new(inline_fragment.into()))
85 }
86 }
87 }
88}
89
90impl TryFrom<apollo_parser::cst::Selection> for Selection {
91 type Error = crate::FromError;
92
93 fn try_from(selection: apollo_parser::cst::Selection) -> Result<Self, Self::Error> {
94 match selection {
95 apollo_parser::cst::Selection::Field(field) => field.try_into().map(Self::Field),
96 apollo_parser::cst::Selection::FragmentSpread(fragment_spread) => {
97 fragment_spread.try_into().map(Self::FragmentSpread)
98 }
99 apollo_parser::cst::Selection::InlineFragment(inline_fragment) => {
100 inline_fragment.try_into().map(Self::InlineFragment)
101 }
102 }
103 }
104}
105
106impl DocumentBuilder<'_> {
107 pub fn selection_set(&mut self) -> ArbitraryResult<SelectionSet> {
109 let mut exclude_names = Vec::new();
110 let selection_nb = self.stack.last().map(|o| o.fields_def().len()).unwrap_or(0);
111
112 let selections = (0..self.u.int_in_range(1..=5)?)
113 .map(|_| {
114 let index = self.u.int_in_range(0..=selection_nb)?;
115 self.selection(index, &mut exclude_names)
116 }) .collect::<ArbitraryResult<Vec<_>>>()?;
118 Ok(SelectionSet { selections })
119 }
120
121 pub fn selection(
123 &mut self,
124 index: usize,
125 excludes: &mut Vec<Name>,
126 ) -> ArbitraryResult<Selection> {
127 let selection = match self.u.int_in_range(0..=2usize)? {
128 0 => Selection::Field(self.field(index)?),
129 1 => match self.fragment_spread(excludes)? {
130 Some(frag_spread) => Selection::FragmentSpread(frag_spread),
131 None => Selection::Field(self.field(index)?),
132 },
133 2 => Selection::InlineFragment(self.inline_fragment()?),
134 _ => unreachable!(),
135 };
136
137 Ok(selection)
138 }
139}