async_graphql/dynamic/
enum.rs1use indexmap::IndexMap;
2
3use super::{directive::to_meta_directive_invocation, Directive};
4use crate::{
5 dynamic::SchemaError,
6 registry::{Deprecation, MetaEnumValue, MetaType, Registry},
7};
8
9#[derive(Debug)]
11pub struct EnumItem {
12 pub(crate) name: String,
13 pub(crate) description: Option<String>,
14 pub(crate) deprecation: Deprecation,
15 inaccessible: bool,
16 tags: Vec<String>,
17 pub(crate) directives: Vec<Directive>,
18}
19
20impl<T: Into<String>> From<T> for EnumItem {
21 #[inline]
22 fn from(name: T) -> Self {
23 EnumItem {
24 name: name.into(),
25 description: None,
26 deprecation: Deprecation::NoDeprecated,
27 inaccessible: false,
28 tags: Vec::new(),
29 directives: Vec::new(),
30 }
31 }
32}
33
34impl EnumItem {
35 #[inline]
37 pub fn new(name: impl Into<String>) -> Self {
38 name.into().into()
39 }
40
41 impl_set_description!();
42 impl_set_deprecation!();
43 impl_set_inaccessible!();
44 impl_set_tags!();
45 impl_directive!();
46}
47
48#[derive(Debug)]
50pub struct Enum {
51 pub(crate) name: String,
52 pub(crate) description: Option<String>,
53 pub(crate) enum_values: IndexMap<String, EnumItem>,
54 inaccessible: bool,
55 tags: Vec<String>,
56 pub(crate) directives: Vec<Directive>,
57}
58
59impl Enum {
60 #[inline]
62 pub fn new(name: impl Into<String>) -> Self {
63 Self {
64 name: name.into(),
65 description: None,
66 enum_values: Default::default(),
67 inaccessible: false,
68 tags: Vec::new(),
69 directives: Vec::new(),
70 }
71 }
72
73 impl_set_description!();
74 impl_directive!();
75
76 #[inline]
78 pub fn item(mut self, item: impl Into<EnumItem>) -> Self {
79 let item = item.into();
80 self.enum_values.insert(item.name.clone(), item);
81 self
82 }
83
84 pub fn items(mut self, items: impl IntoIterator<Item = impl Into<EnumItem>>) -> Self {
86 for item in items {
87 let item = item.into();
88 self.enum_values.insert(item.name.clone(), item);
89 }
90 self
91 }
92
93 impl_set_inaccessible!();
94 impl_set_tags!();
95
96 #[inline]
98 pub fn type_name(&self) -> &str {
99 &self.name
100 }
101
102 pub(crate) fn register(&self, registry: &mut Registry) -> Result<(), SchemaError> {
103 let mut enum_values = IndexMap::new();
104
105 for item in self.enum_values.values() {
106 enum_values.insert(
107 item.name.clone(),
108 MetaEnumValue {
109 name: item.name.as_str().into(),
110 description: item.description.clone(),
111 deprecation: item.deprecation.clone(),
112 visible: None,
113 inaccessible: item.inaccessible,
114 tags: item.tags.clone(),
115 directive_invocations: to_meta_directive_invocation(item.directives.clone()),
116 },
117 );
118 }
119
120 registry.types.insert(
121 self.name.clone(),
122 MetaType::Enum {
123 name: self.name.clone(),
124 description: self.description.clone(),
125 enum_values,
126 visible: None,
127 inaccessible: self.inaccessible,
128 tags: self.tags.clone(),
129 rust_typename: None,
130 directive_invocations: to_meta_directive_invocation(self.directives.clone()),
131 },
132 );
133
134 Ok(())
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use crate::{dynamic::*, value, Name, PathSegment, Pos, ServerError, Value};
141
142 #[tokio::test]
143 async fn enum_type() {
144 let my_enum = Enum::new("MyEnum").item("A").item("B");
145
146 let query = Object::new("Query")
147 .field(Field::new(
148 "value",
149 TypeRef::named_nn(my_enum.type_name()),
150 |_| FieldFuture::new(async { Ok(Some(Value::from(Name::new("A")))) }),
151 ))
152 .field(
153 Field::new("value2", TypeRef::named_nn(my_enum.type_name()), |ctx| {
154 FieldFuture::new(async move {
155 Ok(Some(FieldValue::value(Name::new(
156 ctx.args.try_get("input")?.enum_name()?,
157 ))))
158 })
159 })
160 .argument(InputValue::new(
161 "input",
162 TypeRef::named_nn(my_enum.type_name()),
163 )),
164 )
165 .field(Field::new(
166 "errValue",
167 TypeRef::named_nn(my_enum.type_name()),
168 |_| FieldFuture::new(async { Ok(Some(Value::from(Name::new("C")))) }),
169 ));
170 let schema = Schema::build("Query", None, None)
171 .register(my_enum)
172 .register(query)
173 .finish()
174 .unwrap();
175
176 assert_eq!(
177 schema
178 .execute("{ value value2(input: B) }")
179 .await
180 .into_result()
181 .unwrap()
182 .data,
183 value!({
184 "value": "A",
185 "value2": "B"
186 })
187 );
188
189 assert_eq!(
190 schema
191 .execute("{ errValue }")
192 .await
193 .into_result()
194 .unwrap_err(),
195 vec![ServerError {
196 message: "internal: invalid item for enum \"MyEnum\"".to_owned(),
197 source: None,
198 locations: vec![Pos { column: 3, line: 1 }],
199 path: vec![PathSegment::Field("errValue".to_owned())],
200 extensions: None,
201 }]
202 );
203 }
204}