1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
use crate::{ do_resolve, registry, Context, ContextSelectionSet, ObjectType, OutputValueType, Result, Type, }; use graphql_parser::query::Field; use graphql_parser::Pos; use std::borrow::Cow; use std::collections::HashMap; pub struct Edge<'a, T, E> { pub cursor: &'a str, pub node: &'a T, pub extra_type: &'a E, } impl<'a, T, E> Type for Edge<'a, T, E> where T: OutputValueType + Send + Sync + 'a, E: ObjectType + Sync + Send + 'a, { fn type_name() -> Cow<'static, str> { Cow::Owned(format!("{}Edge", T::type_name())) } fn create_type_info(registry: &mut registry::Registry) -> String { registry.create_type::<Self, _>(|registry| { E::create_type_info(registry); let extra_fields = if let Some(registry::Type::Object { fields, .. }) = registry.types.get_mut(E::type_name().as_ref()) { fields.clone() } else { unreachable!() }; registry.types.remove(E::type_name().as_ref()); registry::Type::Object { name: Self::type_name().to_string(), description: Some("An edge in a connection."), fields: { let mut fields = HashMap::new(); fields.insert( "node".to_string(), registry::Field { name: "node".to_string(), description: Some("The item at the end of the edge"), args: Default::default(), ty: T::create_type_info(registry), deprecation: None, cache_control: Default::default(), external: false, requires: None, provides: None, }, ); fields.insert( "cursor".to_string(), registry::Field { name: "cursor".to_string(), description: Some("A cursor for use in pagination"), args: Default::default(), ty: String::create_type_info(registry), deprecation: None, cache_control: Default::default(), external: false, requires: None, provides: None, }, ); fields.extend(extra_fields); fields }, cache_control: Default::default(), extends: false, keys: None, } }) } } #[async_trait::async_trait] impl<'a, T, E> ObjectType for Edge<'a, T, E> where T: OutputValueType + Send + Sync + 'a, E: ObjectType + Sync + Send + 'a, { async fn resolve_field(&self, ctx: &Context<'_>, field: &Field) -> Result<serde_json::Value> { if field.name.as_str() == "node" { let ctx_obj = ctx.with_selection_set(&field.selection_set); return OutputValueType::resolve(self.node, &ctx_obj, field.position).await; } else if field.name.as_str() == "cursor" { return Ok(self.cursor.into()); } self.extra_type.resolve_field(ctx, field).await } } #[async_trait::async_trait] impl<'a, T, E> OutputValueType for Edge<'a, T, E> where T: OutputValueType + Send + Sync + 'a, E: ObjectType + Sync + Send + 'a, { async fn resolve( value: &Self, ctx: &ContextSelectionSet<'_>, _pos: Pos, ) -> Result<serde_json::Value> { do_resolve(ctx, value).await } }