async-graphql/src/types/query_root.rs

145 lines
5.0 KiB
Rust
Raw Normal View History

2020-03-06 15:58:43 +00:00
use crate::model::{__Schema, __Type};
2020-04-09 14:03:09 +00:00
use crate::scalars::Any;
2020-03-06 15:58:43 +00:00
use crate::{
do_resolve, registry, Context, ContextSelectionSet, Error, ObjectType, OutputValueType, Pos,
QueryError, Result, Type, Value,
2020-03-06 15:58:43 +00:00
};
2020-04-09 14:03:09 +00:00
use async_graphql_derive::SimpleObject;
2020-03-02 00:24:49 +00:00
use std::borrow::Cow;
2020-03-08 12:35:36 +00:00
use std::collections::HashMap;
2020-03-02 00:24:49 +00:00
2020-04-09 14:03:09 +00:00
/// Federation service
#[SimpleObject(internal)]
struct Service {
sdl: Option<String>,
}
2020-03-03 11:15:18 +00:00
pub struct QueryRoot<T> {
pub inner: T,
2020-03-25 07:07:16 +00:00
pub disable_introspection: bool,
2020-03-03 11:15:18 +00:00
}
2020-03-02 00:24:49 +00:00
2020-03-19 09:20:12 +00:00
impl<T: Type> Type for QueryRoot<T> {
2020-03-02 00:24:49 +00:00
fn type_name() -> Cow<'static, str> {
2020-03-03 03:48:00 +00:00
T::type_name()
}
2020-03-03 11:15:18 +00:00
fn create_type_info(registry: &mut registry::Registry) -> String {
2020-03-08 12:35:36 +00:00
let schema_type = __Schema::create_type_info(registry);
let root = T::create_type_info(registry);
if let Some(registry::MetaType::Object { fields, .. }) =
2020-03-19 09:20:12 +00:00
registry.types.get_mut(T::type_name().as_ref())
{
2020-03-08 12:35:36 +00:00
fields.insert(
2020-03-19 09:20:12 +00:00
"__schema".to_string(),
registry::MetaField {
2020-03-19 09:20:12 +00:00
name: "__schema".to_string(),
2020-03-08 12:35:36 +00:00
description: Some("Access the current type schema of this server."),
args: Default::default(),
ty: schema_type,
deprecation: None,
2020-03-22 08:45:59 +00:00
cache_control: Default::default(),
2020-04-09 14:03:09 +00:00
external: false,
requires: None,
provides: None,
2020-03-08 12:35:36 +00:00
},
);
fields.insert(
2020-03-19 09:20:12 +00:00
"__type".to_string(),
registry::MetaField {
2020-03-19 09:20:12 +00:00
name: "__type".to_string(),
2020-03-08 12:35:36 +00:00
description: Some("Request the type information of a single type."),
args: {
let mut args = HashMap::new();
args.insert(
"name",
registry::MetaInputValue {
2020-03-08 12:35:36 +00:00
name: "name",
description: None,
ty: "String!".to_string(),
default_value: None,
2020-03-22 01:34:32 +00:00
validator: None,
2020-03-08 12:35:36 +00:00
},
);
args
},
ty: "__Type".to_string(),
deprecation: None,
2020-03-22 08:45:59 +00:00
cache_control: Default::default(),
2020-04-09 14:03:09 +00:00
external: false,
requires: None,
provides: None,
2020-03-08 12:35:36 +00:00
},
);
}
root
2020-03-02 00:24:49 +00:00
}
}
#[async_trait::async_trait]
2020-03-19 09:20:12 +00:00
impl<T: ObjectType + Send + Sync> ObjectType for QueryRoot<T> {
async fn resolve_field(&self, ctx: &Context<'_>) -> Result<serde_json::Value> {
if ctx.name.node == "__schema" {
2020-03-25 07:07:16 +00:00
if self.disable_introspection {
return Err(Error::Query {
pos: ctx.position(),
path: Some(ctx.path_node.as_ref().unwrap().to_json()),
err: QueryError::FieldNotFound {
field_name: ctx.name.to_string(),
object: Self::type_name().to_string(),
},
});
2020-03-25 07:07:16 +00:00
}
let ctx_obj = ctx.with_selection_set(&ctx.selection_set);
2020-03-19 09:20:12 +00:00
return OutputValueType::resolve(
2020-03-06 15:58:43 +00:00
&__Schema {
registry: &ctx.registry,
},
&ctx_obj,
ctx.position(),
2020-03-06 15:58:43 +00:00
)
.await;
} else if ctx.name.node == "__type" {
let type_name: String = ctx.param_value("name", || Value::Null)?;
let ctx_obj = ctx.with_selection_set(&ctx.selection_set);
2020-03-19 09:20:12 +00:00
return OutputValueType::resolve(
2020-03-06 15:58:43 +00:00
&ctx.registry
.types
.get(&type_name)
.map(|ty| __Type::new_simple(ctx.registry, ty)),
&ctx_obj,
ctx.position(),
2020-03-06 15:58:43 +00:00
)
.await;
} else if ctx.name.node == "_entities" {
let representations: Vec<Any> = ctx.param_value("representations", || Value::Null)?;
2020-04-09 14:03:09 +00:00
let mut res = Vec::new();
for item in representations {
res.push(self.inner.find_entity(ctx, &item.0).await?);
2020-04-09 14:03:09 +00:00
}
return Ok(res.into());
} else if ctx.name.node == "_service" {
let ctx_obj = ctx.with_selection_set(&ctx.selection_set);
2020-04-09 14:03:09 +00:00
return OutputValueType::resolve(
&Service {
sdl: Some(ctx.registry.create_federation_sdl()),
},
&ctx_obj,
ctx.position(),
2020-04-09 14:03:09 +00:00
)
.await;
2020-03-02 00:24:49 +00:00
}
2020-03-03 11:15:18 +00:00
self.inner.resolve_field(ctx).await
2020-03-07 02:39:55 +00:00
}
2020-03-02 00:24:49 +00:00
}
2020-03-19 09:20:12 +00:00
#[async_trait::async_trait]
impl<T: ObjectType + Send + Sync> OutputValueType for QueryRoot<T> {
async fn resolve(&self, ctx: &ContextSelectionSet<'_>, _pos: Pos) -> Result<serde_json::Value> {
do_resolve(ctx, self).await
2020-03-19 09:20:12 +00:00
}
}