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> = std::iter::Map<
104        Values<'b, &'b str, &'b TypeDefinition<'a, C>>,
105        fn(&&'b TypeDefinition<'a, C>) -> TypeDefinitionReference<'b, TypeDefinition<'a, C>>
106    > where 'a: 'b;
107    type DirectiveDefinitions<'b> =
108        std::iter::Copied<Values<'b, &'b str, &'b DirectiveDefinition<'a, C>>> where 'a: 'b;
109    type InterfaceImplementors<'b> = std::iter::Flatten<std::option::IntoIter<std::iter::Copied<std::slice::Iter<'b, &'b ObjectTypeDefinition<'a, C>>>>> where 'a: 'b;
110
111    fn description(&self) -> Option<&str> {
112        self.description.as_ref().map(AsRef::as_ref)
113    }
114
115    fn query(&self) -> &Self::ObjectTypeDefinition {
116        self.query
117    }
118
119    fn mutation(&self) -> Option<&Self::ObjectTypeDefinition> {
120        self.mutation
121    }
122
123    fn subscription(&self) -> Option<&Self::ObjectTypeDefinition> {
124        self.subscription
125    }
126
127    fn get_type_definition(
128        &self,
129        name: &str,
130    ) -> Option<TypeDefinitionReference<'_, Self::TypeDefinition>> {
131        self.type_definitions.get(name).map(|td| td.as_ref())
132    }
133
134    fn type_definitions(&self) -> Self::TypeDefinitions<'_> {
135        self.type_definitions.values().map(
136            |td: &&TypeDefinition<C>| -> TypeDefinitionReference<'_, TypeDefinition<'a, C>> {
137                td.as_ref()
138            },
139        )
140    }
141
142    fn get_directive_definition(&self, name: &str) -> Option<&Self::DirectiveDefinition> {
143        self.directive_definitions.get(name).copied()
144    }
145
146    fn directive_definitions(&self) -> Self::DirectiveDefinitions<'_> {
147        self.directive_definitions.values().copied()
148    }
149
150    fn get_interface_implementors(
151        &self,
152        itd: &Self::InterfaceTypeDefinition,
153    ) -> Self::InterfaceImplementors<'_> {
154        self.interface_implementors
155            .get(itd.name().as_ref())
156            .map(|implementors| implementors.iter().copied())
157            .into_iter()
158            .flatten()
159    }
160}
161
162impl<'a, C: Context> HasDirectives for SchemaDefinition<'a, C> {
163    type Directives = Directives<'a, C>;
164
165    fn directives(&self) -> Option<&Self::Directives> {
166        self.directives
167    }
168}