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#[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}