bluejay_parser/ast/definition/
field_definition.rs

1use crate::ast::definition::{ArgumentsDefinition, Context, Directives, OutputType};
2use crate::ast::{
3    ConstDirectives, DepthLimiter, FromTokens, Parse, ParseError, Tokens, TryFromTokens,
4};
5use crate::lexical_token::{Name, PunctuatorType, StringValue};
6use bluejay_core::definition::{FieldDefinition as CoreFieldDefinition, HasDirectives};
7
8#[derive(Debug)]
9pub struct FieldDefinition<'a, C: Context> {
10    description: Option<StringValue<'a>>,
11    name: Name<'a>,
12    arguments_definition: Option<ArgumentsDefinition<'a, C>>,
13    r#type: OutputType<'a, C>,
14    directives: Option<Directives<'a, C>>,
15    is_builtin: bool,
16}
17
18impl<C: Context> FieldDefinition<'_, C> {
19    const __TYPENAME_DEFINITION: &'static str = "__typename: String!";
20    const __SCHEMA_DEFINITION: &'static str = "__schema: __Schema!";
21    const __TYPE_DEFINITION: &'static str = "__type(name: String!): __Type";
22
23    fn builtin(s: &'static str) -> Self {
24        let mut definition = Self::parse(s).unwrap();
25        definition.is_builtin = true;
26        definition
27    }
28
29    pub(crate) fn __typename() -> Self {
30        Self::builtin(Self::__TYPENAME_DEFINITION)
31    }
32
33    pub(crate) fn __schema() -> Self {
34        Self::builtin(Self::__SCHEMA_DEFINITION)
35    }
36
37    pub(crate) fn __type() -> Self {
38        Self::builtin(Self::__TYPE_DEFINITION)
39    }
40}
41
42impl<'a, C: Context> CoreFieldDefinition for FieldDefinition<'a, C> {
43    type ArgumentsDefinition = ArgumentsDefinition<'a, C>;
44    type OutputType = OutputType<'a, C>;
45
46    fn description(&self) -> Option<&str> {
47        self.description.as_ref().map(AsRef::as_ref)
48    }
49
50    fn name(&self) -> &str {
51        self.name.as_ref()
52    }
53
54    fn arguments_definition(&self) -> Option<&Self::ArgumentsDefinition> {
55        self.arguments_definition.as_ref()
56    }
57
58    fn r#type(&self) -> &Self::OutputType {
59        &self.r#type
60    }
61
62    fn is_builtin(&self) -> bool {
63        self.is_builtin
64    }
65}
66
67impl<'a, C: Context> FromTokens<'a> for FieldDefinition<'a, C> {
68    fn from_tokens(
69        tokens: &mut impl Tokens<'a>,
70        depth_limiter: DepthLimiter,
71    ) -> Result<Self, ParseError> {
72        let description = tokens.next_if_string_value();
73        let name = tokens.expect_name()?;
74        let arguments_definition =
75            ArgumentsDefinition::try_from_tokens(tokens, depth_limiter.bump()?).transpose()?;
76        tokens.expect_punctuator(PunctuatorType::Colon)?;
77        let r#type = OutputType::from_tokens(tokens, depth_limiter.bump()?)?;
78        let directives =
79            ConstDirectives::try_from_tokens(tokens, depth_limiter.bump()?).transpose()?;
80        Ok(Self {
81            description,
82            name,
83            arguments_definition,
84            r#type,
85            directives: directives.map(Directives::from),
86            is_builtin: false,
87        })
88    }
89}
90
91impl<'a, C: Context> HasDirectives for FieldDefinition<'a, C> {
92    type Directives = Directives<'a, C>;
93
94    fn directives(&self) -> Option<&Self::Directives> {
95        self.directives.as_ref()
96    }
97}