async-graphql/src/types/query_root.rs

198 lines
7.5 KiB
Rust
Raw Normal View History

2020-10-15 06:38:10 +00:00
use std::borrow::Cow;
use indexmap::map::IndexMap;
2022-04-13 03:00:24 +00:00
use crate::{
model::{__Schema, __Type},
2022-04-19 04:25:11 +00:00
parser::types::Field,
registry::{self, SDLExportOptions},
2022-04-19 04:25:11 +00:00
resolver_utils::{resolve_container, ContainerType},
2022-04-13 03:00:24 +00:00
schema::IntrospectionMode,
2022-04-19 04:25:11 +00:00
Any, Context, ContextSelectionSet, ObjectType, OutputType, Positioned, ServerError,
ServerResult, SimpleObject, Value,
2020-03-06 15:58:43 +00:00
};
2020-04-09 14:03:09 +00:00
/// Federation service
#[derive(SimpleObject)]
#[graphql(internal, name = "_Service")]
2020-04-09 14:03:09 +00:00
struct Service {
sdl: Option<String>,
}
2020-09-13 09:38:19 +00:00
pub(crate) struct QueryRoot<T> {
pub(crate) inner: T,
2020-03-03 11:15:18 +00:00
}
2020-03-02 00:24:49 +00:00
#[async_trait::async_trait]
impl<T: ObjectType> ContainerType for QueryRoot<T> {
async fn resolve_field(&self, ctx: &Context<'_>) -> ServerResult<Option<Value>> {
2022-04-13 03:00:24 +00:00
if matches!(
ctx.schema_env.registry.introspection_mode,
IntrospectionMode::Enabled | IntrospectionMode::IntrospectionOnly
) && matches!(
ctx.query_env.introspection_mode,
IntrospectionMode::Enabled | IntrospectionMode::IntrospectionOnly,
) {
if ctx.item.node.name.node == "__schema" {
let mut ctx_obj = ctx.with_selection_set(&ctx.item.node.selection_set);
ctx_obj.is_for_introspection = true;
let visible_types = ctx.schema_env.registry.find_visible_types(ctx);
return OutputType::resolve(
&__Schema::new(&ctx.schema_env.registry, &visible_types),
&ctx_obj,
ctx.item,
)
.await
.map(Some);
} else if ctx.item.node.name.node == "__type" {
2021-11-15 01:12:13 +00:00
let (_, type_name) = ctx.param_value::<String>("name", None)?;
let mut ctx_obj = ctx.with_selection_set(&ctx.item.node.selection_set);
ctx_obj.is_for_introspection = true;
let visible_types = ctx.schema_env.registry.find_visible_types(ctx);
return OutputType::resolve(
&ctx.schema_env
.registry
.types
.get(&type_name)
.filter(|_| visible_types.contains(type_name.as_str()))
.map(|ty| __Type::new_simple(&ctx.schema_env.registry, &visible_types, ty)),
&ctx_obj,
ctx.item,
)
.await
.map(Some);
}
}
2022-04-13 03:00:24 +00:00
if ctx.schema_env.registry.introspection_mode == IntrospectionMode::IntrospectionOnly
|| ctx.query_env.introspection_mode == IntrospectionMode::IntrospectionOnly
{
return Ok(None);
}
if ctx.schema_env.registry.enable_federation || ctx.schema_env.registry.has_entities() {
if ctx.item.node.name.node == "_entities" {
2021-11-15 01:12:13 +00:00
let (_, representations) = ctx.param_value::<Vec<Any>>("representations", None)?;
let res = futures_util::future::try_join_all(representations.iter().map(
|item| async move {
self.inner.find_entity(ctx, &item.0).await?.ok_or_else(|| {
ServerError::new("Entity not found.", Some(ctx.item.pos))
})
},
))
.await?;
return Ok(Some(Value::List(res)));
} else if ctx.item.node.name.node == "_service" {
let mut ctx_obj = ctx.with_selection_set(&ctx.item.node.selection_set);
ctx_obj.is_for_introspection = true;
return OutputType::resolve(
&Service {
sdl: Some(
ctx.schema_env
.registry
.export_sdl(SDLExportOptions::new().federation()),
),
},
&ctx_obj,
ctx.item,
)
.await
.map(Some);
}
}
self.inner.resolve_field(ctx).await
}
}
#[async_trait::async_trait]
impl<T: ObjectType> OutputType 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 root = T::create_type_info(registry);
2022-04-13 03:00:24 +00:00
if matches!(
registry.introspection_mode,
IntrospectionMode::Enabled | IntrospectionMode::IntrospectionOnly
) {
let schema_type = __Schema::create_type_info(registry);
if let Some(registry::MetaType::Object { fields, .. }) =
registry.types.get_mut(T::type_name().as_ref())
{
fields.insert(
"__schema".to_string(),
registry::MetaField {
name: "__schema".to_string(),
description: Some("Access the current type schema of this server."),
args: Default::default(),
ty: schema_type,
deprecation: Default::default(),
cache_control: Default::default(),
external: false,
requires: None,
provides: None,
2022-08-17 01:29:43 +00:00
shareable: false,
2022-08-18 09:40:04 +00:00
inaccessible: false,
2022-08-22 09:44:02 +00:00
tags: Default::default(),
visible: None,
compute_complexity: None,
override_from: None,
2020-03-08 12:35:36 +00:00
},
);
fields.insert(
"__type".to_string(),
registry::MetaField {
name: "__type".to_string(),
description: Some("Request the type information of a single type."),
args: {
let mut args = IndexMap::new();
args.insert(
"name".to_string(),
registry::MetaInputValue {
name: "name",
description: None,
ty: "String!".to_string(),
default_value: None,
visible: None,
2022-08-18 09:40:04 +00:00
inaccessible: false,
2022-08-22 09:44:02 +00:00
tags: Default::default(),
is_secret: false,
},
);
args
},
ty: "__Type".to_string(),
deprecation: Default::default(),
cache_control: Default::default(),
external: false,
requires: None,
provides: None,
2022-08-17 01:29:43 +00:00
shareable: false,
2022-08-18 09:40:04 +00:00
inaccessible: false,
2022-08-22 09:44:02 +00:00
tags: Default::default(),
override_from: None,
visible: None,
compute_complexity: None,
},
);
}
2020-03-08 12:35:36 +00:00
}
2020-03-08 12:35:36 +00:00
root
2020-03-02 00:24:49 +00:00
}
2021-06-07 12:51:20 +00:00
async fn resolve(
&self,
ctx: &ContextSelectionSet<'_>,
_field: &Positioned<Field>,
) -> ServerResult<Value> {
2020-09-29 23:45:48 +00:00
resolve_container(ctx, self).await
2020-03-19 09:20:12 +00:00
}
}
impl<T: ObjectType> ObjectType for QueryRoot<T> {}