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