bluejay_parser/ast/definition/
schema_definition.rs

1use crate::ast::definition::{
2    ArgumentsDefinition, Context, CustomScalarTypeDefinition, DefaultContext, Directive,
3    DirectiveDefinition, Directives, EnumTypeDefinition, EnumValueDefinition, EnumValueDefinitions,
4    FieldDefinition, FieldsDefinition, InputFieldsDefinition, InputObjectTypeDefinition, InputType,
5    InputValueDefinition, InterfaceImplementation, InterfaceImplementations,
6    InterfaceTypeDefinition, ObjectTypeDefinition, OutputType, TypeDefinition, UnionMemberType,
7    UnionMemberTypes, UnionTypeDefinition,
8};
9use crate::lexical_token::StringValue;
10use bluejay_core::definition::{
11    HasDirectives, InterfaceImplementation as CoreInterfaceImplementation,
12    ObjectTypeDefinition as CoreObjectTypeDefinition, SchemaDefinition as CoreSchemaDefinition,
13    TypeDefinition as CoreTypeDefinition, TypeDefinitionReference,
14};
15use bluejay_core::AsIter;
16use std::collections::{btree_map::Values, BTreeMap, HashMap};
17
18#[derive(Debug)]
19pub struct SchemaDefinition<'a, C: Context = DefaultContext> {
20    type_definitions: BTreeMap<&'a str, &'a TypeDefinition<'a, C>>,
21    directive_definitions: BTreeMap<&'a str, &'a DirectiveDefinition<'a, C>>,
22    description: Option<&'a StringValue<'a>>,
23    query: &'a ObjectTypeDefinition<'a, C>,
24    mutation: Option<&'a ObjectTypeDefinition<'a, C>>,
25    subscription: Option<&'a ObjectTypeDefinition<'a, C>>,
26    directives: Option<&'a Directives<'a, C>>,
27    interface_implementors: HashMap<&'a str, Vec<&'a ObjectTypeDefinition<'a, C>>>,
28}
29
30impl<'a, C: Context> SchemaDefinition<'a, C> {
31    pub(crate) fn new(
32        type_definitions: BTreeMap<&'a str, &'a TypeDefinition<'a, C>>,
33        directive_definitions: BTreeMap<&'a str, &'a DirectiveDefinition<'a, C>>,
34        description: Option<&'a StringValue>,
35        query: &'a ObjectTypeDefinition<'a, C>,
36        mutation: Option<&'a ObjectTypeDefinition<'a, C>>,
37        subscription: Option<&'a ObjectTypeDefinition<'a, C>>,
38        directives: Option<&'a Directives<'a, C>>,
39    ) -> Self {
40        let interface_implementors = Self::interface_implementors(&type_definitions);
41        Self {
42            type_definitions,
43            directive_definitions,
44            description,
45            query,
46            mutation,
47            subscription,
48            directives,
49            interface_implementors,
50        }
51    }
52
53    fn interface_implementors(
54        type_definitions: &BTreeMap<&'a str, &'a TypeDefinition<'a, C>>,
55    ) -> HashMap<&'a str, Vec<&'a ObjectTypeDefinition<'a, C>>> {
56        type_definitions.values().fold(
57            HashMap::new(),
58            |mut interface_implementors, &type_definition| {
59                if let TypeDefinition::Object(otd) = type_definition {
60                    if let Some(interface_implementations) = otd.interface_implementations() {
61                        interface_implementations
62                            .iter()
63                            .for_each(|interface_implementation| {
64                                let itd_name = interface_implementation.name();
65                                interface_implementors
66                                    .entry(itd_name)
67                                    .or_default()
68                                    .push(otd);
69                            });
70                    }
71                }
72
73                interface_implementors
74            },
75        )
76    }
77}
78
79impl<'a, C: Context> CoreSchemaDefinition for SchemaDefinition<'a, C> {
80    type Directive = Directive<'a, C>;
81    type Directives = Directives<'a, C>;
82    type InputValueDefinition = InputValueDefinition<'a, C>;
83    type InputFieldsDefinition = InputFieldsDefinition<'a, C>;
84    type ArgumentsDefinition = ArgumentsDefinition<'a, C>;
85    type EnumValueDefinition = EnumValueDefinition<'a, C>;
86    type EnumValueDefinitions = EnumValueDefinitions<'a, C>;
87    type FieldDefinition = FieldDefinition<'a, C>;
88    type FieldsDefinition = FieldsDefinition<'a, C>;
89    type InterfaceImplementation = InterfaceImplementation<'a, C>;
90    type InterfaceImplementations = InterfaceImplementations<'a, C>;
91    type UnionMemberType = UnionMemberType<'a, C>;
92    type UnionMemberTypes = UnionMemberTypes<'a, C>;
93    type InputType = InputType<'a, C>;
94    type OutputType = OutputType<'a, C>;
95    type CustomScalarTypeDefinition = CustomScalarTypeDefinition<'a, C>;
96    type ObjectTypeDefinition = ObjectTypeDefinition<'a, C>;
97    type InterfaceTypeDefinition = InterfaceTypeDefinition<'a, C>;
98    type UnionTypeDefinition = UnionTypeDefinition<'a, C>;
99    type InputObjectTypeDefinition = InputObjectTypeDefinition<'a, C>;
100    type EnumTypeDefinition = EnumTypeDefinition<'a, C>;
101    type TypeDefinition = TypeDefinition<'a, C>;
102    type DirectiveDefinition = DirectiveDefinition<'a, C>;
103    type TypeDefinitions<'b>
104        = std::iter::Map<
105        Values<'b, &'b str, &'b TypeDefinition<'a, C>>,
106        fn(&&'b TypeDefinition<'a, C>) -> TypeDefinitionReference<'b, TypeDefinition<'a, C>>,
107    >
108    where
109        'a: 'b;
110    type DirectiveDefinitions<'b>
111        = std::iter::Copied<Values<'b, &'b str, &'b DirectiveDefinition<'a, C>>>
112    where
113        'a: 'b;
114    type InterfaceImplementors<'b>
115        = std::iter::Flatten<
116        std::option::IntoIter<
117            std::iter::Copied<std::slice::Iter<'b, &'b ObjectTypeDefinition<'a, C>>>,
118        >,
119    >
120    where
121        'a: 'b;
122
123    fn description(&self) -> Option<&str> {
124        self.description.as_ref().map(AsRef::as_ref)
125    }
126
127    fn query(&self) -> &Self::ObjectTypeDefinition {
128        self.query
129    }
130
131    fn mutation(&self) -> Option<&Self::ObjectTypeDefinition> {
132        self.mutation
133    }
134
135    fn subscription(&self) -> Option<&Self::ObjectTypeDefinition> {
136        self.subscription
137    }
138
139    fn get_type_definition(
140        &self,
141        name: &str,
142    ) -> Option<TypeDefinitionReference<'_, Self::TypeDefinition>> {
143        self.type_definitions.get(name).map(|td| td.as_ref())
144    }
145
146    fn type_definitions(&self) -> Self::TypeDefinitions<'_> {
147        self.type_definitions.values().map(
148            |td: &&TypeDefinition<C>| -> TypeDefinitionReference<'_, TypeDefinition<'a, C>> {
149                td.as_ref()
150            },
151        )
152    }
153
154    fn get_directive_definition(&self, name: &str) -> Option<&Self::DirectiveDefinition> {
155        self.directive_definitions.get(name).copied()
156    }
157
158    fn directive_definitions(&self) -> Self::DirectiveDefinitions<'_> {
159        self.directive_definitions.values().copied()
160    }
161
162    fn get_interface_implementors(
163        &self,
164        itd: &Self::InterfaceTypeDefinition,
165    ) -> Self::InterfaceImplementors<'_> {
166        self.interface_implementors
167            .get(itd.name().as_ref())
168            .map(|implementors| implementors.iter().copied())
169            .into_iter()
170            .flatten()
171    }
172}
173
174impl<'a, C: Context> HasDirectives for SchemaDefinition<'a, C> {
175    type Directives = Directives<'a, C>;
176
177    fn directives(&self) -> Option<&Self::Directives> {
178        self.directives
179    }
180}