1use crate::{
2 ArgumentsDefinition, Cache, Directive, DirectiveDefinition, Directives, EnumTypeDefinition,
3 EnumValueDefinition, EnumValueDefinitions, FieldDefinition, FieldsDefinition,
4 InputFieldsDefinition, InputObjectTypeDefinition, InputType, InputValueDefinition,
5 InterfaceImplementation, InterfaceImplementations, InterfaceTypeDefinition,
6 ObjectTypeDefinition, OutputType, ScalarTypeDefinition, TypeDefinition, UnionMemberType,
7 UnionMemberTypes, UnionTypeDefinition, Warden,
8};
9use bluejay_core::definition::{
10 self, prelude::*, DirectiveLocation, HasDirectives, TypeDefinitionReference,
11};
12use bluejay_core::{AsIter, Directive as _};
13use elsa::FrozenMap;
14use once_cell::unsync::OnceCell;
15use std::collections::{
16 btree_map::{self, Entry},
17 BTreeMap,
18};
19
20#[derive(Debug)]
21pub enum SchemaDefinitionError<'a> {
22 QueryRootNotVisible,
23 NonUniqueTypeDefinitionName(&'a str),
24}
25
26pub struct SchemaDefinition<'a, S: definition::SchemaDefinition, W: Warden<SchemaDefinition = S>> {
27 cache: &'a Cache<'a, S, W>,
28 query: &'a ObjectTypeDefinition<'a, S, W>,
29 mutation: Option<&'a ObjectTypeDefinition<'a, S, W>>,
30 subscription: Option<&'a ObjectTypeDefinition<'a, S, W>>,
31 interface_implementors: FrozenMap<&'a str, Vec<&'a ObjectTypeDefinition<'a, S, W>>>,
32 type_definitions_and_directive_definitions:
33 OnceCell<TypeDefinitionsAndDirectiveDefinitions<'a, S, W>>,
34 directives: Option<Directives<'a, S, W>>,
35}
36
37impl<'a, S: definition::SchemaDefinition, W: Warden<SchemaDefinition = S>>
38 SchemaDefinition<'a, S, W>
39{
40 pub fn new(cache: &'a Cache<'a, S, W>) -> Result<Self, SchemaDefinitionError<'a>> {
41 let inner = cache.inner_schema_definition();
42 Ok(Self {
43 cache,
44 query: cache
45 .get_or_create_type_definition(TypeDefinitionReference::Object(inner.query()))
46 .ok_or(SchemaDefinitionError::QueryRootNotVisible)
47 .map(|td| {
48 td.as_object()
49 .expect("Error with internal handling of non-unique type names")
50 })?,
51 mutation: inner.mutation().and_then(|mutation| {
52 cache
53 .get_or_create_type_definition(TypeDefinitionReference::Object(mutation))
54 .map(|td| {
55 td.as_object()
56 .expect("Error with internal handling of non-unique type names")
57 })
58 }),
59 subscription: inner.subscription().and_then(|subscription| {
60 cache
61 .get_or_create_type_definition(TypeDefinitionReference::Object(subscription))
62 .map(|td| {
63 td.as_object()
64 .expect("Error with internal handling of non-unique type names")
65 })
66 }),
67 interface_implementors: FrozenMap::new(),
68 type_definitions_and_directive_definitions: OnceCell::new(),
69 directives: inner.directives().map(|d| Directives::new(d, cache)),
70 })
71 }
72
73 pub fn inner(&self) -> &'a S {
74 self.cache.inner_schema_definition()
75 }
76
77 pub fn cache(&self) -> &'a Cache<'a, S, W> {
78 self.cache
79 }
80
81 fn type_definitions_and_directive_definitions(
82 &self,
83 ) -> &TypeDefinitionsAndDirectiveDefinitions<'a, S, W> {
84 self.type_definitions_and_directive_definitions
85 .get_or_init(|| VisibilityVisitor::visit(self))
86 }
87
88 fn get_directive_definition(&self, name: &str) -> Option<&'a DirectiveDefinition<'a, S, W>> {
91 self.cache.get_directive_definition(name).or_else(|| {
92 self.inner()
93 .get_directive_definition(name)
94 .and_then(|dd| self.cache.get_or_create_directive_definition(dd))
95 })
96 }
97
98 fn get_interface_implementors(
101 &self,
102 itd: &InterfaceTypeDefinition<'a, S, W>,
103 ) -> std::iter::Copied<std::slice::Iter<'_, &'a ObjectTypeDefinition<'a, S, W>>> {
104 self.interface_implementors
105 .get(itd.name())
106 .map(|ii| ii.iter())
107 .unwrap_or_else(|| {
108 let interface_implementors = self
109 .inner()
110 .get_interface_implementors(itd.inner())
111 .filter_map(|otd| {
112 let otd = self
113 .cache
114 .get_or_create_type_definition(
115 definition::TypeDefinitionReference::Object(otd),
116 )?
117 .as_object()
118 .unwrap();
119
120 otd.interface_implementations()
121 .is_some_and(|interface_implementations| {
122 interface_implementations
123 .iter()
124 .any(|ii| ii.name() == itd.name())
125 })
126 .then_some(otd)
127 })
128 .collect();
129 self.interface_implementors
130 .insert(itd.inner().name(), interface_implementors)
131 .iter()
132 })
133 .copied()
134 }
135}
136
137impl<'a, S: definition::SchemaDefinition + 'a, W: Warden<SchemaDefinition = S>>
138 definition::SchemaDefinition for SchemaDefinition<'a, S, W>
139{
140 type Directive = Directive<'a, S, W>;
141 type Directives = Directives<'a, S, W>;
142 type InputValueDefinition = InputValueDefinition<'a, S, W>;
143 type InputFieldsDefinition = InputFieldsDefinition<'a, S, W>;
144 type ArgumentsDefinition = ArgumentsDefinition<'a, S, W>;
145 type EnumValueDefinition = EnumValueDefinition<'a, S, W>;
146 type EnumValueDefinitions = EnumValueDefinitions<'a, S, W>;
147 type FieldDefinition = FieldDefinition<'a, S, W>;
148 type FieldsDefinition = FieldsDefinition<'a, S, W>;
149 type InterfaceImplementation = InterfaceImplementation<'a, S, W>;
150 type InterfaceImplementations = InterfaceImplementations<'a, S, W>;
151 type UnionMemberType = UnionMemberType<'a, S, W>;
152 type UnionMemberTypes = UnionMemberTypes<'a, S, W>;
153 type InputType = InputType<'a, S, W>;
154 type OutputType = OutputType<'a, S, W>;
155 type CustomScalarTypeDefinition = ScalarTypeDefinition<'a, S, W>;
156 type ObjectTypeDefinition = ObjectTypeDefinition<'a, S, W>;
157 type InterfaceTypeDefinition = InterfaceTypeDefinition<'a, S, W>;
158 type UnionTypeDefinition = UnionTypeDefinition<'a, S, W>;
159 type InputObjectTypeDefinition = InputObjectTypeDefinition<'a, S, W>;
160 type EnumTypeDefinition = EnumTypeDefinition<'a, S, W>;
161 type TypeDefinition = TypeDefinition<'a, S, W>;
162 type DirectiveDefinition = DirectiveDefinition<'a, S, W>;
163 type TypeDefinitions<'b>
164 = std::iter::Copied<
165 btree_map::Values<'b, &'a str, TypeDefinitionReference<'b, Self::TypeDefinition>>,
166 >
167 where
168 'a: 'b;
169 type DirectiveDefinitions<'b>
170 = std::iter::Copied<btree_map::Values<'b, &'a str, &'b Self::DirectiveDefinition>>
171 where
172 'a: 'b;
173 type InterfaceImplementors<'b>
174 = std::iter::Copied<std::slice::Iter<'b, &'b Self::ObjectTypeDefinition>>
175 where
176 'a: 'b;
177
178 fn description(&self) -> Option<&str> {
179 self.inner().description()
180 }
181
182 fn query(&self) -> &Self::ObjectTypeDefinition {
183 self.query
184 }
185
186 fn mutation(&self) -> Option<&Self::ObjectTypeDefinition> {
187 self.mutation
188 }
189
190 fn subscription(&self) -> Option<&Self::ObjectTypeDefinition> {
191 self.subscription
192 }
193
194 fn type_definitions(&self) -> Self::TypeDefinitions<'_> {
195 self.type_definitions_and_directive_definitions()
196 .type_definitions
197 .values()
198 .copied()
199 }
200
201 fn get_type_definition(
202 &self,
203 name: &str,
204 ) -> Option<definition::TypeDefinitionReference<Self::TypeDefinition>> {
205 self.cache
206 .get_type_definition(name)
207 .or_else(|| {
208 self.cache
209 .warden()
210 .type_definitions_for_name(self.inner(), name)
211 .find_map(|tdr| self.cache.get_or_create_type_definition(tdr))
212 })
213 .map(TypeDefinition::as_ref)
214 }
215
216 fn get_interface_implementors(
217 &self,
218 itd: &Self::InterfaceTypeDefinition,
219 ) -> Self::InterfaceImplementors<'_> {
220 SchemaDefinition::get_interface_implementors(self, itd)
221 }
222
223 fn directive_definitions(&self) -> Self::DirectiveDefinitions<'_> {
224 self.type_definitions_and_directive_definitions()
225 .directive_definitions
226 .values()
227 .copied()
228 }
229
230 fn get_directive_definition(&self, name: &str) -> Option<&Self::DirectiveDefinition> {
231 SchemaDefinition::get_directive_definition(self, name)
232 }
233}
234
235impl<'a, S: definition::SchemaDefinition + 'a, W: Warden<SchemaDefinition = S>> HasDirectives
236 for SchemaDefinition<'a, S, W>
237{
238 type Directives = Directives<'a, S, W>;
239
240 fn directives(&self) -> Option<&Self::Directives> {
241 self.directives.as_ref()
242 }
243}
244
245struct TypeDefinitionsAndDirectiveDefinitions<
246 'a,
247 S: definition::SchemaDefinition,
248 W: Warden<SchemaDefinition = S>,
249> {
250 type_definitions: BTreeMap<&'a str, TypeDefinitionReference<'a, TypeDefinition<'a, S, W>>>,
251 directive_definitions: BTreeMap<&'a str, &'a DirectiveDefinition<'a, S, W>>,
252}
253
254impl<'a, S: definition::SchemaDefinition, W: Warden<SchemaDefinition = S>>
255 From<VisibilityVisitor<'a, '_, S, W>> for TypeDefinitionsAndDirectiveDefinitions<'a, S, W>
256{
257 fn from(value: VisibilityVisitor<'a, '_, S, W>) -> Self {
258 let VisibilityVisitor {
259 type_definitions,
260 directive_definitions,
261 ..
262 } = value;
263 Self {
264 type_definitions,
265 directive_definitions,
266 }
267 }
268}
269
270struct VisibilityVisitor<'a, 'b, S: definition::SchemaDefinition, W: Warden<SchemaDefinition = S>> {
271 schema_definition: &'b SchemaDefinition<'a, S, W>,
272 type_definitions: BTreeMap<&'a str, TypeDefinitionReference<'a, TypeDefinition<'a, S, W>>>,
273 directive_definitions: BTreeMap<&'a str, &'a DirectiveDefinition<'a, S, W>>,
274}
275
276impl<'a, 'b, S: definition::SchemaDefinition, W: Warden<SchemaDefinition = S>>
277 VisibilityVisitor<'a, 'b, S, W>
278{
279 fn visit(
280 schema_definition: &'b SchemaDefinition<'a, S, W>,
281 ) -> TypeDefinitionsAndDirectiveDefinitions<'a, S, W> {
282 let mut instance = Self {
283 schema_definition,
284 type_definitions: BTreeMap::new(),
285 directive_definitions: BTreeMap::new(),
286 };
287
288 schema_definition
292 .inner()
293 .directive_definitions()
294 .for_each(|dd| {
295 if dd.is_builtin() || dd.locations().iter().any(DirectiveLocation::is_executable) {
296 if let Some(dd) = schema_definition
297 .cache
298 .get_or_create_directive_definition(dd)
299 {
300 instance.visit_directive_definition(dd);
301 }
302 }
303 });
304
305 instance.visit_type_definition(TypeDefinitionReference::Object(schema_definition.query));
306
307 if let Some(mutation) = schema_definition.mutation {
308 instance.visit_type_definition(TypeDefinitionReference::Object(mutation));
309 }
310
311 if let Some(subscription) = schema_definition.subscription {
312 instance.visit_type_definition(TypeDefinitionReference::Object(subscription));
313 }
314
315 instance.into()
316 }
317
318 fn visit_type_definition(
319 &mut self,
320 type_definition: TypeDefinitionReference<'a, TypeDefinition<'a, S, W>>,
321 ) {
322 if let Entry::Vacant(entry) = self.type_definitions.entry(type_definition.name()) {
323 entry.insert(type_definition);
324
325 match type_definition {
326 TypeDefinitionReference::BuiltinScalar(_) => {}
327 TypeDefinitionReference::CustomScalar(cstd) => {
328 self.visit_custom_scalar_type_definition(cstd)
329 }
330 TypeDefinitionReference::Object(otd) => self.visit_object_type_definition(otd),
331 TypeDefinitionReference::Interface(itd) => {
332 self.visit_interface_type_definition(itd)
333 }
334 TypeDefinitionReference::Union(utd) => self.visit_union_type_definition(utd),
335 TypeDefinitionReference::Enum(etd) => self.visit_enum_type_definition(etd),
336 TypeDefinitionReference::InputObject(iotd) => {
337 self.visit_input_object_type_definition(iotd)
338 }
339 }
340 }
341 }
342
343 fn visit_custom_scalar_type_definition(
344 &mut self,
345 custom_scalar_type_definition: &'a ScalarTypeDefinition<'a, S, W>,
346 ) {
347 self.visit_directives(custom_scalar_type_definition.directives());
348 }
349
350 fn visit_object_type_definition(
351 &mut self,
352 object_type_definition: &'a ObjectTypeDefinition<'a, S, W>,
353 ) {
354 self.visit_directives(object_type_definition.directives());
355 self.visit_fields_definition(object_type_definition.fields_definition());
356 if let Some(interface_implementations) = object_type_definition.interface_implementations()
357 {
358 self.visit_interface_implementations(interface_implementations);
359 }
360 }
361
362 fn visit_interface_type_definition(
363 &mut self,
364 interface_type_definition: &'a InterfaceTypeDefinition<'a, S, W>,
365 ) {
366 self.visit_directives(interface_type_definition.directives());
367 self.visit_fields_definition(interface_type_definition.fields_definition());
368 if let Some(interface_implementations) =
369 interface_type_definition.interface_implementations()
370 {
371 self.visit_interface_implementations(interface_implementations);
372 }
373 self.schema_definition
374 .get_interface_implementors(interface_type_definition)
375 .for_each(|otd| {
376 self.visit_type_definition(TypeDefinitionReference::Object(otd));
377 })
378 }
379
380 fn visit_union_type_definition(
381 &mut self,
382 union_type_definition: &'a UnionTypeDefinition<'a, S, W>,
383 ) {
384 self.visit_directives(union_type_definition.directives());
385 union_type_definition
386 .union_member_types()
387 .iter()
388 .for_each(|member_type| {
389 self.visit_type_definition(TypeDefinitionReference::Object(
390 member_type.member_type(),
391 ))
392 })
393 }
394
395 fn visit_enum_type_definition(
396 &mut self,
397 enum_type_definition: &'a EnumTypeDefinition<'a, S, W>,
398 ) {
399 self.visit_directives(enum_type_definition.directives());
400 enum_type_definition
401 .enum_value_definitions()
402 .iter()
403 .for_each(|etd| {
404 self.visit_directives(etd.directives());
405 })
406 }
407
408 fn visit_input_object_type_definition(
409 &mut self,
410 input_object_type_definition: &'a InputObjectTypeDefinition<'a, S, W>,
411 ) {
412 self.visit_directives(input_object_type_definition.directives());
413 input_object_type_definition
414 .input_field_definitions()
415 .iter()
416 .for_each(|ivd| {
417 self.visit_input_value_definition(ivd);
418 })
419 }
420
421 fn visit_directives(&mut self, directives: Option<&'a Directives<'a, S, W>>) {
422 if let Some(directives) = directives {
423 directives.iter().for_each(|directive| {
424 if let Some(directive_definition) = self
427 .schema_definition
428 .get_directive_definition(directive.name())
429 {
430 self.visit_directive_definition(directive_definition);
431 }
432 })
433 }
434 }
435
436 fn visit_directive_definition(
437 &mut self,
438 directive_definition: &'a DirectiveDefinition<'a, S, W>,
439 ) {
440 if let Entry::Vacant(entry) = self
441 .directive_definitions
442 .entry(directive_definition.name())
443 {
444 entry.insert(directive_definition);
445 if let Some(arguments_definition) = directive_definition.arguments_definition() {
446 self.visit_arguments_definition(arguments_definition);
447 }
448 }
449 }
450
451 fn visit_fields_definition(&mut self, fields_definition: &'a FieldsDefinition<'a, S, W>) {
452 fields_definition.iter().for_each(|field| {
453 self.visit_field_definition(field);
454 })
455 }
456
457 fn visit_field_definition(&mut self, field_definition: &'a FieldDefinition<'a, S, W>) {
458 self.visit_directives(field_definition.directives());
459 if let Some(arguments_definition) = field_definition.arguments_definition() {
460 self.visit_arguments_definition(arguments_definition);
461 }
462 let base_type = field_definition.r#type().base();
463 self.visit_type_definition(base_type.into())
464 }
465
466 fn visit_arguments_definition(
467 &mut self,
468 arguments_definition: &'a ArgumentsDefinition<'a, S, W>,
469 ) {
470 arguments_definition.iter().for_each(|ivd| {
471 self.visit_input_value_definition(ivd);
472 })
473 }
474
475 fn visit_input_value_definition(
476 &mut self,
477 input_value_definition: &'a InputValueDefinition<'a, S, W>,
478 ) {
479 self.visit_directives(input_value_definition.directives());
480 let base_type = input_value_definition.r#type().base();
481 self.visit_type_definition(base_type.into())
482 }
483
484 fn visit_interface_implementations(
485 &mut self,
486 interface_implementations: &'a InterfaceImplementations<'a, S, W>,
487 ) {
488 interface_implementations.iter().for_each(|ii| {
489 self.visit_type_definition(TypeDefinitionReference::Interface(ii.interface()));
490 })
491 }
492}