bluejay_parser/ast/executable/
operation_definition.rs

1use crate::ast::executable::{SelectionSet, VariableDefinitions};
2use crate::ast::{
3    FromTokens, IsMatch, OperationType, ParseError, Tokens, TryFromTokens, VariableDirectives,
4};
5use crate::lexical_token::Name;
6use crate::{HasSpan, Span};
7use bluejay_core::{
8    executable::{OperationDefinition as CoreOperationDefinition, OperationDefinitionReference},
9    Indexable,
10};
11
12#[derive(Debug)]
13pub enum OperationDefinition<'a> {
14    Explicit(ExplicitOperationDefinition<'a>),
15    Implicit(ImplicitOperationDefinition<'a>),
16}
17
18impl<'a> OperationDefinition<'a> {
19    pub fn selection_set(&self) -> &SelectionSet<'a> {
20        match self {
21            Self::Explicit(e) => &e.selection_set,
22            Self::Implicit(i) => &i.selection_set,
23        }
24    }
25}
26
27impl<'a> Indexable for OperationDefinition<'a> {
28    type Id = Span;
29
30    fn id(&self) -> &Self::Id {
31        self.span()
32    }
33}
34
35impl<'a> CoreOperationDefinition for OperationDefinition<'a> {
36    type ExplicitOperationDefinition = ExplicitOperationDefinition<'a>;
37    type ImplicitOperationDefinition = ImplicitOperationDefinition<'a>;
38
39    fn as_ref(&self) -> OperationDefinitionReference<'_, Self> {
40        match self {
41            Self::Explicit(e) => OperationDefinitionReference::Explicit(e),
42            Self::Implicit(i) => OperationDefinitionReference::Implicit(i),
43        }
44    }
45}
46
47impl<'a> FromTokens<'a> for OperationDefinition<'a> {
48    #[inline]
49    fn from_tokens(tokens: &mut impl Tokens<'a>) -> Result<Self, ParseError> {
50        if let Some(operation_type) = OperationType::try_from_tokens(tokens).transpose()? {
51            let name = tokens.next_if_name();
52            let variable_definitions = VariableDefinitions::try_from_tokens(tokens).transpose()?;
53            let directives = VariableDirectives::try_from_tokens(tokens).transpose()?;
54            let selection_set = SelectionSet::from_tokens(tokens)?;
55            let span = operation_type.span().merge(selection_set.span());
56            Ok(Self::Explicit(ExplicitOperationDefinition {
57                operation_type,
58                name,
59                variable_definitions,
60                directives,
61                selection_set,
62                span,
63            }))
64        } else if let Some(selection_set) = SelectionSet::try_from_tokens(tokens).transpose()? {
65            Ok(Self::Implicit(ImplicitOperationDefinition {
66                selection_set,
67            }))
68        } else {
69            Err(tokens.unexpected_token())
70        }
71    }
72}
73
74impl<'a> IsMatch<'a> for OperationDefinition<'a> {
75    #[inline]
76    fn is_match(tokens: &mut impl Tokens<'a>) -> bool {
77        OperationType::is_match(tokens) || SelectionSet::is_match(tokens)
78    }
79}
80
81impl<'a> HasSpan for OperationDefinition<'a> {
82    fn span(&self) -> &Span {
83        match self {
84            Self::Explicit(e) => e.span(),
85            Self::Implicit(i) => i.span(),
86        }
87    }
88}
89
90#[derive(Debug)]
91pub struct ExplicitOperationDefinition<'a> {
92    operation_type: OperationType,
93    name: Option<Name<'a>>,
94    variable_definitions: Option<VariableDefinitions<'a>>,
95    directives: Option<VariableDirectives<'a>>,
96    selection_set: SelectionSet<'a>,
97    span: Span,
98}
99
100impl<'a> bluejay_core::executable::ExplicitOperationDefinition for ExplicitOperationDefinition<'a> {
101    type VariableDefinitions = VariableDefinitions<'a>;
102    type Directives = VariableDirectives<'a>;
103    type SelectionSet = SelectionSet<'a>;
104
105    fn operation_type(&self) -> bluejay_core::OperationType {
106        (&self.operation_type).into()
107    }
108
109    fn name(&self) -> Option<&str> {
110        self.name.as_ref().map(|name| name.as_ref())
111    }
112
113    fn variable_definitions(&self) -> Option<&Self::VariableDefinitions> {
114        self.variable_definitions.as_ref()
115    }
116
117    fn directives(&self) -> Option<&Self::Directives> {
118        self.directives.as_ref()
119    }
120
121    fn selection_set(&self) -> &Self::SelectionSet {
122        &self.selection_set
123    }
124}
125
126impl<'a> ExplicitOperationDefinition<'a> {
127    pub fn name(&self) -> Option<&Name<'a>> {
128        self.name.as_ref()
129    }
130
131    pub fn operation_type(&self) -> &OperationType {
132        &self.operation_type
133    }
134}
135
136impl<'a> HasSpan for ExplicitOperationDefinition<'a> {
137    fn span(&self) -> &Span {
138        &self.span
139    }
140}
141
142#[derive(Debug)]
143pub struct ImplicitOperationDefinition<'a> {
144    selection_set: SelectionSet<'a>,
145}
146
147impl<'a> bluejay_core::executable::ImplicitOperationDefinition for ImplicitOperationDefinition<'a> {
148    type SelectionSet = SelectionSet<'a>;
149
150    fn selection_set(&self) -> &Self::SelectionSet {
151        &self.selection_set
152    }
153}
154
155impl<'a> HasSpan for ImplicitOperationDefinition<'a> {
156    fn span(&self) -> &Span {
157        self.selection_set.span()
158    }
159}