1mod cache_control;
2mod export_sdl;
3mod stringify_exec_doc;
4
5use std::{
6 collections::{BTreeMap, BTreeSet, HashMap, HashSet},
7 fmt::{self, Display, Formatter, Write},
8 sync::Arc,
9};
10
11pub use cache_control::CacheControl;
12pub use export_sdl::SDLExportOptions;
13use indexmap::{map::IndexMap, set::IndexSet};
14
15pub use crate::model::{__DirectiveLocation, location_traits};
16use crate::{
17 Any, Context, ID, InputType, OutputType, Positioned, ServerResult, SubscriptionType, Value,
18 VisitorContext,
19 model::__Schema,
20 parser::types::{BaseType as ParsedBaseType, Field, Type as ParsedType, VariableDefinition},
21 schema::IntrospectionMode,
22};
23
24fn strip_brackets(type_name: &str) -> Option<&str> {
25 type_name
26 .strip_prefix('[')
27 .map(|rest| &rest[..rest.len() - 1])
28}
29
30#[derive(Clone, Copy, Eq, PartialEq, Debug)]
31pub enum MetaTypeName<'a> {
32 List(&'a str),
33 NonNull(&'a str),
34 Named(&'a str),
35}
36
37impl Display for MetaTypeName<'_> {
38 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
39 match self {
40 MetaTypeName::Named(name) => write!(f, "{}", name),
41 MetaTypeName::NonNull(name) => write!(f, "{}!", name),
42 MetaTypeName::List(name) => write!(f, "[{}]", name),
43 }
44 }
45}
46
47impl MetaTypeName<'_> {
48 #[inline]
49 pub fn create(type_name: &str) -> MetaTypeName {
50 if let Some(type_name) = type_name.strip_suffix('!') {
51 MetaTypeName::NonNull(type_name)
52 } else if let Some(type_name) = strip_brackets(type_name) {
53 MetaTypeName::List(type_name)
54 } else {
55 MetaTypeName::Named(type_name)
56 }
57 }
58
59 #[inline]
60 pub fn concrete_typename(type_name: &str) -> &str {
61 match MetaTypeName::create(type_name) {
62 MetaTypeName::List(type_name) => Self::concrete_typename(type_name),
63 MetaTypeName::NonNull(type_name) => Self::concrete_typename(type_name),
64 MetaTypeName::Named(type_name) => type_name,
65 }
66 }
67
68 #[inline]
69 pub fn is_non_null(&self) -> bool {
70 matches!(self, MetaTypeName::NonNull(_))
71 }
72
73 #[inline]
74 #[must_use]
75 pub fn unwrap_non_null(&self) -> Self {
76 match self {
77 MetaTypeName::NonNull(ty) => MetaTypeName::create(ty),
78 _ => *self,
79 }
80 }
81
82 #[inline]
83 pub fn is_subtype(&self, sub: &MetaTypeName<'_>) -> bool {
84 match (self, sub) {
85 (MetaTypeName::NonNull(super_type), MetaTypeName::NonNull(sub_type))
86 | (MetaTypeName::Named(super_type), MetaTypeName::NonNull(sub_type)) => {
87 MetaTypeName::create(super_type).is_subtype(&MetaTypeName::create(sub_type))
88 }
89 (MetaTypeName::Named(super_type), MetaTypeName::Named(sub_type)) => {
90 super_type == sub_type
91 }
92 (MetaTypeName::List(super_type), MetaTypeName::List(sub_type)) => {
93 MetaTypeName::create(super_type).is_subtype(&MetaTypeName::create(sub_type))
94 }
95 _ => false,
96 }
97 }
98
99 #[inline]
100 pub fn is_list(&self) -> bool {
101 match self {
102 MetaTypeName::List(_) => true,
103 MetaTypeName::NonNull(ty) => MetaTypeName::create(ty).is_list(),
104 MetaTypeName::Named(name) => name.ends_with(']'),
105 }
106 }
107}
108
109#[derive(Debug, Clone)]
111pub struct MetaDirectiveInvocation {
112 pub name: String,
114 pub args: IndexMap<String, Value>,
116}
117
118impl MetaDirectiveInvocation {
119 pub fn sdl(&self) -> String {
120 let formatted_args = if self.args.is_empty() {
121 String::new()
122 } else {
123 format!(
124 "({})",
125 self.args
126 .iter()
127 .map(|(name, value)| format!("{}: {}", name, value))
128 .collect::<Vec<_>>()
129 .join(", ")
130 )
131 };
132 format!("@{}{}", self.name, formatted_args)
133 }
134}
135
136#[derive(Clone)]
138pub struct MetaInputValue {
139 pub name: String,
141 pub description: Option<String>,
143 pub ty: String,
145 pub deprecation: Deprecation,
147 pub default_value: Option<String>,
149 pub visible: Option<MetaVisibleFn>,
152 pub inaccessible: bool,
155 pub tags: Vec<String>,
158 pub is_secret: bool,
160 pub directive_invocations: Vec<MetaDirectiveInvocation>,
162}
163
164type ComputeComplexityFn = fn(
165 &VisitorContext<'_>,
166 &[Positioned<VariableDefinition>],
167 &Field,
168 usize,
169) -> ServerResult<usize>;
170
171#[derive(Debug, Clone, Default)]
172pub enum Deprecation {
173 #[default]
174 NoDeprecated,
175 Deprecated {
176 reason: Option<String>,
177 },
178}
179
180impl Deprecation {
181 #[inline]
182 pub fn is_deprecated(&self) -> bool {
183 matches!(self, Deprecation::Deprecated { .. })
184 }
185
186 #[inline]
187 pub fn reason(&self) -> Option<&str> {
188 match self {
189 Deprecation::NoDeprecated => None,
190 Deprecation::Deprecated { reason } => reason.as_deref(),
191 }
192 }
193}
194
195#[derive(Clone)]
197pub struct MetaField {
198 pub name: String,
200 pub description: Option<String>,
202 pub args: IndexMap<String, MetaInputValue>,
204 pub ty: String,
206 pub deprecation: Deprecation,
208 pub cache_control: CacheControl,
210 pub external: bool,
214 pub requires: Option<String>,
219 pub provides: Option<String>,
222 pub visible: Option<MetaVisibleFn>,
225 pub shareable: bool,
228 pub inaccessible: bool,
231 pub tags: Vec<String>,
234 pub override_from: Option<String>,
237 pub compute_complexity: Option<ComputeComplexityFn>,
239 pub directive_invocations: Vec<MetaDirectiveInvocation>,
241 pub requires_scopes: Vec<String>,
245}
246
247#[derive(Clone)]
248pub struct MetaEnumValue {
249 pub name: String,
250 pub description: Option<String>,
251 pub deprecation: Deprecation,
252 pub visible: Option<MetaVisibleFn>,
253 pub inaccessible: bool,
254 pub tags: Vec<String>,
255 pub directive_invocations: Vec<MetaDirectiveInvocation>,
256}
257
258type MetaVisibleFn = fn(&Context<'_>) -> bool;
259
260#[derive(Debug, Copy, Clone, Eq, PartialEq)]
261pub enum MetaTypeId {
262 Scalar,
263 Object,
264 Interface,
265 Union,
266 Enum,
267 InputObject,
268}
269
270impl MetaTypeId {
271 fn create_fake_type(&self, rust_typename: &'static str) -> MetaType {
272 match self {
273 MetaTypeId::Scalar => MetaType::Scalar {
274 name: "".to_string(),
275 description: None,
276 is_valid: None,
277 visible: None,
278 inaccessible: false,
279 tags: vec![],
280 specified_by_url: None,
281 directive_invocations: vec![],
282 requires_scopes: vec![],
283 },
284 MetaTypeId::Object => MetaType::Object {
285 name: "".to_string(),
286 description: None,
287 fields: Default::default(),
288 cache_control: Default::default(),
289 extends: false,
290 shareable: false,
291 resolvable: true,
292 inaccessible: false,
293 interface_object: false,
294 tags: vec![],
295 keys: None,
296 visible: None,
297 is_subscription: false,
298 rust_typename: Some(rust_typename),
299 directive_invocations: vec![],
300 requires_scopes: vec![],
301 },
302 MetaTypeId::Interface => MetaType::Interface {
303 name: "".to_string(),
304 description: None,
305 fields: Default::default(),
306 possible_types: Default::default(),
307 extends: false,
308 inaccessible: false,
309 tags: vec![],
310 keys: None,
311 visible: None,
312 rust_typename: Some(rust_typename),
313 directive_invocations: vec![],
314 requires_scopes: vec![],
315 },
316 MetaTypeId::Union => MetaType::Union {
317 name: "".to_string(),
318 description: None,
319 possible_types: Default::default(),
320 visible: None,
321 inaccessible: false,
322 tags: vec![],
323 rust_typename: Some(rust_typename),
324 directive_invocations: vec![],
325 },
326 MetaTypeId::Enum => MetaType::Enum {
327 name: "".to_string(),
328 description: None,
329 enum_values: Default::default(),
330 visible: None,
331 inaccessible: false,
332 tags: vec![],
333 rust_typename: Some(rust_typename),
334 directive_invocations: vec![],
335 requires_scopes: vec![],
336 },
337 MetaTypeId::InputObject => MetaType::InputObject {
338 name: "".to_string(),
339 description: None,
340 input_fields: Default::default(),
341 visible: None,
342 inaccessible: false,
343 tags: vec![],
344 rust_typename: Some(rust_typename),
345 oneof: false,
346 directive_invocations: vec![],
347 },
348 }
349 }
350}
351
352impl Display for MetaTypeId {
353 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
354 f.write_str(match self {
355 MetaTypeId::Scalar => "Scalar",
356 MetaTypeId::Object => "Object",
357 MetaTypeId::Interface => "Interface",
358 MetaTypeId::Union => "Union",
359 MetaTypeId::Enum => "Enum",
360 MetaTypeId::InputObject => "InputObject",
361 })
362 }
363}
364
365pub type ScalarValidatorFn = Arc<dyn Fn(&Value) -> bool + Send + Sync>;
367
368#[derive(Clone)]
370pub enum MetaType {
371 Scalar {
375 name: String,
377 description: Option<String>,
379 is_valid: Option<ScalarValidatorFn>,
381 visible: Option<MetaVisibleFn>,
384 inaccessible: bool,
389 tags: Vec<String>,
394 specified_by_url: Option<String>,
398 directive_invocations: Vec<MetaDirectiveInvocation>,
400 requires_scopes: Vec<String>,
404 },
405 Object {
409 name: String,
411 description: Option<String>,
413 fields: IndexMap<String, MetaField>,
415 cache_control: CacheControl,
417 extends: bool,
422 shareable: bool,
428 resolvable: bool,
436 keys: Option<Vec<String>>,
444 visible: Option<MetaVisibleFn>,
447 inaccessible: bool,
452 interface_object: bool,
458 tags: Vec<String>,
463 is_subscription: bool,
465 rust_typename: Option<&'static str>,
467 directive_invocations: Vec<MetaDirectiveInvocation>,
469 requires_scopes: Vec<String>,
473 },
474 Interface {
478 name: String,
480 description: Option<String>,
482 fields: IndexMap<String, MetaField>,
484 possible_types: IndexSet<String>,
487 extends: bool,
492 keys: Option<Vec<String>>,
500 visible: Option<MetaVisibleFn>,
503 inaccessible: bool,
508 tags: Vec<String>,
513 rust_typename: Option<&'static str>,
515 directive_invocations: Vec<MetaDirectiveInvocation>,
517 requires_scopes: Vec<String>,
521 },
522 Union {
526 name: String,
528 description: Option<String>,
530 possible_types: IndexSet<String>,
532 visible: Option<MetaVisibleFn>,
535 inaccessible: bool,
540 tags: Vec<String>,
545 rust_typename: Option<&'static str>,
547 directive_invocations: Vec<MetaDirectiveInvocation>,
549 },
550 Enum {
554 name: String,
556 description: Option<String>,
558 enum_values: IndexMap<String, MetaEnumValue>,
560 visible: Option<MetaVisibleFn>,
563 inaccessible: bool,
568 tags: Vec<String>,
573 rust_typename: Option<&'static str>,
575 directive_invocations: Vec<MetaDirectiveInvocation>,
577 requires_scopes: Vec<String>,
581 },
582 InputObject {
586 name: String,
588 description: Option<String>,
590 input_fields: IndexMap<String, MetaInputValue>,
592 visible: Option<MetaVisibleFn>,
595 inaccessible: bool,
600 tags: Vec<String>,
605 rust_typename: Option<&'static str>,
607 oneof: bool,
611 directive_invocations: Vec<MetaDirectiveInvocation>,
613 },
614}
615
616impl MetaType {
617 #[inline]
618 pub fn type_id(&self) -> MetaTypeId {
619 match self {
620 MetaType::Scalar { .. } => MetaTypeId::Scalar,
621 MetaType::Object { .. } => MetaTypeId::Object,
622 MetaType::Interface { .. } => MetaTypeId::Interface,
623 MetaType::Union { .. } => MetaTypeId::Union,
624 MetaType::Enum { .. } => MetaTypeId::Enum,
625 MetaType::InputObject { .. } => MetaTypeId::InputObject,
626 }
627 }
628
629 #[inline]
630 pub fn field_by_name(&self, name: &str) -> Option<&MetaField> {
631 self.fields().and_then(|fields| fields.get(name))
632 }
633
634 #[inline]
635 pub fn fields(&self) -> Option<&IndexMap<String, MetaField>> {
636 match self {
637 MetaType::Object { fields, .. } => Some(&fields),
638 MetaType::Interface { fields, .. } => Some(&fields),
639 _ => None,
640 }
641 }
642
643 #[inline]
644 pub fn is_visible(&self, ctx: &Context<'_>) -> bool {
645 let visible = match self {
646 MetaType::Scalar { visible, .. } => visible,
647 MetaType::Object { visible, .. } => visible,
648 MetaType::Interface { visible, .. } => visible,
649 MetaType::Union { visible, .. } => visible,
650 MetaType::Enum { visible, .. } => visible,
651 MetaType::InputObject { visible, .. } => visible,
652 };
653 is_visible(ctx, visible)
654 }
655
656 #[inline]
657 pub fn name(&self) -> &str {
658 match self {
659 MetaType::Scalar { name, .. } => &name,
660 MetaType::Object { name, .. } => name,
661 MetaType::Interface { name, .. } => name,
662 MetaType::Union { name, .. } => name,
663 MetaType::Enum { name, .. } => name,
664 MetaType::InputObject { name, .. } => name,
665 }
666 }
667
668 #[inline]
669 pub fn is_composite(&self) -> bool {
670 matches!(
671 self,
672 MetaType::Object { .. } | MetaType::Interface { .. } | MetaType::Union { .. }
673 )
674 }
675
676 #[inline]
677 pub fn is_abstract(&self) -> bool {
678 matches!(self, MetaType::Interface { .. } | MetaType::Union { .. })
679 }
680
681 #[inline]
682 pub fn is_leaf(&self) -> bool {
683 matches!(self, MetaType::Enum { .. } | MetaType::Scalar { .. })
684 }
685
686 #[inline]
687 pub fn is_input(&self) -> bool {
688 matches!(
689 self,
690 MetaType::Enum { .. } | MetaType::Scalar { .. } | MetaType::InputObject { .. }
691 )
692 }
693
694 #[inline]
695 pub fn is_possible_type(&self, type_name: &str) -> bool {
696 match self {
697 MetaType::Interface { possible_types, .. } => possible_types.contains(type_name),
698 MetaType::Union { possible_types, .. } => possible_types.contains(type_name),
699 MetaType::Object { name, .. } => name == type_name,
700 _ => false,
701 }
702 }
703
704 #[inline]
705 pub fn possible_types(&self) -> Option<&IndexSet<String>> {
706 match self {
707 MetaType::Interface { possible_types, .. } => Some(possible_types),
708 MetaType::Union { possible_types, .. } => Some(possible_types),
709 _ => None,
710 }
711 }
712
713 pub fn type_overlap(&self, ty: &MetaType) -> bool {
714 if std::ptr::eq(self, ty) {
715 return true;
716 }
717
718 match (self.is_abstract(), ty.is_abstract()) {
719 (true, true) => self
720 .possible_types()
721 .iter()
722 .copied()
723 .flatten()
724 .any(|type_name| ty.is_possible_type(type_name)),
725 (true, false) => self.is_possible_type(ty.name()),
726 (false, true) => ty.is_possible_type(self.name()),
727 (false, false) => false,
728 }
729 }
730
731 pub fn rust_typename(&self) -> Option<&'static str> {
732 match self {
733 MetaType::Scalar { .. } => None,
734 MetaType::Object { rust_typename, .. } => *rust_typename,
735 MetaType::Interface { rust_typename, .. } => *rust_typename,
736 MetaType::Union { rust_typename, .. } => *rust_typename,
737 MetaType::Enum { rust_typename, .. } => *rust_typename,
738 MetaType::InputObject { rust_typename, .. } => *rust_typename,
739 }
740 }
741}
742
743pub struct MetaDirective {
744 pub name: String,
745 pub description: Option<String>,
746 pub locations: Vec<__DirectiveLocation>,
747 pub args: IndexMap<String, MetaInputValue>,
748 pub is_repeatable: bool,
749 pub visible: Option<MetaVisibleFn>,
750 pub composable: Option<String>,
751}
752
753impl MetaDirective {
754 pub(crate) fn sdl(&self, options: &SDLExportOptions) -> String {
755 let mut sdl = String::new();
756
757 if let Some(description) = &self.description {
758 self::export_sdl::write_description(&mut sdl, options, 0, description);
759 }
760
761 write!(sdl, "directive @{}", self.name).ok();
762
763 if !self.args.is_empty() {
764 let args = self
765 .args
766 .values()
767 .map(|value| self.argument_sdl(value))
768 .collect::<Vec<_>>()
769 .join(", ");
770 write!(sdl, "({})", args).ok();
771 }
772 let locations = self
773 .locations
774 .iter()
775 .map(|location| location.to_value().to_string())
776 .collect::<Vec<_>>()
777 .join(" | ");
778 write!(sdl, " on {}", locations).ok();
779 sdl
780 }
781
782 pub(crate) fn argument_sdl(&self, argument: &MetaInputValue) -> String {
783 let argument_default = match &argument.default_value {
784 Some(default) => format!(" = {default}"),
785 None => "".to_string(),
786 };
787
788 format!("{}: {}{}", argument.name, argument.ty, argument_default)
789 }
790}
791
792#[derive(Default)]
794pub struct Registry {
795 pub types: BTreeMap<String, MetaType>,
796 pub directives: BTreeMap<String, MetaDirective>,
797 pub implements: HashMap<String, IndexSet<String>>,
798 pub query_type: String,
799 pub mutation_type: Option<String>,
800 pub subscription_type: Option<String>,
801 pub introspection_mode: IntrospectionMode,
802 pub enable_federation: bool,
803 pub federation_subscription: bool,
804 pub ignore_name_conflicts: HashSet<String>,
805 pub enable_suggestions: bool,
806}
807
808impl Registry {
809 pub(crate) fn add_system_types(&mut self) {
810 self.add_directive(MetaDirective {
811 name: "skip".into(),
812 description: Some("Directs the executor to skip this field or fragment when the `if` argument is true.".to_string()),
813 locations: vec![
814 __DirectiveLocation::FIELD,
815 __DirectiveLocation::FRAGMENT_SPREAD,
816 __DirectiveLocation::INLINE_FRAGMENT
817 ],
818 args: {
819 let mut args = IndexMap::new();
820 args.insert("if".to_string(), MetaInputValue {
821 name: "if".to_string(),
822 description: Some("Skipped when true.".to_string()),
823 ty: "Boolean!".to_string(),
824 deprecation: Deprecation::NoDeprecated,
825 default_value: None,
826 visible: None,
827 inaccessible: false,
828 tags: Default::default(),
829 is_secret: false,
830 directive_invocations: vec![]
831 });
832 args
833 },
834 is_repeatable: false,
835 visible: None,
836 composable: None,
837 });
838
839 self.add_directive(MetaDirective {
840 name: "include".into(),
841 description: Some("Directs the executor to include this field or fragment only when the `if` argument is true.".to_string()),
842 locations: vec![
843 __DirectiveLocation::FIELD,
844 __DirectiveLocation::FRAGMENT_SPREAD,
845 __DirectiveLocation::INLINE_FRAGMENT
846 ],
847 args: {
848 let mut args = IndexMap::new();
849 args.insert("if".to_string(), MetaInputValue {
850 name: "if".to_string(),
851 description: Some("Included when true.".to_string()),
852 ty: "Boolean!".to_string(),
853 deprecation: Deprecation::NoDeprecated,
854 default_value: None,
855 visible: None,
856 inaccessible: false,
857 tags: Default::default(),
858 is_secret: false,
859 directive_invocations: vec![]
860 });
861 args
862 },
863 is_repeatable: false,
864 visible: None,
865 composable: None,
866 });
867
868 self.add_directive(MetaDirective {
869 name: "deprecated".into(),
870 description: Some(
871 "Marks an element of a GraphQL schema as no longer supported.".into(),
872 ),
873 locations: vec![
874 __DirectiveLocation::FIELD_DEFINITION,
875 __DirectiveLocation::ARGUMENT_DEFINITION,
876 __DirectiveLocation::INPUT_FIELD_DEFINITION,
877 __DirectiveLocation::ENUM_VALUE,
878 ],
879 args: {
880 let mut args = IndexMap::new();
881 args.insert(
882 "reason".into(),
883 MetaInputValue {
884 name: "reason".into(),
885 description: Some(
886 "A reason for why it is deprecated, formatted using Markdown syntax"
887 .into(),
888 ),
889 ty: "String".into(),
890 deprecation: Deprecation::NoDeprecated,
891 default_value: Some(r#""No longer supported""#.into()),
892 visible: None,
893 inaccessible: false,
894 tags: Default::default(),
895 is_secret: false,
896 directive_invocations: vec![],
897 },
898 );
899 args
900 },
901 is_repeatable: false,
902 visible: None,
903 composable: None,
904 });
905
906 self.add_directive(MetaDirective {
907 name: "specifiedBy".into(),
908 description: Some("Provides a scalar specification URL for specifying the behavior of custom scalar types.".into()),
909 locations: vec![__DirectiveLocation::SCALAR],
910 args: {
911 let mut args = IndexMap::new();
912 args.insert(
913 "url".into(),
914 MetaInputValue {
915 name: "url".into(),
916 description: Some("URL that specifies the behavior of this scalar.".into()),
917 ty: "String!".into(),
918 deprecation: Deprecation::NoDeprecated,
919 default_value: None,
920 visible: None,
921 inaccessible: false,
922 tags: Default::default(),
923 is_secret: false,
924 directive_invocations: vec![],
925 },
926 );
927 args
928 },
929 is_repeatable: false,
930 visible: None,
931 composable: None,
932 });
933
934 self.add_directive(MetaDirective {
935 name: "oneOf".into(),
936 description: Some(
937 "Indicates that an Input Object is a OneOf Input Object (and thus requires \
938 exactly one of its field be provided)"
939 .to_string(),
940 ),
941 locations: vec![__DirectiveLocation::INPUT_OBJECT],
942 args: Default::default(),
943 is_repeatable: false,
944 visible: None,
945 composable: None,
946 });
947
948 <bool as InputType>::create_type_info(self);
950 <i32 as InputType>::create_type_info(self);
951 <f32 as InputType>::create_type_info(self);
952 <String as InputType>::create_type_info(self);
953 <ID as InputType>::create_type_info(self);
954 }
955
956 pub fn create_input_type<T, F>(&mut self, type_id: MetaTypeId, mut f: F) -> String
957 where
958 T: InputType,
959 F: FnMut(&mut Registry) -> MetaType,
960 {
961 self.create_type(&mut f, &T::type_name(), std::any::type_name::<T>(), type_id);
962 T::qualified_type_name()
963 }
964
965 pub fn create_output_type<T, F>(&mut self, type_id: MetaTypeId, mut f: F) -> String
966 where
967 T: OutputType + ?Sized,
968 F: FnMut(&mut Registry) -> MetaType,
969 {
970 self.create_type(&mut f, &T::type_name(), std::any::type_name::<T>(), type_id);
971 T::qualified_type_name()
972 }
973
974 pub fn create_subscription_type<T, F>(&mut self, mut f: F) -> String
975 where
976 T: SubscriptionType + ?Sized,
977 F: FnMut(&mut Registry) -> MetaType,
978 {
979 self.create_type(
980 &mut f,
981 &T::type_name(),
982 std::any::type_name::<T>(),
983 MetaTypeId::Object,
984 );
985 T::qualified_type_name()
986 }
987
988 fn create_type<F: FnMut(&mut Registry) -> MetaType>(
989 &mut self,
990 f: &mut F,
991 name: &str,
992 rust_typename: &'static str,
993 type_id: MetaTypeId,
994 ) {
995 match self.types.get(name) {
996 Some(ty) => {
997 if let Some(prev_typename) = ty.rust_typename() {
998 if prev_typename == "__fake_type__" {
999 return;
1000 }
1001
1002 if rust_typename != prev_typename && !self.ignore_name_conflicts.contains(name)
1003 {
1004 panic!(
1005 "`{}` and `{}` have the same GraphQL name `{}`",
1006 prev_typename, rust_typename, name,
1007 );
1008 }
1009
1010 if ty.type_id() != type_id {
1011 panic!(
1012 "Register `{}` as `{}`, but it is already registered as `{}`",
1013 name,
1014 type_id,
1015 ty.type_id()
1016 );
1017 }
1018 }
1019 }
1020 None => {
1021 self.types
1024 .insert(name.to_string(), type_id.create_fake_type(rust_typename));
1025 let ty = f(self);
1026 *self.types.get_mut(name).unwrap() = ty;
1027 }
1028 }
1029 }
1030
1031 pub fn create_fake_output_type<T: OutputType>(&mut self) -> MetaType {
1032 T::create_type_info(self);
1033 self.types
1034 .get(&*T::type_name())
1035 .cloned()
1036 .expect("You definitely encountered a bug!")
1037 }
1038
1039 pub fn create_fake_input_type<T: InputType>(&mut self) -> MetaType {
1040 T::create_type_info(self);
1041 self.types
1042 .get(&*T::type_name())
1043 .cloned()
1044 .expect("You definitely encountered a bug!")
1045 }
1046
1047 pub fn create_fake_subscription_type<T: SubscriptionType>(&mut self) -> MetaType {
1048 T::create_type_info(self);
1049 self.types
1050 .get(&*T::type_name())
1051 .cloned()
1052 .expect("You definitely encountered a bug!")
1053 }
1054
1055 pub fn add_directive(&mut self, directive: MetaDirective) {
1056 self.directives
1057 .insert(directive.name.to_string(), directive);
1058 }
1059
1060 pub fn add_implements(&mut self, ty: &str, interface: &str) {
1061 self.implements
1062 .entry(ty.to_string())
1063 .and_modify(|interfaces| {
1064 interfaces.insert(interface.to_string());
1065 })
1066 .or_insert({
1067 let mut interfaces = IndexSet::new();
1068 interfaces.insert(interface.to_string());
1069 interfaces
1070 });
1071 }
1072
1073 pub fn add_keys(&mut self, ty: &str, keys: impl Into<String>) {
1074 let all_keys = match self.types.get_mut(ty) {
1075 Some(MetaType::Object { keys: all_keys, .. }) => all_keys,
1076 Some(MetaType::Interface { keys: all_keys, .. }) => all_keys,
1077 _ => return,
1078 };
1079 if let Some(all_keys) = all_keys {
1080 all_keys.push(keys.into());
1081 } else {
1082 *all_keys = Some(vec![keys.into()]);
1083 }
1084 }
1085
1086 pub fn concrete_type_by_name(&self, type_name: &str) -> Option<&MetaType> {
1087 self.types.get(MetaTypeName::concrete_typename(type_name))
1088 }
1089
1090 pub fn concrete_type_by_parsed_type(&self, query_type: &ParsedType) -> Option<&MetaType> {
1091 match &query_type.base {
1092 ParsedBaseType::Named(name) => self.types.get(name.as_str()),
1093 ParsedBaseType::List(ty) => self.concrete_type_by_parsed_type(ty),
1094 }
1095 }
1096
1097 pub(crate) fn has_entities(&self) -> bool {
1098 self.types.values().any(|ty| match ty {
1099 MetaType::Object {
1100 keys: Some(keys),
1101 resolvable: true,
1102 ..
1103 }
1104 | MetaType::Interface {
1105 keys: Some(keys), ..
1106 } => !keys.is_empty(),
1107 _ => false,
1108 })
1109 }
1110
1111 fn create_entity_type_and_root_field(&mut self) {
1117 let possible_types: IndexSet<String> = self
1118 .types
1119 .values()
1120 .filter_map(|ty| match ty {
1121 MetaType::Object {
1122 name,
1123 keys: Some(keys),
1124 resolvable: true,
1125 ..
1126 } if !keys.is_empty() => Some(name.clone()),
1127 MetaType::Interface {
1128 name,
1129 keys: Some(keys),
1130 ..
1131 } if !keys.is_empty() => Some(name.clone()),
1132 _ => None,
1133 })
1134 .collect();
1135
1136 if let MetaType::Object { fields, .. } = self
1137 .types
1138 .get_mut(&self.query_type)
1139 .expect("missing query type")
1140 {
1141 fields.insert(
1142 "_service".to_string(),
1143 MetaField {
1144 name: "_service".to_string(),
1145 description: None,
1146 args: Default::default(),
1147 ty: "_Service!".to_string(),
1148 deprecation: Default::default(),
1149 cache_control: Default::default(),
1150 external: false,
1151 requires: None,
1152 provides: None,
1153 shareable: false,
1154 inaccessible: false,
1155 tags: Default::default(),
1156 override_from: None,
1157 visible: None,
1158 compute_complexity: None,
1159 directive_invocations: vec![],
1160 requires_scopes: vec![],
1161 },
1162 );
1163 }
1164
1165 if !possible_types.is_empty() {
1166 self.types.insert(
1167 "_Entity".to_string(),
1168 MetaType::Union {
1169 name: "_Entity".to_string(),
1170 description: None,
1171 possible_types,
1172 visible: None,
1173 inaccessible: false,
1174 tags: Default::default(),
1175 rust_typename: Some("async_graphql::federation::Entity"),
1176 directive_invocations: vec![],
1177 },
1178 );
1179
1180 if let MetaType::Object { fields, .. } = self.types.get_mut(&self.query_type).unwrap() {
1181 fields.insert(
1182 "_entities".to_string(),
1183 MetaField {
1184 name: "_entities".to_string(),
1185 description: None,
1186 args: {
1187 let mut args = IndexMap::new();
1188 args.insert(
1189 "representations".to_string(),
1190 MetaInputValue {
1191 name: "representations".to_string(),
1192 description: None,
1193 ty: "[_Any!]!".to_string(),
1194 deprecation: Deprecation::NoDeprecated,
1195 default_value: None,
1196 visible: None,
1197 inaccessible: false,
1198 tags: Default::default(),
1199 is_secret: false,
1200 directive_invocations: vec![],
1201 },
1202 );
1203 args
1204 },
1205 ty: "[_Entity]!".to_string(),
1206 deprecation: Default::default(),
1207 cache_control: Default::default(),
1208 external: false,
1209 requires: None,
1210 provides: None,
1211 shareable: false,
1212 visible: None,
1213 inaccessible: false,
1214 tags: Default::default(),
1215 override_from: None,
1216 compute_complexity: None,
1217 directive_invocations: vec![],
1218 requires_scopes: vec![],
1219 },
1220 );
1221 }
1222 }
1223 }
1224
1225 pub(crate) fn create_introspection_types(&mut self) {
1226 __Schema::create_type_info(self);
1227
1228 if let Some(MetaType::Object { fields, .. }) = self.types.get_mut(&self.query_type) {
1229 fields.insert(
1230 "__schema".to_string(),
1231 MetaField {
1232 name: "__schema".to_string(),
1233 description: Some("Access the current type schema of this server.".to_string()),
1234 args: Default::default(),
1235 ty: "__Schema".to_string(),
1236 deprecation: Default::default(),
1237 cache_control: Default::default(),
1238 external: false,
1239 requires: None,
1240 provides: None,
1241 shareable: false,
1242 inaccessible: false,
1243 tags: Default::default(),
1244 visible: None,
1245 compute_complexity: None,
1246 override_from: None,
1247 directive_invocations: vec![],
1248 requires_scopes: vec![],
1249 },
1250 );
1251
1252 fields.insert(
1253 "__type".to_string(),
1254 MetaField {
1255 name: "__type".to_string(),
1256 description: Some("Request the type information of a single type.".to_string()),
1257 args: {
1258 let mut args = IndexMap::new();
1259 args.insert(
1260 "name".to_string(),
1261 MetaInputValue {
1262 name: "name".to_string(),
1263 description: None,
1264 ty: "String!".to_string(),
1265 deprecation: Deprecation::NoDeprecated,
1266 default_value: None,
1267 visible: None,
1268 inaccessible: false,
1269 tags: Default::default(),
1270 is_secret: false,
1271 directive_invocations: vec![],
1272 },
1273 );
1274 args
1275 },
1276 ty: "__Type".to_string(),
1277 deprecation: Default::default(),
1278 cache_control: Default::default(),
1279 external: false,
1280 requires: None,
1281 provides: None,
1282 shareable: false,
1283 inaccessible: false,
1284 tags: Default::default(),
1285 override_from: None,
1286 visible: None,
1287 compute_complexity: None,
1288 directive_invocations: vec![],
1289 requires_scopes: vec![],
1290 },
1291 );
1292 }
1293 }
1294
1295 pub(crate) fn create_federation_types(&mut self) {
1296 <Any as InputType>::create_type_info(self);
1297
1298 self.types.insert(
1299 "_Service".to_string(),
1300 MetaType::Object {
1301 name: "_Service".to_string(),
1302 description: None,
1303 fields: {
1304 let mut fields = IndexMap::new();
1305 fields.insert(
1306 "sdl".to_string(),
1307 MetaField {
1308 name: "sdl".to_string(),
1309 description: None,
1310 args: Default::default(),
1311 ty: "String".to_string(),
1312 deprecation: Default::default(),
1313 cache_control: Default::default(),
1314 external: false,
1315 requires: None,
1316 provides: None,
1317 shareable: false,
1318 visible: None,
1319 inaccessible: false,
1320 tags: Default::default(),
1321 override_from: None,
1322 compute_complexity: None,
1323 directive_invocations: vec![],
1324 requires_scopes: vec![],
1325 },
1326 );
1327 fields
1328 },
1329 cache_control: Default::default(),
1330 extends: false,
1331 shareable: false,
1332 resolvable: true,
1333 interface_object: false,
1334 keys: None,
1335 visible: None,
1336 inaccessible: false,
1337 tags: Default::default(),
1338 is_subscription: false,
1339 rust_typename: Some("async_graphql::federation::Service"),
1340 directive_invocations: vec![],
1341 requires_scopes: vec![],
1342 },
1343 );
1344
1345 self.create_entity_type_and_root_field();
1346 }
1347
1348 pub fn names(&self) -> Vec<String> {
1349 let mut names = HashSet::new();
1350
1351 for d in self.directives.values() {
1352 names.insert(d.name.to_string());
1353 names.extend(d.args.values().map(|arg| arg.name.to_string()));
1354 }
1355
1356 for ty in self.types.values() {
1357 match ty {
1358 MetaType::Scalar { name, .. } | MetaType::Union { name, .. } => {
1359 names.insert(name.clone());
1360 }
1361 MetaType::Object { name, fields, .. }
1362 | MetaType::Interface { name, fields, .. } => {
1363 names.insert(name.clone());
1364 names.extend(
1365 fields
1366 .values()
1367 .map(|field| {
1368 std::iter::once(field.name.clone())
1369 .chain(field.args.values().map(|arg| arg.name.to_string()))
1370 })
1371 .flatten(),
1372 );
1373 }
1374 MetaType::Enum {
1375 name, enum_values, ..
1376 } => {
1377 names.insert(name.clone());
1378 names.extend(enum_values.values().map(|value| value.name.to_string()));
1379 }
1380 MetaType::InputObject {
1381 name, input_fields, ..
1382 } => {
1383 names.insert(name.clone());
1384 names.extend(input_fields.values().map(|field| field.name.to_string()));
1385 }
1386 }
1387 }
1388
1389 names.into_iter().collect()
1390 }
1391
1392 pub fn set_description(&mut self, name: impl AsRef<str>, desc: impl Into<String>) {
1393 let desc = desc.into();
1394 match self.types.get_mut(name.as_ref()) {
1395 Some(MetaType::Scalar { description, .. }) => *description = Some(desc),
1396 Some(MetaType::Object { description, .. }) => *description = Some(desc),
1397 Some(MetaType::Interface { description, .. }) => *description = Some(desc),
1398 Some(MetaType::Union { description, .. }) => *description = Some(desc),
1399 Some(MetaType::Enum { description, .. }) => *description = Some(desc),
1400 Some(MetaType::InputObject { description, .. }) => *description = Some(desc),
1401 None => {}
1402 }
1403 }
1404
1405 pub fn remove_unused_types(&mut self) {
1406 let mut used_types = BTreeSet::new();
1407 let mut unused_types = BTreeSet::new();
1408
1409 fn traverse_field<'a>(
1410 types: &'a BTreeMap<String, MetaType>,
1411 used_types: &mut BTreeSet<&'a str>,
1412 field: &'a MetaField,
1413 ) {
1414 traverse_type(
1415 types,
1416 used_types,
1417 MetaTypeName::concrete_typename(&field.ty),
1418 );
1419 for arg in field.args.values() {
1420 traverse_input_value(types, used_types, arg);
1421 }
1422 }
1423
1424 fn traverse_input_value<'a>(
1425 types: &'a BTreeMap<String, MetaType>,
1426 used_types: &mut BTreeSet<&'a str>,
1427 input_value: &'a MetaInputValue,
1428 ) {
1429 traverse_type(
1430 types,
1431 used_types,
1432 MetaTypeName::concrete_typename(&input_value.ty),
1433 );
1434 }
1435
1436 fn traverse_type<'a>(
1437 types: &'a BTreeMap<String, MetaType>,
1438 used_types: &mut BTreeSet<&'a str>,
1439 type_name: &'a str,
1440 ) {
1441 if used_types.contains(type_name) {
1442 return;
1443 }
1444
1445 if let Some(ty) = types.get(type_name) {
1446 used_types.insert(type_name);
1447 match ty {
1448 MetaType::Object { fields, .. } => {
1449 for field in fields.values() {
1450 traverse_field(types, used_types, field);
1451 }
1452 }
1453 MetaType::Interface {
1454 fields,
1455 possible_types,
1456 ..
1457 } => {
1458 for field in fields.values() {
1459 traverse_field(types, used_types, field);
1460 }
1461 for type_name in possible_types.iter() {
1462 traverse_type(types, used_types, type_name);
1463 }
1464 }
1465 MetaType::Union { possible_types, .. } => {
1466 for type_name in possible_types.iter() {
1467 traverse_type(types, used_types, type_name);
1468 }
1469 }
1470 MetaType::InputObject { input_fields, .. } => {
1471 for field in input_fields.values() {
1472 traverse_input_value(types, used_types, field);
1473 }
1474 }
1475 _ => {}
1476 }
1477 }
1478 }
1479
1480 for directive in self.directives.values() {
1481 for arg in directive.args.values() {
1482 traverse_input_value(&self.types, &mut used_types, arg);
1483 }
1484 }
1485
1486 for type_name in Some(&self.query_type)
1487 .into_iter()
1488 .chain(self.mutation_type.iter())
1489 .chain(self.subscription_type.iter())
1490 {
1491 traverse_type(&self.types, &mut used_types, type_name);
1492 }
1493
1494 for ty in self.types.values().filter(|ty| match ty {
1495 MetaType::Object {
1496 keys: Some(keys), ..
1497 }
1498 | MetaType::Interface {
1499 keys: Some(keys), ..
1500 } => !keys.is_empty(),
1501 _ => false,
1502 }) {
1503 traverse_type(&self.types, &mut used_types, ty.name());
1504 }
1505
1506 for ty in self.types.values() {
1507 let name = ty.name();
1508 if !is_system_type(name) && !used_types.contains(name) {
1509 unused_types.insert(name.to_string());
1510 }
1511 }
1512
1513 for type_name in unused_types {
1514 self.types.remove(&type_name);
1515 }
1516 }
1517
1518 pub fn find_visible_types(&self, ctx: &Context<'_>) -> HashSet<&str> {
1519 let mut visible_types = HashSet::new();
1520
1521 fn traverse_field<'a>(
1522 ctx: &Context<'_>,
1523 types: &'a BTreeMap<String, MetaType>,
1524 visible_types: &mut HashSet<&'a str>,
1525 field: &'a MetaField,
1526 ) {
1527 if !is_visible(ctx, &field.visible) {
1528 return;
1529 }
1530
1531 traverse_type(
1532 ctx,
1533 types,
1534 visible_types,
1535 MetaTypeName::concrete_typename(&field.ty),
1536 );
1537 for arg in field.args.values() {
1538 traverse_input_value(ctx, types, visible_types, arg);
1539 }
1540 }
1541
1542 fn traverse_input_value<'a>(
1543 ctx: &Context<'_>,
1544 types: &'a BTreeMap<String, MetaType>,
1545 visible_types: &mut HashSet<&'a str>,
1546 input_value: &'a MetaInputValue,
1547 ) {
1548 if !is_visible(ctx, &input_value.visible) {
1549 return;
1550 }
1551
1552 traverse_type(
1553 ctx,
1554 types,
1555 visible_types,
1556 MetaTypeName::concrete_typename(&input_value.ty),
1557 );
1558 }
1559
1560 fn traverse_type<'a>(
1561 ctx: &Context<'_>,
1562 types: &'a BTreeMap<String, MetaType>,
1563 visible_types: &mut HashSet<&'a str>,
1564 type_name: &'a str,
1565 ) {
1566 if visible_types.contains(type_name) {
1567 return;
1568 }
1569
1570 if let Some(ty) = types.get(type_name) {
1571 if !ty.is_visible(ctx) {
1572 return;
1573 }
1574
1575 visible_types.insert(type_name);
1576 match ty {
1577 MetaType::Object { fields, .. } => {
1578 for field in fields.values() {
1579 traverse_field(ctx, types, visible_types, field);
1580 }
1581 }
1582 MetaType::Interface {
1583 fields,
1584 possible_types,
1585 ..
1586 } => {
1587 for field in fields.values() {
1588 traverse_field(ctx, types, visible_types, field);
1589 }
1590 for type_name in possible_types.iter() {
1591 traverse_type(ctx, types, visible_types, type_name);
1592 }
1593 }
1594 MetaType::Union { possible_types, .. } => {
1595 for type_name in possible_types.iter() {
1596 traverse_type(ctx, types, visible_types, type_name);
1597 }
1598 }
1599 MetaType::InputObject { input_fields, .. } => {
1600 for field in input_fields.values() {
1601 traverse_input_value(ctx, types, visible_types, field);
1602 }
1603 }
1604 _ => {}
1605 }
1606 }
1607 }
1608
1609 for directive in self.directives.values() {
1610 if is_visible(ctx, &directive.visible) {
1611 for arg in directive.args.values() {
1612 traverse_input_value(ctx, &self.types, &mut visible_types, arg);
1613 }
1614 }
1615 }
1616
1617 for type_name in Some(&self.query_type)
1618 .into_iter()
1619 .chain(self.mutation_type.iter())
1620 .chain(self.subscription_type.iter())
1621 {
1622 traverse_type(ctx, &self.types, &mut visible_types, type_name);
1623 }
1624
1625 for ty in self.types.values().filter(|ty| match ty {
1626 MetaType::Object {
1627 keys: Some(keys), ..
1628 }
1629 | MetaType::Interface {
1630 keys: Some(keys), ..
1631 } => !keys.is_empty(),
1632 _ => false,
1633 }) {
1634 traverse_type(ctx, &self.types, &mut visible_types, ty.name());
1635 }
1636
1637 for ty in self.types.values() {
1638 if let MetaType::Interface { possible_types, .. } = ty {
1639 if ty.is_visible(ctx) && !visible_types.contains(ty.name()) {
1640 for type_name in possible_types.iter() {
1641 if visible_types.contains(type_name.as_str()) {
1642 traverse_type(ctx, &self.types, &mut visible_types, ty.name());
1643 break;
1644 }
1645 }
1646 }
1647 }
1648 }
1649
1650 self.types
1651 .values()
1652 .filter_map(|ty| {
1653 let name = ty.name();
1654 if is_system_type(name) || visible_types.contains(name) {
1655 Some(name)
1656 } else {
1657 None
1658 }
1659 })
1660 .collect()
1661 }
1662}
1663
1664pub(crate) fn is_visible(ctx: &Context<'_>, visible: &Option<MetaVisibleFn>) -> bool {
1665 match visible {
1666 Some(f) => f(ctx),
1667 None => true,
1668 }
1669}
1670
1671fn is_system_type(name: &str) -> bool {
1672 if name.starts_with("__") {
1673 return true;
1674 }
1675
1676 name == "Boolean" || name == "Int" || name == "Float" || name == "String" || name == "ID"
1677}
1678
1679#[cfg(test)]
1680mod test {
1681 use crate::registry::MetaDirectiveInvocation;
1682
1683 #[test]
1684 fn test_directive_invocation_dsl() {
1685 let expected = r#"@testDirective(int_value: 1, str_value: "abc")"#;
1686 assert_eq!(
1687 expected.to_string(),
1688 MetaDirectiveInvocation {
1689 name: "testDirective".to_string(),
1690 args: [
1691 ("int_value".to_string(), 1u32.into()),
1692 ("str_value".to_string(), "abc".into())
1693 ]
1694 .into(),
1695 }
1696 .sdl()
1697 )
1698 }
1699}