apollo_smith/
operation.rs1use crate::directive::Directive;
2use crate::directive::DirectiveLocation;
3use crate::name::Name;
4use crate::selection_set::SelectionSet;
5use crate::variable::VariableDef;
6use crate::DocumentBuilder;
7use apollo_compiler::ast;
8use apollo_compiler::Node;
9use arbitrary::Arbitrary;
10use arbitrary::Result as ArbitraryResult;
11use indexmap::IndexMap;
12
13#[derive(Debug, Clone)]
20pub struct OperationDef {
21 pub(crate) operation_type: OperationType,
22 pub(crate) name: Option<Name>,
23 pub(crate) variable_definitions: Vec<VariableDef>,
24 pub(crate) directives: IndexMap<Name, Directive>,
25 pub(crate) selection_set: SelectionSet,
26}
27
28impl From<OperationDef> for ast::Definition {
29 fn from(x: OperationDef) -> Self {
30 ast::OperationDefinition {
31 operation_type: x.operation_type.into(),
32 name: x.name.map(Into::into),
33 directives: Directive::to_ast(x.directives),
34 variables: x
35 .variable_definitions
36 .into_iter()
37 .map(|x| Node::new(x.into()))
38 .collect(),
39 selection_set: x.selection_set.into(),
40 }
41 .into()
42 }
43}
44
45impl From<OperationDef> for String {
46 fn from(op_def: OperationDef) -> Self {
47 ast::Definition::from(op_def).to_string()
48 }
49}
50
51impl TryFrom<apollo_parser::cst::OperationDefinition> for OperationDef {
52 type Error = crate::FromError;
53
54 fn try_from(
55 operation_def: apollo_parser::cst::OperationDefinition,
56 ) -> Result<Self, Self::Error> {
57 Ok(Self {
58 name: operation_def.name().map(Name::from),
59 directives: operation_def
60 .directives()
61 .map(Directive::convert_directives)
62 .transpose()?
63 .unwrap_or_default(),
64 operation_type: operation_def
65 .operation_type()
66 .map(OperationType::from)
67 .unwrap_or(OperationType::Query),
68 variable_definitions: Vec::new(),
69 selection_set: operation_def.selection_set().unwrap().try_into()?,
70 })
71 }
72}
73
74#[derive(Debug, Arbitrary, Clone, Copy, PartialEq, Eq)]
81pub enum OperationType {
82 Query,
83 Mutation,
84 Subscription,
85}
86
87impl From<OperationType> for ast::OperationType {
88 fn from(op_type: OperationType) -> Self {
89 match op_type {
90 OperationType::Query => Self::Query,
91 OperationType::Mutation => Self::Mutation,
92 OperationType::Subscription => Self::Subscription,
93 }
94 }
95}
96
97impl From<apollo_parser::cst::OperationType> for OperationType {
98 fn from(op_type: apollo_parser::cst::OperationType) -> Self {
99 if op_type.query_token().is_some() {
100 Self::Query
101 } else if op_type.mutation_token().is_some() {
102 Self::Mutation
103 } else if op_type.subscription_token().is_some() {
104 Self::Subscription
105 } else {
106 Self::Query
107 }
108 }
109}
110
111impl DocumentBuilder<'_> {
112 pub fn operation_definition(&mut self) -> ArbitraryResult<Option<OperationDef>> {
114 let schema = match self.schema_def.clone() {
115 Some(schema_def) => schema_def,
116 None => return Ok(None),
117 };
118 let name = self
119 .u
120 .arbitrary()
121 .unwrap_or(false)
122 .then(|| self.type_name())
123 .transpose()?;
124 let available_operations = {
125 let mut ops = vec![];
126 if let Some(query) = &schema.query {
127 ops.push((OperationType::Query, query));
128 }
129 if let Some(mutation) = &schema.mutation {
130 ops.push((OperationType::Mutation, mutation));
131 }
132 if let Some(subscription) = &schema.subscription {
133 ops.push((OperationType::Subscription, subscription));
134 }
135
136 ops
137 };
138
139 let (operation_type, chosen_ty) = self.u.choose(&available_operations)?;
140 let directive_location = match operation_type {
141 OperationType::Query => DirectiveLocation::Query,
142 OperationType::Mutation => DirectiveLocation::Mutation,
143 OperationType::Subscription => DirectiveLocation::Subscription,
144 };
145 let directives = self.directives(directive_location)?;
146
147 self.stack_ty(chosen_ty);
149
150 let selection_set = self.selection_set()?;
151
152 self.stack.pop();
153 self.chosen_arguments.clear();
155 self.chosen_aliases.clear();
157
158 assert!(
159 self.stack.is_empty(),
160 "the stack must be empty at the end of an operation definition"
161 );
162
163 let variable_definitions = vec![];
165
166 Ok(Some(OperationDef {
167 operation_type: *operation_type,
168 name,
169 variable_definitions,
170 directives,
171 selection_set,
172 }))
173 }
174}