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
use crate::model::{__Schema, __Type}; use crate::registry::Type; use crate::{ registry, Context, ContextSelectionSet, ErrorWithPosition, GQLObject, GQLOutputValue, GQLType, QueryError, Result, Value, }; use graphql_parser::query::Field; use std::borrow::Cow; use std::collections::HashMap; pub struct QueryRoot<T> { pub inner: T, } impl<T: GQLType> GQLType for QueryRoot<T> { fn type_name() -> Cow<'static, str> { T::type_name() } fn create_type_info(registry: &mut registry::Registry) -> String { let schema_type = __Schema::create_type_info(registry); let root = T::create_type_info(registry); if let Some(Type::Object { fields, .. }) = registry.types.get_mut(T::type_name().as_ref()) { fields.insert( "__schema", registry::Field { name: "__schema", description: Some("Access the current type schema of this server."), args: Default::default(), ty: schema_type, deprecation: None, }, ); fields.insert( "__type", registry::Field { name: "__type", description: Some("Request the type information of a single type."), args: { let mut args = HashMap::new(); args.insert( "name", registry::InputValue { name: "name", description: None, ty: "String!".to_string(), default_value: None, }, ); args }, ty: "__Type".to_string(), deprecation: None, }, ); } root } } #[async_trait::async_trait] impl<T: GQLObject + Send + Sync> GQLObject for QueryRoot<T> { async fn resolve_field(&self, ctx: &Context<'_>, field: &Field) -> Result<serde_json::Value> { if field.name.as_str() == "__schema" { let ctx_obj = ctx.with_item(&field.selection_set); return GQLOutputValue::resolve( &__Schema { registry: &ctx.registry, }, &ctx_obj, ) .await .map_err(|err| err.with_position(field.position).into()); } else if field.name.as_str() == "__type" { let type_name: String = ctx.param_value("name", || Value::Null)?; let ctx_obj = ctx.with_item(&field.selection_set); return GQLOutputValue::resolve( &ctx.registry .types .get(&type_name) .map(|ty| __Type::new_simple(ctx.registry, ty)), &ctx_obj, ) .await .map_err(|err| err.with_position(field.position).into()); } return self.inner.resolve_field(ctx, field).await; } async fn resolve_inline_fragment( &self, name: &str, _ctx: &ContextSelectionSet<'_>, _result: &mut serde_json::Map<String, serde_json::Value>, ) -> Result<()> { anyhow::bail!(QueryError::UnrecognizedInlineFragment { object: T::type_name().to_string(), name: name.to_string(), }); } }