Skip to main content

bluejay_parser/ast/definition/
explicit_schema_definition.rs

1use crate::ast::{
2    definition::{Context, Directives},
3    ConstDirectives, DepthLimiter, FromTokens, ParseError, Tokens, TryFromTokens,
4};
5use crate::lexical_token::{Name, PunctuatorType, StringValue};
6use crate::Span;
7use bluejay_core::OperationType;
8use std::str::FromStr;
9
10#[derive(Debug)]
11pub struct ExplicitSchemaDefinition<'a, C: Context> {
12    description: Option<StringValue<'a>>,
13    schema_identifier_span: Span,
14    directives: Option<Directives<'a, C>>,
15    root_operation_type_definitions: Vec<RootOperationTypeDefinition<'a>>,
16    root_operation_type_definitions_span: Span,
17}
18
19impl<'a, C: Context> ExplicitSchemaDefinition<'a, C> {
20    pub(crate) const SCHEMA_IDENTIFIER: &'static str = "schema";
21
22    pub(crate) fn description(&self) -> Option<&StringValue<'_>> {
23        self.description.as_ref()
24    }
25
26    pub(crate) fn root_operation_type_definitions(&self) -> &[RootOperationTypeDefinition<'a>] {
27        &self.root_operation_type_definitions
28    }
29
30    pub(crate) fn directives(&self) -> Option<&Directives<'a, C>> {
31        self.directives.as_ref()
32    }
33
34    pub(crate) fn schema_identifier_span(&self) -> &Span {
35        &self.schema_identifier_span
36    }
37
38    pub(crate) fn root_operation_type_definitions_span(&self) -> &Span {
39        &self.root_operation_type_definitions_span
40    }
41}
42
43impl<'a, C: Context> FromTokens<'a> for ExplicitSchemaDefinition<'a, C> {
44    fn from_tokens(
45        tokens: &mut impl Tokens<'a>,
46        depth_limiter: DepthLimiter,
47    ) -> Result<Self, ParseError> {
48        let description = tokens.next_if_string_value();
49
50        let schema_identifier_span = tokens.expect_name_value(Self::SCHEMA_IDENTIFIER)?;
51
52        let directives = ConstDirectives::try_from_tokens(tokens, depth_limiter.bump()?)?;
53
54        let mut root_operation_type_definitions = Vec::new();
55
56        let open_span = tokens.expect_punctuator(PunctuatorType::OpenBrace)?;
57
58        let close_span = loop {
59            root_operation_type_definitions.push(RootOperationTypeDefinition::from_tokens(
60                tokens,
61                depth_limiter.bump()?,
62            )?);
63            if let Some(close_span) = tokens.next_if_punctuator(PunctuatorType::CloseBrace) {
64                break close_span;
65            }
66        };
67
68        let root_operation_type_definitions_span = open_span.merge(&close_span);
69
70        Ok(Self {
71            description,
72            schema_identifier_span,
73            directives: directives.map(Directives::from),
74            root_operation_type_definitions,
75            root_operation_type_definitions_span,
76        })
77    }
78}
79
80#[derive(Debug)]
81pub struct RootOperationTypeDefinition<'a> {
82    operation_type: OperationType,
83    name: Name<'a>,
84}
85
86impl<'a> RootOperationTypeDefinition<'a> {
87    pub(crate) fn operation_type(&self) -> OperationType {
88        self.operation_type
89    }
90
91    pub(crate) fn name_token(&self) -> &Name<'a> {
92        &self.name
93    }
94
95    pub(crate) fn name(&self) -> &str {
96        self.name.as_ref()
97    }
98}
99
100impl<'a> FromTokens<'a> for RootOperationTypeDefinition<'a> {
101    fn from_tokens(tokens: &mut impl Tokens<'a>, _: DepthLimiter) -> Result<Self, ParseError> {
102        let operation_type = tokens.expect_name().and_then(|name| {
103            OperationType::from_str(name.as_str()).map_err(|_| ParseError::ExpectedOneOf {
104                span: name.into(),
105                values: OperationType::POSSIBLE_VALUES,
106            })
107        })?;
108        tokens.expect_punctuator(PunctuatorType::Colon)?;
109        let name = tokens.expect_name()?;
110        Ok(Self {
111            operation_type,
112            name,
113        })
114    }
115}