async_graphql_parser/types/
executable.rs

1//! Executable document-related GraphQL types.
2
3use serde::{Deserialize, Serialize};
4
5use super::*;
6
7/// An executable GraphQL file or request string.
8///
9/// [Reference](https://spec.graphql.org/October2021/#ExecutableDocument).
10#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct ExecutableDocument {
12    /// The operations of the document.
13    pub operations: DocumentOperations,
14    /// The fragments of the document.
15    pub fragments: HashMap<Name, Positioned<FragmentDefinition>>,
16}
17
18/// The operations of a GraphQL document.
19///
20/// There is either one anonymous operation or many named operations.
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub enum DocumentOperations {
23    /// The document contains a single anonymous operation.
24    Single(Positioned<OperationDefinition>),
25    /// The document contains many named operations.
26    Multiple(HashMap<Name, Positioned<OperationDefinition>>),
27}
28
29impl DocumentOperations {
30    /// Iterate over the operations of the document.
31    #[must_use]
32    pub fn iter(&self) -> OperationsIter<'_> {
33        OperationsIter(match self {
34            Self::Single(op) => OperationsIterInner::Single(Some(op)),
35            Self::Multiple(ops) => OperationsIterInner::Multiple(ops.iter()),
36        })
37    }
38}
39
40// TODO: This is not implemented as I would like to later implement IntoIterator
41// for DocumentOperations (not a reference) without having a breaking change.
42//
43// impl<'a> IntoIterator for &'a DocumentOperations {
44//    type Item = &'a Positioned<OperationDefinition>;
45//    type IntoIter = OperationsIter<'a>;
46//
47//    fn into_iter(self) -> Self::IntoIter {
48//        self.iter()
49//    }
50//}
51
52/// An iterator over the operations of a document.
53#[derive(Debug, Clone)]
54pub struct OperationsIter<'a>(OperationsIterInner<'a>);
55
56impl<'a> Iterator for OperationsIter<'a> {
57    type Item = (Option<&'a Name>, &'a Positioned<OperationDefinition>);
58
59    fn next(&mut self) -> Option<Self::Item> {
60        match &mut self.0 {
61            OperationsIterInner::Single(op) => op.take().map(|op| (None, op)),
62            OperationsIterInner::Multiple(iter) => iter.next().map(|(name, op)| (Some(name), op)),
63        }
64    }
65
66    fn size_hint(&self) -> (usize, Option<usize>) {
67        let size = self.len();
68        (size, Some(size))
69    }
70}
71
72impl std::iter::FusedIterator for OperationsIter<'_> {}
73
74impl ExactSizeIterator for OperationsIter<'_> {
75    fn len(&self) -> usize {
76        match &self.0 {
77            OperationsIterInner::Single(opt) => usize::from(opt.is_some()),
78            OperationsIterInner::Multiple(iter) => iter.len(),
79        }
80    }
81}
82
83#[derive(Debug, Clone)]
84enum OperationsIterInner<'a> {
85    Single(Option<&'a Positioned<OperationDefinition>>),
86    Multiple(hash_map::Iter<'a, Name, Positioned<OperationDefinition>>),
87}
88
89/// A GraphQL operation, such as `mutation($content:String!) { makePost(content:
90/// $content) { id } }`.
91///
92/// [Reference](https://spec.graphql.org/October2021/#OperationDefinition).
93#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct OperationDefinition {
95    /// The type of operation.
96    pub ty: OperationType,
97    /// The variable definitions.
98    pub variable_definitions: Vec<Positioned<VariableDefinition>>,
99    /// The operation's directives.
100    pub directives: Vec<Positioned<Directive>>,
101    /// The operation's selection set.
102    pub selection_set: Positioned<SelectionSet>,
103}
104
105/// A variable definition inside a list of variable definitions, for example
106/// `$name:String!`.
107///
108/// [Reference](https://spec.graphql.org/October2021/#VariableDefinition).
109#[derive(Debug, Clone, Serialize, Deserialize)]
110pub struct VariableDefinition {
111    /// The name of the variable, without the preceding `$`.
112    pub name: Positioned<Name>,
113    /// The type of the variable.
114    pub var_type: Positioned<Type>,
115    /// The variable's directives.
116    pub directives: Vec<Positioned<Directive>>,
117    /// The optional default value of the variable.
118    pub default_value: Option<Positioned<ConstValue>>,
119}
120
121impl VariableDefinition {
122    /// Get the default value of the variable; this is `default_value` if it is
123    /// present, `Value::Null` if it is nullable and `None` otherwise.
124    #[must_use]
125    pub fn default_value(&self) -> Option<&ConstValue> {
126        self.default_value.as_ref().map(|value| &value.node).or({
127            if self.var_type.node.nullable {
128                Some(&ConstValue::Null)
129            } else {
130                None
131            }
132        })
133    }
134}
135
136/// A set of fields to be selected, for example `{ name age }`.
137///
138/// [Reference](https://spec.graphql.org/October2021/#SelectionSet).
139#[derive(Debug, Default, Clone, Serialize, Deserialize)]
140pub struct SelectionSet {
141    /// The fields to be selected.
142    pub items: Vec<Positioned<Selection>>,
143}
144
145/// A part of an object to be selected; a single field, a fragment spread or an
146/// inline fragment.
147///
148/// [Reference](https://spec.graphql.org/October2021/#Selection).
149#[derive(Debug, Clone, Serialize, Deserialize)]
150pub enum Selection {
151    /// Select a single field, such as `name` or `weightKilos: weight(unit:
152    /// KILOGRAMS)`.
153    Field(Positioned<Field>),
154    /// Select using a fragment.
155    FragmentSpread(Positioned<FragmentSpread>),
156    /// Select using an inline fragment.
157    InlineFragment(Positioned<InlineFragment>),
158}
159
160impl Selection {
161    /// Get a reference to the directives of the selection.
162    #[must_use]
163    pub fn directives(&self) -> &Vec<Positioned<Directive>> {
164        match self {
165            Self::Field(field) => &field.node.directives,
166            Self::FragmentSpread(spread) => &spread.node.directives,
167            Self::InlineFragment(fragment) => &fragment.node.directives,
168        }
169    }
170    /// Get a mutable reference to the directives of the selection.
171    #[must_use]
172    pub fn directives_mut(&mut self) -> &mut Vec<Positioned<Directive>> {
173        match self {
174            Self::Field(field) => &mut field.node.directives,
175            Self::FragmentSpread(spread) => &mut spread.node.directives,
176            Self::InlineFragment(fragment) => &mut fragment.node.directives,
177        }
178    }
179}
180
181/// A field being selected on an object, such as `name` or `weightKilos:
182/// weight(unit: KILOGRAMS)`.
183///
184/// [Reference](https://spec.graphql.org/October2021/#Field).
185#[derive(Debug, Clone, Serialize, Deserialize)]
186pub struct Field {
187    /// The optional field alias.
188    pub alias: Option<Positioned<Name>>,
189    /// The name of the field.
190    pub name: Positioned<Name>,
191    /// The arguments to the field, empty if no arguments are provided.
192    pub arguments: Vec<(Positioned<Name>, Positioned<Value>)>,
193    /// The directives in the field selector.
194    pub directives: Vec<Positioned<Directive>>,
195    /// The subfields being selected in this field, if it is an object. Empty if
196    /// no fields are being selected.
197    pub selection_set: Positioned<SelectionSet>,
198}
199
200impl Field {
201    /// Get the response key of the field. This is the alias if present and the
202    /// name otherwise.
203    #[must_use]
204    pub fn response_key(&self) -> &Positioned<Name> {
205        self.alias.as_ref().unwrap_or(&self.name)
206    }
207
208    /// Get the value of the argument with the specified name.
209    #[must_use]
210    pub fn get_argument(&self, name: &str) -> Option<&Positioned<Value>> {
211        self.arguments
212            .iter()
213            .find(|item| item.0.node == name)
214            .map(|item| &item.1)
215    }
216}
217
218/// A fragment selector, such as `... userFields`.
219///
220/// [Reference](https://spec.graphql.org/October2021/#FragmentSpread).
221#[derive(Debug, Clone, Serialize, Deserialize)]
222pub struct FragmentSpread {
223    /// The name of the fragment being selected.
224    pub fragment_name: Positioned<Name>,
225    /// The directives in the fragment selector.
226    pub directives: Vec<Positioned<Directive>>,
227}
228
229/// An inline fragment selector, such as `... on User { name }`.
230///
231/// [Reference](https://spec.graphql.org/October2021/#InlineFragment).
232#[derive(Debug, Clone, Serialize, Deserialize)]
233pub struct InlineFragment {
234    /// The type condition.
235    pub type_condition: Option<Positioned<TypeCondition>>,
236    /// The directives in the inline fragment.
237    pub directives: Vec<Positioned<Directive>>,
238    /// The selected fields of the fragment.
239    pub selection_set: Positioned<SelectionSet>,
240}
241
242/// The definition of a fragment, such as `fragment userFields on User { name
243/// age }`.
244///
245/// [Reference](https://spec.graphql.org/October2021/#FragmentDefinition).
246#[derive(Debug, Clone, Serialize, Deserialize)]
247pub struct FragmentDefinition {
248    /// The type this fragment operates on.
249    pub type_condition: Positioned<TypeCondition>,
250    /// Directives in the fragment.
251    pub directives: Vec<Positioned<Directive>>,
252    /// The fragment's selection set.
253    pub selection_set: Positioned<SelectionSet>,
254}
255
256/// A type a fragment can apply to (`on` followed by the type).
257///
258/// [Reference](https://spec.graphql.org/October2021/#TypeCondition).
259#[derive(Debug, Clone, Serialize, Deserialize)]
260pub struct TypeCondition {
261    /// The type this fragment applies to.
262    pub on: Positioned<Name>,
263}