1use crate::ast::definition::{
2 directive_definition::BuiltinDirectiveDefinition, BaseInputType, BaseOutputType, Context,
3 CustomScalarTypeDefinition, DefaultContext, DirectiveDefinition, Directives,
4 EnumTypeDefinition, ExplicitSchemaDefinition, FieldsDefinition, InputObjectTypeDefinition,
5 InputValueDefinition, InterfaceImplementations, InterfaceTypeDefinition, ObjectTypeDefinition,
6 SchemaDefinition, TypeDefinition, UnionTypeDefinition,
7};
8use crate::ast::{FromTokens, Parse, ParseError, Tokens};
9use crate::Error;
10use bluejay_core::definition::{prelude::*, HasDirectives};
11use bluejay_core::{
12 AsIter, BuiltinScalarDefinition, Directive as _, IntoEnumIterator, OperationType,
13};
14use std::collections::btree_map::Entry;
15use std::collections::{BTreeMap, HashMap, HashSet};
16
17mod definition_document_error;
18use definition_document_error::DefinitionDocumentError;
19
20#[derive(Debug)]
21pub struct DefinitionDocument<'a, C: Context = DefaultContext> {
22 schema_definitions: Vec<ExplicitSchemaDefinition<'a, C>>,
23 directive_definitions: Vec<DirectiveDefinition<'a, C>>,
24 type_definitions: Vec<TypeDefinition<'a, C>>,
25}
26
27#[derive(Debug)]
28pub struct ImplicitSchemaDefinition<'a, C: Context> {
29 query: &'a ObjectTypeDefinition<'a, C>,
30 mutation: Option<&'a ObjectTypeDefinition<'a, C>>,
31 subscription: Option<&'a ObjectTypeDefinition<'a, C>>,
32}
33
34type ExplicitSchemaDefinitionWithRootTypes<'a, C> = (
35 &'a ExplicitSchemaDefinition<'a, C>,
36 &'a ObjectTypeDefinition<'a, C>,
37 Option<&'a ObjectTypeDefinition<'a, C>>,
38 Option<&'a ObjectTypeDefinition<'a, C>>,
39);
40
41impl<'a, C: Context> Parse<'a> for DefinitionDocument<'a, C> {
42 fn parse_from_tokens(mut tokens: impl Tokens<'a>) -> Result<Self, Vec<Error>> {
43 let mut instance: Self = Self::new();
44 let mut errors = Vec::new();
45 let mut last_pass_had_error = false;
46
47 loop {
48 match Self::next_definition_identifier(&mut tokens) {
49 Some(CustomScalarTypeDefinition::<C>::SCALAR_IDENTIFIER) => {
50 Self::parse_definition::<_, CustomScalarTypeDefinition<C>>(
51 &mut instance.type_definitions,
52 &mut tokens,
53 &mut errors,
54 &mut last_pass_had_error,
55 )
56 }
57 Some(ObjectTypeDefinition::<C>::TYPE_IDENTIFIER) => {
58 Self::parse_definition::<_, ObjectTypeDefinition<C>>(
59 &mut instance.type_definitions,
60 &mut tokens,
61 &mut errors,
62 &mut last_pass_had_error,
63 )
64 }
65 Some(InputObjectTypeDefinition::<C>::INPUT_IDENTIFIER) => {
66 Self::parse_definition::<_, InputObjectTypeDefinition<C>>(
67 &mut instance.type_definitions,
68 &mut tokens,
69 &mut errors,
70 &mut last_pass_had_error,
71 )
72 }
73 Some(EnumTypeDefinition::<C>::ENUM_IDENTIFIER) => {
74 Self::parse_definition::<_, EnumTypeDefinition<C>>(
75 &mut instance.type_definitions,
76 &mut tokens,
77 &mut errors,
78 &mut last_pass_had_error,
79 )
80 }
81 Some(UnionTypeDefinition::<C>::UNION_IDENTIFIER) => {
82 Self::parse_definition::<_, UnionTypeDefinition<C>>(
83 &mut instance.type_definitions,
84 &mut tokens,
85 &mut errors,
86 &mut last_pass_had_error,
87 )
88 }
89 Some(InterfaceTypeDefinition::<C>::INTERFACE_IDENTIFIER) => {
90 Self::parse_definition::<_, InterfaceTypeDefinition<C>>(
91 &mut instance.type_definitions,
92 &mut tokens,
93 &mut errors,
94 &mut last_pass_had_error,
95 )
96 }
97 Some(ExplicitSchemaDefinition::<C>::SCHEMA_IDENTIFIER) => {
98 Self::parse_definition::<_, ExplicitSchemaDefinition<C>>(
99 &mut instance.schema_definitions,
100 &mut tokens,
101 &mut errors,
102 &mut last_pass_had_error,
103 )
104 }
105 Some(DirectiveDefinition::<C>::DIRECTIVE_IDENTIFIER) => {
106 Self::parse_definition::<_, DirectiveDefinition<C>>(
107 &mut instance.directive_definitions,
108 &mut tokens,
109 &mut errors,
110 &mut last_pass_had_error,
111 )
112 }
113 _ => {
114 if let Some(token) = tokens.next() {
115 if !last_pass_had_error {
116 errors.push(ParseError::UnexpectedToken { span: token.into() });
117 last_pass_had_error = true;
118 }
119 } else {
120 break;
121 }
122 }
123 }
124 }
125
126 let lex_errors = tokens.into_errors();
127
128 let errors = if lex_errors.is_empty() {
129 if errors.is_empty() && instance.is_empty() {
130 vec![ParseError::EmptyDocument.into()]
131 } else {
132 errors.into_iter().map(Into::into).collect()
133 }
134 } else {
135 lex_errors.into_iter().map(Into::into).collect()
136 };
137
138 if errors.is_empty() {
139 instance.insert_builtin_scalar_definitions();
140 instance.insert_builtin_directive_definitions();
141 instance.add_query_root_fields();
142 Ok(instance)
143 } else {
144 Err(errors)
145 }
146 }
147}
148
149impl<'a, C: Context> DefinitionDocument<'a, C> {
150 fn new() -> Self {
151 Self {
152 schema_definitions: Vec::new(),
153 directive_definitions: Vec::new(),
154 type_definitions: vec![
155 ObjectTypeDefinition::__schema().into(),
156 ObjectTypeDefinition::__type().into(),
157 ObjectTypeDefinition::__field().into(),
158 ObjectTypeDefinition::__input_value().into(),
159 ObjectTypeDefinition::__enum_value().into(),
160 ObjectTypeDefinition::__directive().into(),
161 EnumTypeDefinition::__type_kind().into(),
162 EnumTypeDefinition::__directive_location().into(),
163 ],
164 }
165 }
166
167 fn parse_definition<'b, S, T: FromTokens<'b> + Into<S>>(
168 definitions: &mut Vec<S>,
169 tokens: &mut impl Tokens<'b>,
170 errors: &mut Vec<ParseError>,
171 last_pass_had_error: &mut bool,
172 ) {
173 match T::from_tokens(tokens) {
174 Ok(definition) => {
175 definitions.push(definition.into());
176 *last_pass_had_error = false;
177 }
178 Err(err) => {
179 if !*last_pass_had_error {
180 errors.push(err);
181 *last_pass_had_error = true;
182 }
183 }
184 }
185 }
186
187 fn insert_builtin_scalar_definitions(&mut self) {
190 let mut builtin_scalars_by_name: HashMap<&str, BuiltinScalarDefinition> =
191 HashMap::from_iter(BuiltinScalarDefinition::iter().map(|bstd| (bstd.name(), bstd)));
192
193 self.type_definitions.iter().for_each(|td| {
194 builtin_scalars_by_name.remove(td.name());
195 });
196
197 self.type_definitions.extend(
198 builtin_scalars_by_name
199 .into_values()
200 .map(TypeDefinition::BuiltinScalar),
201 );
202 }
203
204 fn insert_builtin_directive_definitions(&mut self) {
207 let mut builtin_directive_definitions_by_name: HashMap<&str, BuiltinDirectiveDefinition> =
208 HashMap::from_iter(
209 BuiltinDirectiveDefinition::iter()
210 .map(|bdd: BuiltinDirectiveDefinition| (bdd.into(), bdd)),
211 );
212
213 self.directive_definitions().iter().for_each(|dd| {
214 builtin_directive_definitions_by_name.remove(dd.name());
215 });
216
217 self.directive_definitions.extend(
218 builtin_directive_definitions_by_name
219 .into_values()
220 .map(DirectiveDefinition::from),
221 );
222 }
223
224 fn add_query_root_fields(&mut self) {
225 let explicit_query_roots: HashSet<&str> = HashSet::from_iter(
226 self.schema_definitions
227 .iter()
228 .flat_map(|schema_definition| {
229 schema_definition
230 .root_operation_type_definitions()
231 .iter()
232 .filter(|rotd| rotd.operation_type() == OperationType::Query)
233 .map(|rotd| rotd.name())
234 }),
235 );
236
237 self.type_definitions
238 .iter_mut()
239 .for_each(|type_definition| {
240 if let TypeDefinition::Object(otd) = type_definition {
241 let name = otd.name().as_ref();
242 if name == "Query" || explicit_query_roots.contains(name) {
243 otd.add_query_root_fields();
244 }
245 }
246 })
247 }
248
249 fn is_empty(&self) -> bool {
250 self.definition_count() == 0
251 }
252
253 fn next_definition_identifier(tokens: &mut impl Tokens<'a>) -> Option<&str> {
254 let idx_to_peek = if tokens.peek_string_value(0) { 1 } else { 0 };
255 tokens.peek_name(idx_to_peek).map(AsRef::as_ref)
256 }
257
258 pub fn definition_count(&self) -> usize {
259 self.directive_definitions
260 .iter()
261 .filter(|dd| !dd.is_builtin())
262 .count()
263 + self.schema_definitions.len()
264 + self
265 .type_definitions
266 .iter()
267 .filter(|td| !td.as_ref().is_builtin())
268 .count()
269 }
270
271 pub fn directive_definitions(&self) -> &[DirectiveDefinition<'a, C>] {
272 &self.directive_definitions
273 }
274
275 fn index_directive_definitions(
276 &'a self,
277 errors: &mut Vec<DefinitionDocumentError<'a, C>>,
278 ) -> BTreeMap<&str, &'a DirectiveDefinition<'a, C>> {
279 let mut indexed: BTreeMap<&str, &DirectiveDefinition<'a, C>> = BTreeMap::new();
280 let mut duplicates: BTreeMap<&str, Vec<&DirectiveDefinition<'a, C>>> = BTreeMap::new();
281
282 self.directive_definitions
283 .iter()
284 .for_each(|directive_definition| {
285 match indexed.entry(directive_definition.name().as_ref()) {
286 Entry::Vacant(entry) => {
287 entry.insert(directive_definition);
288 }
289 Entry::Occupied(entry) => {
290 duplicates
291 .entry(directive_definition.name().as_ref())
292 .or_insert_with(|| vec![entry.get()])
293 .push(directive_definition);
294 }
295 }
296 });
297
298 errors.extend(duplicates.into_iter().map(|(name, definitions)| {
299 DefinitionDocumentError::DuplicateDirectiveDefinitions { name, definitions }
300 }));
301
302 indexed
303 }
304
305 fn index_type_definitions(
306 &'a self,
307 errors: &mut Vec<DefinitionDocumentError<'a, C>>,
308 ) -> BTreeMap<&str, &TypeDefinition<'a, C>> {
309 let mut indexed: BTreeMap<&str, &TypeDefinition<'a, C>> = BTreeMap::new();
310 let mut duplicates: BTreeMap<&str, Vec<&TypeDefinition<'a, C>>> = BTreeMap::new();
311
312 self.type_definitions
313 .iter()
314 .for_each(|td| match indexed.entry(td.name()) {
315 Entry::Vacant(entry) => {
316 entry.insert(td);
317 }
318 Entry::Occupied(entry) => {
319 duplicates
320 .entry(td.name())
321 .or_insert_with(|| vec![entry.get()])
322 .push(td);
323 }
324 });
325
326 errors.extend(duplicates.into_iter().map(|(name, definitions)| {
327 DefinitionDocumentError::DuplicateTypeDefinitions { name, definitions }
328 }));
329
330 indexed
331 }
332
333 fn implicit_schema_definition(
334 indexed_type_definitions: &BTreeMap<&str, &'a TypeDefinition<'a, C>>,
335 ) -> Result<Option<ImplicitSchemaDefinition<'a, C>>, Vec<DefinitionDocumentError<'a, C>>> {
336 let mut errors = Vec::new();
337 let query =
338 Self::implicit_root_operation_type("Query", indexed_type_definitions, &mut errors);
339 let mutation =
340 Self::implicit_root_operation_type("Mutation", indexed_type_definitions, &mut errors);
341 let subscription = Self::implicit_root_operation_type(
342 "Subscription",
343 indexed_type_definitions,
344 &mut errors,
345 );
346
347 if !errors.is_empty() {
348 return Err(errors);
349 }
350
351 if let Some(query) = query {
352 Ok(Some(ImplicitSchemaDefinition {
353 query,
354 mutation,
355 subscription,
356 }))
357 } else if mutation.is_some() || subscription.is_some() {
358 Err(vec![
359 DefinitionDocumentError::ImplicitSchemaDefinitionMissingQuery,
360 ])
361 } else {
362 Ok(None)
363 }
364 }
365
366 fn implicit_root_operation_type(
367 name: &str,
368 indexed_type_definitions: &BTreeMap<&str, &'a TypeDefinition<'a, C>>,
369 errors: &mut Vec<DefinitionDocumentError<'a, C>>,
370 ) -> Option<&'a ObjectTypeDefinition<'a, C>> {
371 match indexed_type_definitions.get(name) {
372 Some(TypeDefinition::Object(o)) => Some(o),
373 Some(definition) => {
374 errors.push(
375 DefinitionDocumentError::ImplicitRootOperationTypeNotAnObject { definition },
376 );
377 None
378 }
379 None => None,
380 }
381 }
382
383 fn explicit_schema_definition(
384 &'a self,
385 indexed_type_definitions: &BTreeMap<&str, &'a TypeDefinition<'a, C>>,
386 ) -> Result<
387 Option<ExplicitSchemaDefinitionWithRootTypes<'a, C>>,
388 Vec<DefinitionDocumentError<'a, C>>,
389 > {
390 let mut errors = Vec::new();
391 if let Some(first) = self.schema_definitions.first() {
392 if self.schema_definitions.len() == 1 {
393 let query = match Self::explicit_operation_type_definition(
394 OperationType::Query,
395 first,
396 indexed_type_definitions,
397 ) {
398 Ok(query) => query,
399 Err(err) => {
400 errors.push(err);
401 None
402 }
403 };
404 let mutation = match Self::explicit_operation_type_definition(
405 OperationType::Mutation,
406 first,
407 indexed_type_definitions,
408 ) {
409 Ok(mutation) => mutation,
410 Err(err) => {
411 errors.push(err);
412 None
413 }
414 };
415 let subscription = match Self::explicit_operation_type_definition(
416 OperationType::Subscription,
417 first,
418 indexed_type_definitions,
419 ) {
420 Ok(subscription) => subscription,
421 Err(err) => {
422 errors.push(err);
423 None
424 }
425 };
426 if !errors.is_empty() {
427 return Err(errors);
428 }
429 if let Some(query) = query {
430 Ok(Some((first, query, mutation, subscription)))
431 } else {
432 Err(vec![
433 DefinitionDocumentError::ExplicitSchemaDefinitionMissingQuery {
434 definition: first,
435 },
436 ])
437 }
438 } else {
439 Err(vec![
440 DefinitionDocumentError::DuplicateExplicitSchemaDefinitions {
441 definitions: &self.schema_definitions,
442 },
443 ])
444 }
445 } else {
446 Ok(None)
447 }
448 }
449
450 fn explicit_operation_type_definition(
451 operation_type: OperationType,
452 explicit_schema_definition: &'a ExplicitSchemaDefinition<'a, C>,
453 indexed_type_definitions: &BTreeMap<&str, &'a TypeDefinition<'a, C>>,
454 ) -> Result<Option<&'a ObjectTypeDefinition<'a, C>>, DefinitionDocumentError<'a, C>> {
455 let root_operation_type_definitions: Vec<_> = explicit_schema_definition
456 .root_operation_type_definitions()
457 .iter()
458 .filter(|rotd| rotd.operation_type() == operation_type)
459 .collect();
460
461 if let Some(first) = root_operation_type_definitions.first() {
462 if root_operation_type_definitions.len() == 1 {
463 match indexed_type_definitions.get(first.name()) {
464 Some(TypeDefinition::Object(o)) => Ok(Some(o)),
465 Some(_) => Err(
466 DefinitionDocumentError::ExplicitRootOperationTypeNotAnObject {
467 name: first.name_token(),
468 },
469 ),
470 None => Err(
471 DefinitionDocumentError::ExplicitRootOperationTypeDoesNotExist {
472 root_operation_type_definition: first,
473 },
474 ),
475 }
476 } else {
477 Err(
478 DefinitionDocumentError::DuplicateExplicitRootOperationDefinitions {
479 operation_type,
480 root_operation_type_definitions,
481 },
482 )
483 }
484 } else {
485 Ok(None)
486 }
487 }
488
489 fn resolve_type_and_directive_definitions(
490 indexed_type_definitions: &BTreeMap<&str, &'a TypeDefinition<'a, C>>,
491 indexed_directive_definitions: &BTreeMap<&str, &'a DirectiveDefinition<'a, C>>,
492 errors: &mut Vec<DefinitionDocumentError<'a, C>>,
493 ) {
494 indexed_type_definitions
495 .values()
496 .for_each(|type_definition| match type_definition {
497 TypeDefinition::Object(otd) => {
498 Self::resolve_fields_definition_types_and_directives(
499 indexed_type_definitions,
500 indexed_directive_definitions,
501 otd.fields_definition(),
502 errors,
503 );
504 if let Some(interface_implementations) = otd.interface_implementations() {
505 Self::resolve_interface_implementations(
506 indexed_type_definitions,
507 interface_implementations,
508 errors,
509 );
510 }
511 Self::resolve_directive_definitions(indexed_directive_definitions, otd, errors);
512 }
513 TypeDefinition::Interface(itd) => {
514 Self::resolve_fields_definition_types_and_directives(
515 indexed_type_definitions,
516 indexed_directive_definitions,
517 itd.fields_definition(),
518 errors,
519 );
520 if let Some(interface_implementations) = itd.interface_implementations() {
521 Self::resolve_interface_implementations(
522 indexed_type_definitions,
523 interface_implementations,
524 errors,
525 );
526 }
527 Self::resolve_directive_definitions(indexed_directive_definitions, itd, errors);
528 }
529 TypeDefinition::Union(utd) => {
530 Self::resolve_fields_definition_types_and_directives(
531 indexed_type_definitions,
532 indexed_directive_definitions,
533 utd.fields_definition(),
534 errors,
535 );
536 utd.union_member_types().iter().for_each(|member_type| {
537 match indexed_type_definitions.get(member_type.name().as_ref()) {
538 Some(TypeDefinition::Object(_)) => {}
539 Some(_) => errors.push(
540 DefinitionDocumentError::ReferencedUnionMemberTypeIsNotAnObject {
541 name: member_type.name(),
542 },
543 ),
544 None => {
545 errors.push(DefinitionDocumentError::ReferencedTypeDoesNotExist {
546 name: member_type.name(),
547 })
548 }
549 }
550 });
551 Self::resolve_directive_definitions(indexed_directive_definitions, utd, errors);
552 }
553 TypeDefinition::InputObject(iotd) => {
554 Self::resolve_input_types_and_directives(
555 indexed_type_definitions,
556 indexed_directive_definitions,
557 iotd.input_field_definitions().iter(),
558 errors,
559 );
560
561 Self::resolve_directive_definitions(
562 indexed_directive_definitions,
563 iotd,
564 errors,
565 );
566 }
567 TypeDefinition::CustomScalar(cstd) => {
568 Self::resolve_directive_definitions(indexed_directive_definitions, cstd, errors)
569 }
570 TypeDefinition::Enum(etd) => {
571 Self::resolve_directive_definitions(indexed_directive_definitions, etd, errors);
572 etd.enum_value_definitions().iter().for_each(|evd| {
573 Self::resolve_directive_definitions(
574 indexed_directive_definitions,
575 evd,
576 errors,
577 );
578 });
579 }
580 TypeDefinition::BuiltinScalar(_) => {}
581 });
582
583 indexed_directive_definitions
584 .values()
585 .for_each(|directive_definition| {
586 if let Some(arguments_definition) = directive_definition.arguments_definition() {
587 Self::resolve_input_types_and_directives(
588 indexed_type_definitions,
589 indexed_directive_definitions,
590 arguments_definition.iter(),
591 errors,
592 );
593 }
594 })
595 }
596
597 fn resolve_fields_definition_types_and_directives(
598 indexed_type_definitions: &BTreeMap<&str, &'a TypeDefinition<'a, C>>,
599 indexed_directive_definitions: &BTreeMap<&str, &'a DirectiveDefinition<'a, C>>,
600 fields_definition: &'a FieldsDefinition<'a, C>,
601 errors: &mut Vec<DefinitionDocumentError<'a, C>>,
602 ) {
603 fields_definition.iter().for_each(|field_definition| {
604 let t = field_definition.r#type().base();
605 match indexed_type_definitions.get(t.name().as_ref()) {
606 Some(&td) => match BaseOutputType::core_type_from_type_definition(td) {
607 Ok(_) => {}
608 Err(_) => {
609 errors.push(DefinitionDocumentError::ReferencedTypeIsNotAnOutputType {
610 name: t.name(),
611 })
612 }
613 },
614 None => errors
615 .push(DefinitionDocumentError::ReferencedTypeDoesNotExist { name: t.name() }),
616 }
617
618 if let Some(arguments_definition) = field_definition.arguments_definition() {
619 Self::resolve_input_types_and_directives(
620 indexed_type_definitions,
621 indexed_directive_definitions,
622 arguments_definition.iter(),
623 errors,
624 )
625 }
626
627 Self::resolve_directive_definitions(
628 indexed_directive_definitions,
629 field_definition,
630 errors,
631 );
632 })
633 }
634
635 fn resolve_interface_implementations(
636 indexed_type_definitions: &BTreeMap<&str, &'a TypeDefinition<'a, C>>,
637 interface_impelementations: &'a InterfaceImplementations<'a, C>,
638 errors: &mut Vec<DefinitionDocumentError<'a, C>>,
639 ) {
640 interface_impelementations
641 .iter()
642 .for_each(|interface_implementation| {
643 let name = interface_implementation.interface_name();
644 match indexed_type_definitions.get(name.as_ref()) {
645 Some(TypeDefinition::Interface(_)) => {}
646 Some(_) => errors
647 .push(DefinitionDocumentError::ReferencedTypeIsNotAnInterface { name }),
648 None => {
649 errors.push(DefinitionDocumentError::ReferencedTypeDoesNotExist { name })
650 }
651 }
652 })
653 }
654
655 fn resolve_input_types_and_directives(
656 indexed_type_definitions: &BTreeMap<&str, &'a TypeDefinition<'a, C>>,
657 indexed_directive_definitions: &BTreeMap<&str, &'a DirectiveDefinition<'a, C>>,
658 input_value_definitions: impl Iterator<Item = &'a InputValueDefinition<'a, C>>,
659 errors: &mut Vec<DefinitionDocumentError<'a, C>>,
660 ) {
661 input_value_definitions.for_each(|input_value_definition| {
662 let t = input_value_definition.r#type().base();
663 match indexed_type_definitions.get(t.name().as_ref()) {
664 Some(&td) => match BaseInputType::core_type_from_type_definition(td) {
665 Ok(_) => {}
666 Err(_) => {
667 errors.push(DefinitionDocumentError::ReferencedTypeIsNotAnInputType {
668 name: t.name(),
669 })
670 }
671 },
672 None => errors
673 .push(DefinitionDocumentError::ReferencedTypeDoesNotExist { name: t.name() }),
674 }
675
676 Self::resolve_directive_definitions(
677 indexed_directive_definitions,
678 input_value_definition,
679 errors,
680 );
681 })
682 }
683
684 fn resolve_directive_definitions(
685 indexed_directive_definitions: &BTreeMap<&str, &'a DirectiveDefinition<'a, C>>,
686 subject: &'a impl HasDirectives<Directives = Directives<'a, C>>,
687 errors: &mut Vec<DefinitionDocumentError<'a, C>>,
688 ) {
689 if let Some(directives) = subject.directives() {
690 directives.iter().for_each(|directive| {
691 match indexed_directive_definitions.get(directive.name()) {
692 Some(_) => {}
693 None => errors.push(DefinitionDocumentError::ReferencedDirectiveDoesNotExist {
694 directive,
695 }),
696 }
697 })
698 }
699 }
700}
701
702impl<'a, C: Context> TryFrom<&'a DefinitionDocument<'a, C>> for SchemaDefinition<'a, C> {
703 type Error = Vec<DefinitionDocumentError<'a, C>>;
704
705 fn try_from(definition_document: &'a DefinitionDocument<'a, C>) -> Result<Self, Self::Error> {
706 let mut errors = Vec::new();
707
708 let indexed_type_definitions = definition_document.index_type_definitions(&mut errors);
709
710 let indexed_directive_definitions =
711 definition_document.index_directive_definitions(&mut errors);
712
713 DefinitionDocument::resolve_type_and_directive_definitions(
714 &indexed_type_definitions,
715 &indexed_directive_definitions,
716 &mut errors,
717 );
718
719 if !errors.is_empty() {
720 return Err(errors);
721 }
722
723 if let Some((explicit, query, mutation, subscription)) =
724 definition_document.explicit_schema_definition(&indexed_type_definitions)?
725 {
726 return Ok(Self::new(
727 indexed_type_definitions,
728 indexed_directive_definitions,
729 explicit.description(),
730 query,
731 mutation,
732 subscription,
733 explicit.directives(),
734 ));
735 }
736
737 match DefinitionDocument::implicit_schema_definition(&indexed_type_definitions)? {
738 Some(implicit) => Ok(Self::new(
739 indexed_type_definitions,
740 indexed_directive_definitions,
741 None,
742 implicit.query,
743 implicit.mutation,
744 implicit.subscription,
745 None,
746 )),
747 None => Err(vec![DefinitionDocumentError::NoSchemaDefinition]),
748 }
749 }
750}
751
752#[cfg(test)]
753mod tests {
754 use std::collections::HashSet;
755
756 use bluejay_core::{
757 definition::{
758 FieldDefinition as CoreFieldDefinition,
759 ObjectTypeDefinition as CoreObjectTypeDefinition,
760 SchemaDefinition as CoreSchemaDefinition,
761 },
762 AsIter,
763 };
764
765 use super::{DefinitionDocument, Parse, SchemaDefinition};
766
767 #[test]
768 fn test_can_be_used_owned_with_self_cell() {
769 self_cell::self_cell!(
770 struct OwnedDefinitionDocument {
771 owner: String,
772
773 #[covariant]
774 dependent: DefinitionDocument,
775 }
776 );
777
778 self_cell::self_cell!(
779 struct OwnedSchemaDefinition {
780 owner: OwnedDefinitionDocument,
781
782 #[covariant]
783 dependent: SchemaDefinition,
784 }
785 );
786
787 let source = r#"
788 """
789 Description
790 """
791 type Query {
792 foo: String!
793 }
794 "#
795 .to_string();
796
797 let owned_definition_document = OwnedDefinitionDocument::new(source, |source| {
798 DefinitionDocument::parse(source).unwrap()
799 });
800
801 let owned_schema_definition =
802 OwnedSchemaDefinition::new(owned_definition_document, |owned_definition_document| {
803 SchemaDefinition::try_from(owned_definition_document.borrow_dependent()).unwrap()
804 });
805
806 let schema_definition = owned_schema_definition.borrow_dependent();
807
808 assert_eq!("Query", schema_definition.query().name().as_str());
809 }
810
811 #[test]
812 fn smoke_test() {
813 let s = r#"
814 """
815 Description
816 """
817 type Object {
818 foo: String!
819 }
820 "#;
821
822 let document: DefinitionDocument = DefinitionDocument::parse(s).unwrap();
823
824 assert_eq!(1, document.definition_count());
825 }
826
827 #[test]
828 fn builtin_fields_and_types_test() {
829 let s = r#"
830 directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
831
832 type Query {
833 foo: String!
834 }
835
836 type Mutation {
837 foo: String!
838 }
839 "#;
840
841 let document: DefinitionDocument =
842 DefinitionDocument::parse(s).expect("Document had parse errors");
843
844 let schema_definition = SchemaDefinition::try_from(&document)
845 .expect("Could not convert document to schema definition");
846
847 let query_root_builtin_fields: HashSet<&str> = schema_definition
848 .query()
849 .fields_definition()
850 .iter()
851 .filter_map(|fd| fd.is_builtin().then_some(fd.name()))
852 .collect();
853
854 assert_eq!(
855 HashSet::from(["__typename", "__schema", "__type"]),
856 query_root_builtin_fields,
857 );
858
859 let mutation_root = schema_definition
860 .mutation()
861 .expect("Schema definition did not have a mutation root");
862
863 let mutation_root_builtin_fields: HashSet<&str> = mutation_root
864 .fields_definition()
865 .iter()
866 .filter_map(|fd| fd.is_builtin().then_some(fd.name()))
867 .collect();
868
869 assert_eq!(HashSet::from(["__typename"]), mutation_root_builtin_fields);
870
871 let directives: HashSet<&str> = schema_definition
872 .directive_definitions()
873 .map(|dd| dd.name())
874 .collect();
875
876 assert!(
877 HashSet::from(["include", "skip", "deprecated", "specifiedBy", "oneOf"])
878 .is_subset(&directives)
879 );
880
881 let builtin_types: HashSet<&str> = schema_definition
882 .type_definitions()
883 .filter_map(|td| td.is_builtin().then_some(td.name()))
884 .collect();
885
886 assert_eq!(
887 HashSet::from([
888 "__TypeKind",
889 "__DirectiveLocation",
890 "__Schema",
891 "__Type",
892 "__Field",
893 "__InputValue",
894 "__EnumValue",
895 "__Directive",
896 "String",
897 "ID",
898 "Boolean",
899 "Int",
900 "Float",
901 ]),
902 builtin_types,
903 );
904 }
905}