bluejay_parser/ast/definition/
explicit_schema_definition.rs1use 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 =
53 ConstDirectives::try_from_tokens(tokens, depth_limiter.bump()?).transpose()?;
54
55 let mut root_operation_type_definitions = Vec::new();
56
57 let open_span = tokens.expect_punctuator(PunctuatorType::OpenBrace)?;
58
59 let close_span = loop {
60 root_operation_type_definitions.push(RootOperationTypeDefinition::from_tokens(
61 tokens,
62 depth_limiter.bump()?,
63 )?);
64 if let Some(close_span) = tokens.next_if_punctuator(PunctuatorType::CloseBrace) {
65 break close_span;
66 }
67 };
68
69 let root_operation_type_definitions_span = open_span.merge(&close_span);
70
71 Ok(Self {
72 description,
73 schema_identifier_span,
74 directives: directives.map(Directives::from),
75 root_operation_type_definitions,
76 root_operation_type_definitions_span,
77 })
78 }
79}
80
81#[derive(Debug)]
82pub struct RootOperationTypeDefinition<'a> {
83 operation_type: OperationType,
84 name: Name<'a>,
85}
86
87impl<'a> RootOperationTypeDefinition<'a> {
88 pub(crate) fn operation_type(&self) -> OperationType {
89 self.operation_type
90 }
91
92 pub(crate) fn name_token(&self) -> &Name<'a> {
93 &self.name
94 }
95
96 pub(crate) fn name(&self) -> &str {
97 self.name.as_ref()
98 }
99}
100
101impl<'a> FromTokens<'a> for RootOperationTypeDefinition<'a> {
102 fn from_tokens(tokens: &mut impl Tokens<'a>, _: DepthLimiter) -> Result<Self, ParseError> {
103 let operation_type = tokens.expect_name().and_then(|name| {
104 OperationType::from_str(name.as_str()).map_err(|_| ParseError::ExpectedOneOf {
105 span: name.into(),
106 values: OperationType::POSSIBLE_VALUES,
107 })
108 })?;
109 tokens.expect_punctuator(PunctuatorType::Colon)?;
110 let name = tokens.expect_name()?;
111 Ok(Self {
112 operation_type,
113 name,
114 })
115 }
116}