async_graphql/model/
type.rs

1use std::collections::HashSet;
2
3use crate::{
4    model::{__EnumValue, __Field, __InputValue, __TypeKind},
5    registry,
6    registry::is_visible,
7    Context, Object,
8};
9
10enum TypeDetail<'a> {
11    Named(&'a registry::MetaType),
12    NonNull(String),
13    List(String),
14}
15
16pub struct __Type<'a> {
17    registry: &'a registry::Registry,
18    visible_types: &'a HashSet<&'a str>,
19    detail: TypeDetail<'a>,
20}
21
22impl<'a> __Type<'a> {
23    #[inline]
24    pub fn new_simple(
25        registry: &'a registry::Registry,
26        visible_types: &'a HashSet<&'a str>,
27        ty: &'a registry::MetaType,
28    ) -> __Type<'a> {
29        __Type {
30            registry,
31            visible_types,
32            detail: TypeDetail::Named(ty),
33        }
34    }
35
36    #[inline]
37    pub fn new(
38        registry: &'a registry::Registry,
39        visible_types: &'a HashSet<&'a str>,
40        type_name: &str,
41    ) -> __Type<'a> {
42        match registry::MetaTypeName::create(type_name) {
43            registry::MetaTypeName::NonNull(ty) => __Type {
44                registry,
45                visible_types,
46                detail: TypeDetail::NonNull(ty.to_string()),
47            },
48            registry::MetaTypeName::List(ty) => __Type {
49                registry,
50                visible_types,
51                detail: TypeDetail::List(ty.to_string()),
52            },
53            registry::MetaTypeName::Named(ty) => __Type {
54                registry,
55                visible_types,
56                detail: TypeDetail::Named(match registry.types.get(ty) {
57                    Some(t) => t,
58                    None => panic!("Type '{}' not found!", ty),
59                }),
60            },
61        }
62    }
63}
64
65/// The fundamental unit of any GraphQL Schema is the type. There are many kinds
66/// of types in GraphQL as represented by the `__TypeKind` enum.
67///
68/// Depending on the kind of a type, certain fields describe information about
69/// that type. Scalar types provide no information beyond a name and
70/// description, while Enum types provide their values. Object and Interface
71/// types provide the fields they describe. Abstract types, Union and Interface,
72/// provide the Object types possible at runtime. List and NonNull types compose
73/// other types.
74#[Object(internal, name = "__Type")]
75impl<'a> __Type<'a> {
76    #[inline]
77    async fn kind(&self) -> __TypeKind {
78        match &self.detail {
79            TypeDetail::Named(ty) => match ty {
80                registry::MetaType::Scalar { .. } => __TypeKind::Scalar,
81                registry::MetaType::Object { .. } => __TypeKind::Object,
82                registry::MetaType::Interface { .. } => __TypeKind::Interface,
83                registry::MetaType::Union { .. } => __TypeKind::Union,
84                registry::MetaType::Enum { .. } => __TypeKind::Enum,
85                registry::MetaType::InputObject { .. } => __TypeKind::InputObject,
86            },
87            TypeDetail::NonNull(_) => __TypeKind::NonNull,
88            TypeDetail::List(_) => __TypeKind::List,
89        }
90    }
91
92    #[inline]
93    async fn name(&self) -> Option<&str> {
94        match &self.detail {
95            TypeDetail::Named(ty) => Some(ty.name()),
96            TypeDetail::NonNull(_) => None,
97            TypeDetail::List(_) => None,
98        }
99    }
100
101    #[inline]
102    async fn description(&self) -> Option<&str> {
103        match &self.detail {
104            TypeDetail::Named(ty) => match ty {
105                registry::MetaType::Scalar { description, .. }
106                | registry::MetaType::Object { description, .. }
107                | registry::MetaType::Interface { description, .. }
108                | registry::MetaType::Union { description, .. }
109                | registry::MetaType::Enum { description, .. }
110                | registry::MetaType::InputObject { description, .. } => description.as_deref(),
111            },
112            TypeDetail::NonNull(_) => None,
113            TypeDetail::List(_) => None,
114        }
115    }
116
117    async fn fields(
118        &self,
119        ctx: &Context<'_>,
120        #[graphql(default = false)] include_deprecated: bool,
121    ) -> Option<Vec<__Field<'a>>> {
122        if let TypeDetail::Named(ty) = &self.detail {
123            ty.fields().map(|fields| {
124                fields
125                    .values()
126                    .filter(|field| is_visible(ctx, &field.visible))
127                    .filter(|field| {
128                        (include_deprecated || !field.deprecation.is_deprecated())
129                            && !field.name.starts_with("__")
130                    })
131                    .map(|field| __Field {
132                        registry: self.registry,
133                        visible_types: self.visible_types,
134                        field,
135                    })
136                    .collect()
137            })
138        } else {
139            None
140        }
141    }
142
143    async fn interfaces(&self) -> Option<Vec<__Type<'a>>> {
144        if let TypeDetail::Named(registry::MetaType::Object { name, .. }) = &self.detail {
145            Some(
146                self.registry
147                    .implements
148                    .get(name)
149                    .unwrap_or(&Default::default())
150                    .iter()
151                    .filter(|ty| self.visible_types.contains(ty.as_str()))
152                    .map(|ty| __Type::new(self.registry, self.visible_types, ty))
153                    .collect(),
154            )
155        } else {
156            None
157        }
158    }
159
160    async fn possible_types(&self) -> Option<Vec<__Type<'a>>> {
161        if let TypeDetail::Named(registry::MetaType::Interface { possible_types, .. })
162        | TypeDetail::Named(registry::MetaType::Union { possible_types, .. }) = &self.detail
163        {
164            Some(
165                possible_types
166                    .iter()
167                    .filter(|ty| self.visible_types.contains(ty.as_str()))
168                    .map(|ty| __Type::new(self.registry, self.visible_types, ty))
169                    .collect(),
170            )
171        } else {
172            None
173        }
174    }
175
176    async fn enum_values(
177        &self,
178        ctx: &Context<'_>,
179        #[graphql(default = false)] include_deprecated: bool,
180    ) -> Option<Vec<__EnumValue<'a>>> {
181        if let TypeDetail::Named(registry::MetaType::Enum { enum_values, .. }) = &self.detail {
182            Some(
183                enum_values
184                    .values()
185                    .filter(|value| is_visible(ctx, &value.visible))
186                    .filter(|value| include_deprecated || !value.deprecation.is_deprecated())
187                    .map(|value| __EnumValue { value })
188                    .collect(),
189            )
190        } else {
191            None
192        }
193    }
194
195    async fn input_fields(
196        &self,
197        ctx: &Context<'_>,
198        #[graphql(default = false)] include_deprecated: bool,
199    ) -> Option<Vec<__InputValue<'a>>> {
200        if let TypeDetail::Named(registry::MetaType::InputObject { input_fields, .. }) =
201            &self.detail
202        {
203            Some(
204                input_fields
205                    .values()
206                    .filter(|input_value| {
207                        include_deprecated || !input_value.deprecation.is_deprecated()
208                    })
209                    .filter(|input_value| is_visible(ctx, &input_value.visible))
210                    .map(|input_value| __InputValue {
211                        registry: self.registry,
212                        visible_types: self.visible_types,
213                        input_value,
214                    })
215                    .collect(),
216            )
217        } else {
218            None
219        }
220    }
221
222    #[inline]
223    async fn of_type(&self) -> Option<__Type<'a>> {
224        if let TypeDetail::List(ty) = &self.detail {
225            Some(__Type::new(self.registry, self.visible_types, &ty))
226        } else if let TypeDetail::NonNull(ty) = &self.detail {
227            Some(__Type::new(self.registry, self.visible_types, &ty))
228        } else {
229            None
230        }
231    }
232
233    #[graphql(name = "specifiedByURL")]
234    async fn specified_by_url(&self) -> Option<&'a str> {
235        if let TypeDetail::Named(registry::MetaType::Scalar {
236            specified_by_url, ..
237        }) = &self.detail
238        {
239            specified_by_url.as_deref()
240        } else {
241            None
242        }
243    }
244
245    async fn is_one_of(&self) -> Option<bool> {
246        if let TypeDetail::Named(registry::MetaType::InputObject { oneof, .. }) = &self.detail {
247            Some(*oneof)
248        } else {
249            None
250        }
251    }
252}