1use indexmap::{IndexMap, IndexSet};
2
3use super::{directive::to_meta_directive_invocation, Directive};
4use crate::{
5 dynamic::{InputValue, SchemaError, TypeRef},
6 registry::{Deprecation, MetaField, MetaType, Registry},
7};
8
9#[derive(Debug)]
86pub struct InterfaceField {
87 pub(crate) name: String,
88 pub(crate) description: Option<String>,
89 pub(crate) arguments: IndexMap<String, InputValue>,
90 pub(crate) ty: TypeRef,
91 pub(crate) deprecation: Deprecation,
92 pub(crate) external: bool,
93 pub(crate) requires: Option<String>,
94 pub(crate) provides: Option<String>,
95 pub(crate) shareable: bool,
96 pub(crate) inaccessible: bool,
97 pub(crate) tags: Vec<String>,
98 pub(crate) override_from: Option<String>,
99 pub(crate) directives: Vec<Directive>,
100}
101
102impl InterfaceField {
103 pub fn new(name: impl Into<String>, ty: impl Into<TypeRef>) -> Self {
105 Self {
106 name: name.into(),
107 description: None,
108 arguments: Default::default(),
109 ty: ty.into(),
110 deprecation: Deprecation::NoDeprecated,
111 external: false,
112 requires: None,
113 provides: None,
114 shareable: false,
115 inaccessible: false,
116 tags: Vec::new(),
117 override_from: None,
118 directives: Vec::new(),
119 }
120 }
121
122 impl_set_description!();
123 impl_set_deprecation!();
124 impl_set_external!();
125 impl_set_requires!();
126 impl_set_provides!();
127 impl_set_shareable!();
128 impl_set_inaccessible!();
129 impl_set_tags!();
130 impl_set_override_from!();
131 impl_directive!();
132
133 #[inline]
135 pub fn argument(mut self, input_value: InputValue) -> Self {
136 self.arguments.insert(input_value.name.clone(), input_value);
137 self
138 }
139}
140
141#[derive(Debug)]
143pub struct Interface {
144 pub(crate) name: String,
145 pub(crate) description: Option<String>,
146 pub(crate) fields: IndexMap<String, InterfaceField>,
147 pub(crate) implements: IndexSet<String>,
148 keys: Vec<String>,
149 extends: bool,
150 inaccessible: bool,
151 tags: Vec<String>,
152 pub(crate) directives: Vec<Directive>,
153}
154
155impl Interface {
156 #[inline]
158 pub fn new(name: impl Into<String>) -> Self {
159 Self {
160 name: name.into(),
161 description: None,
162 fields: Default::default(),
163 implements: Default::default(),
164 keys: Vec::new(),
165 extends: false,
166 inaccessible: false,
167 tags: Vec::new(),
168 directives: Vec::new(),
169 }
170 }
171
172 impl_set_description!();
173 impl_set_extends!();
174 impl_set_inaccessible!();
175 impl_set_tags!();
176 impl_directive!();
177
178 #[inline]
180 pub fn field(mut self, field: InterfaceField) -> Self {
181 assert!(
182 !self.fields.contains_key(&field.name),
183 "Field `{}` already exists",
184 field.name
185 );
186 self.fields.insert(field.name.clone(), field);
187 self
188 }
189
190 #[inline]
192 pub fn implement(mut self, interface: impl Into<String>) -> Self {
193 let interface = interface.into();
194 assert!(
195 !self.implements.contains(&interface),
196 "Implement `{}` already exists",
197 interface
198 );
199 self.implements.insert(interface);
200 self
201 }
202
203 pub fn key(mut self, fields: impl Into<String>) -> Self {
207 self.keys.push(fields.into());
208 self
209 }
210
211 #[inline]
213 pub fn type_name(&self) -> &str {
214 &self.name
215 }
216
217 #[inline]
218 pub(crate) fn is_entity(&self) -> bool {
219 !self.keys.is_empty()
220 }
221
222 pub(crate) fn register(&self, registry: &mut Registry) -> Result<(), SchemaError> {
223 let mut fields = IndexMap::new();
224
225 for field in self.fields.values() {
226 let mut args = IndexMap::new();
227
228 for argument in field.arguments.values() {
229 args.insert(argument.name.clone(), argument.to_meta_input_value());
230 }
231
232 fields.insert(
233 field.name.clone(),
234 MetaField {
235 name: field.name.clone(),
236 description: field.description.clone(),
237 args,
238 ty: field.ty.to_string(),
239 deprecation: field.deprecation.clone(),
240 cache_control: Default::default(),
241 external: field.external,
242 requires: field.requires.clone(),
243 provides: field.provides.clone(),
244 visible: None,
245 shareable: field.shareable,
246 inaccessible: field.inaccessible,
247 tags: field.tags.clone(),
248 override_from: field.override_from.clone(),
249 compute_complexity: None,
250 directive_invocations: to_meta_directive_invocation(field.directives.clone()),
251 },
252 );
253 }
254
255 registry.types.insert(
256 self.name.clone(),
257 MetaType::Interface {
258 name: self.name.clone(),
259 description: self.description.clone(),
260 fields,
261 possible_types: Default::default(),
262 extends: self.extends,
263 keys: if !self.keys.is_empty() {
264 Some(self.keys.clone())
265 } else {
266 None
267 },
268 visible: None,
269 inaccessible: self.inaccessible,
270 tags: self.tags.clone(),
271 rust_typename: None,
272 directive_invocations: to_meta_directive_invocation(self.directives.clone()),
273 },
274 );
275
276 Ok(())
277 }
278}
279
280#[cfg(test)]
281mod tests {
282 use async_graphql_parser::Pos;
283
284 use crate::{dynamic::*, value, PathSegment, ServerError, Value};
285
286 #[tokio::test]
287 async fn basic_interface() {
288 let obj_a = Object::new("MyObjA")
289 .implement("MyInterface")
290 .field(Field::new("a", TypeRef::named(TypeRef::INT), |_| {
291 FieldFuture::new(async { Ok(Some(Value::from(100))) })
292 }))
293 .field(Field::new("b", TypeRef::named(TypeRef::INT), |_| {
294 FieldFuture::new(async { Ok(Some(Value::from(200))) })
295 }));
296
297 let obj_b = Object::new("MyObjB")
298 .implement("MyInterface")
299 .field(Field::new("a", TypeRef::named(TypeRef::INT), |_| {
300 FieldFuture::new(async { Ok(Some(Value::from(300))) })
301 }))
302 .field(Field::new("c", TypeRef::named(TypeRef::INT), |_| {
303 FieldFuture::new(async { Ok(Some(Value::from(400))) })
304 }));
305
306 let interface = Interface::new("MyInterface")
307 .field(InterfaceField::new("a", TypeRef::named(TypeRef::INT)));
308
309 let query = Object::new("Query")
310 .field(Field::new(
311 "valueA",
312 TypeRef::named_nn(interface.type_name()),
313 |_| FieldFuture::new(async { Ok(Some(FieldValue::NULL.with_type("MyObjA"))) }),
314 ))
315 .field(Field::new(
316 "valueB",
317 TypeRef::named_nn(interface.type_name()),
318 |_| FieldFuture::new(async { Ok(Some(FieldValue::NULL.with_type("MyObjB"))) }),
319 ));
320
321 let schema = Schema::build(query.type_name(), None, None)
322 .register(obj_a)
323 .register(obj_b)
324 .register(interface)
325 .register(query)
326 .finish()
327 .unwrap();
328
329 let query = r#"
330 fragment A on MyObjA {
331 b
332 }
333
334 fragment B on MyObjB {
335 c
336 }
337
338 {
339 valueA { __typename a ...A ...B }
340 valueB { __typename a ...A ...B }
341 }
342 "#;
343 assert_eq!(
344 schema.execute(query).await.into_result().unwrap().data,
345 value!({
346 "valueA": {
347 "__typename": "MyObjA",
348 "a": 100,
349 "b": 200,
350 },
351 "valueB": {
352 "__typename": "MyObjB",
353 "a": 300,
354 "c": 400,
355 }
356 })
357 );
358 }
359
360 #[tokio::test]
361 async fn does_not_implement() {
362 let obj_a = Object::new("MyObjA")
363 .field(Field::new("a", TypeRef::named(TypeRef::INT), |_| {
364 FieldFuture::new(async { Ok(Some(Value::from(100))) })
365 }))
366 .field(Field::new("b", TypeRef::named(TypeRef::INT), |_| {
367 FieldFuture::new(async { Ok(Some(Value::from(200))) })
368 }));
369
370 let interface = Interface::new("MyInterface")
371 .field(InterfaceField::new("a", TypeRef::named(TypeRef::INT)));
372
373 let query = Object::new("Query").field(Field::new(
374 "valueA",
375 TypeRef::named_nn(interface.type_name()),
376 |_| FieldFuture::new(async { Ok(Some(FieldValue::NULL.with_type("MyObjA"))) }),
377 ));
378
379 let schema = Schema::build(query.type_name(), None, None)
380 .register(obj_a)
381 .register(interface)
382 .register(query)
383 .finish()
384 .unwrap();
385
386 let query = r#"
387 {
388 valueA { a }
389 }
390 "#;
391 assert_eq!(
392 schema.execute(query).await.into_result().unwrap_err(),
393 vec![ServerError {
394 message: "internal: object \"MyObjA\" does not implement interface \"MyInterface\""
395 .to_owned(),
396 source: None,
397 locations: vec![Pos {
398 column: 13,
399 line: 3
400 }],
401 path: vec![PathSegment::Field("valueA".to_owned())],
402 extensions: None,
403 }]
404 );
405 }
406 #[tokio::test]
407 async fn query_type_condition() {
408 struct MyObjA;
409 let obj_a = Object::new("MyObjA")
410 .implement("MyInterface")
411 .field(Field::new("a", TypeRef::named(TypeRef::INT), |_| {
412 FieldFuture::new(async { Ok(Some(Value::from(100))) })
413 }))
414 .field(Field::new("b", TypeRef::named(TypeRef::INT), |_| {
415 FieldFuture::new(async { Ok(Some(Value::from(200))) })
416 }));
417 let interface = Interface::new("MyInterface")
418 .field(InterfaceField::new("a", TypeRef::named(TypeRef::INT)));
419 let query = Object::new("Query");
420 let query = query.field(Field::new(
421 "valueA",
422 TypeRef::named_nn(obj_a.type_name()),
423 |_| FieldFuture::new(async { Ok(Some(FieldValue::owned_any(MyObjA))) }),
424 ));
425 let schema = Schema::build(query.type_name(), None, None)
426 .register(obj_a)
427 .register(interface)
428 .register(query)
429 .finish()
430 .unwrap();
431 let query = r#"
432 {
433 valueA { __typename
434 b
435 ... on MyInterface { a } }
436 }
437 "#;
438 assert_eq!(
439 schema.execute(query).await.into_result().unwrap().data,
440 value!({
441 "valueA": {
442 "__typename": "MyObjA",
443 "b": 200,
444 "a": 100,
445 }
446 })
447 );
448 }
449}