bluejay_parser/ast/executable/
operation_definition.rs

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