2020-03-06 15:58:43 +00:00
|
|
|
use crate::model::{__Schema, __Type};
|
2020-09-06 06:16:36 +00:00
|
|
|
use crate::parser::types::Field;
|
2020-09-12 09:29:52 +00:00
|
|
|
use crate::resolver_utils::{resolve_object, ObjectType};
|
2020-03-06 15:58:43 +00:00
|
|
|
use crate::{
|
2020-09-18 00:52:13 +00:00
|
|
|
registry, Any, Context, ContextSelectionSet, Error, OutputValueType, Positioned, QueryError,
|
|
|
|
Result, SimpleObject, Type,
|
2020-03-06 15:58:43 +00:00
|
|
|
};
|
2020-09-13 03:41:15 +00:00
|
|
|
|
2020-05-16 02:05:48 +00:00
|
|
|
use indexmap::map::IndexMap;
|
2020-03-02 00:24:49 +00:00
|
|
|
use std::borrow::Cow;
|
|
|
|
|
2020-04-09 14:03:09 +00:00
|
|
|
/// Federation service
|
2020-09-18 00:52:13 +00:00
|
|
|
#[derive(SimpleObject)]
|
2020-09-13 03:41:15 +00:00
|
|
|
#[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,
|
|
|
|
pub(crate) 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);
|
2020-05-15 02:08:37 +00:00
|
|
|
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(),
|
2020-05-15 02:08:37 +00:00
|
|
|
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(),
|
2020-05-15 02:08:37 +00:00
|
|
|
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: {
|
2020-05-16 02:05:48 +00:00
|
|
|
let mut args = IndexMap::new();
|
2020-03-08 12:35:36 +00:00
|
|
|
args.insert(
|
|
|
|
"name",
|
2020-05-15 02:08:37 +00:00
|
|
|
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> {
|
2020-04-26 07:12:18 +00:00
|
|
|
async fn resolve_field(&self, ctx: &Context<'_>) -> Result<serde_json::Value> {
|
2020-09-06 05:38:31 +00:00
|
|
|
if ctx.item.node.name.node == "__schema" {
|
2020-03-25 07:07:16 +00:00
|
|
|
if self.disable_introspection {
|
2020-04-02 02:21:04 +00:00
|
|
|
return Err(Error::Query {
|
2020-09-12 16:42:15 +00:00
|
|
|
pos: ctx.item.pos,
|
2020-07-15 10:05:24 +00:00
|
|
|
path: ctx
|
|
|
|
.path_node
|
|
|
|
.as_ref()
|
|
|
|
.and_then(|path| serde_json::to_value(path).ok()),
|
2020-04-02 02:21:04 +00:00
|
|
|
err: QueryError::FieldNotFound {
|
2020-09-06 05:38:31 +00:00
|
|
|
field_name: ctx.item.node.name.to_string(),
|
2020-04-02 02:21:04 +00:00
|
|
|
object: Self::type_name().to_string(),
|
|
|
|
},
|
|
|
|
});
|
2020-03-25 07:07:16 +00:00
|
|
|
}
|
|
|
|
|
2020-09-06 05:38:31 +00:00
|
|
|
let ctx_obj = ctx.with_selection_set(&ctx.item.node.selection_set);
|
2020-03-19 09:20:12 +00:00
|
|
|
return OutputValueType::resolve(
|
2020-03-06 15:58:43 +00:00
|
|
|
&__Schema {
|
2020-05-19 08:24:15 +00:00
|
|
|
registry: &ctx.schema_env.registry,
|
2020-03-06 15:58:43 +00:00
|
|
|
},
|
|
|
|
&ctx_obj,
|
2020-05-20 00:18:28 +00:00
|
|
|
ctx.item,
|
2020-03-06 15:58:43 +00:00
|
|
|
)
|
2020-04-02 02:21:04 +00:00
|
|
|
.await;
|
2020-09-06 05:38:31 +00:00
|
|
|
} else if ctx.item.node.name.node == "__type" {
|
2020-05-26 10:34:43 +00:00
|
|
|
let type_name: String = ctx.param_value("name", None)?;
|
2020-09-06 05:38:31 +00:00
|
|
|
let ctx_obj = ctx.with_selection_set(&ctx.item.node.selection_set);
|
2020-03-19 09:20:12 +00:00
|
|
|
return OutputValueType::resolve(
|
2020-05-19 08:24:15 +00:00
|
|
|
&ctx.schema_env
|
|
|
|
.registry
|
2020-03-06 15:58:43 +00:00
|
|
|
.types
|
|
|
|
.get(&type_name)
|
2020-05-19 08:24:15 +00:00
|
|
|
.map(|ty| __Type::new_simple(&ctx.schema_env.registry, ty)),
|
2020-03-06 15:58:43 +00:00
|
|
|
&ctx_obj,
|
2020-05-20 00:18:28 +00:00
|
|
|
ctx.item,
|
2020-03-06 15:58:43 +00:00
|
|
|
)
|
2020-04-02 02:21:04 +00:00
|
|
|
.await;
|
2020-09-06 05:38:31 +00:00
|
|
|
} else if ctx.item.node.name.node == "_entities" {
|
2020-05-26 10:34:43 +00:00
|
|
|
let representations: Vec<Any> = ctx.param_value("representations", None)?;
|
2020-04-09 14:03:09 +00:00
|
|
|
let mut res = Vec::new();
|
|
|
|
for item in representations {
|
2020-05-09 09:55:04 +00:00
|
|
|
res.push(self.inner.find_entity(ctx, &item.0).await?);
|
2020-04-09 14:03:09 +00:00
|
|
|
}
|
|
|
|
return Ok(res.into());
|
2020-09-06 05:38:31 +00:00
|
|
|
} else if ctx.item.node.name.node == "_service" {
|
|
|
|
let ctx_obj = ctx.with_selection_set(&ctx.item.node.selection_set);
|
2020-04-09 14:03:09 +00:00
|
|
|
return OutputValueType::resolve(
|
|
|
|
&Service {
|
2020-09-23 00:04:00 +00:00
|
|
|
sdl: Some(ctx.schema_env.registry.export_sdl(true)),
|
2020-04-09 14:03:09 +00:00
|
|
|
},
|
|
|
|
&ctx_obj,
|
2020-05-20 00:18:28 +00:00
|
|
|
ctx.item,
|
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
|
|
|
|
2020-04-26 07:12: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> {
|
2020-05-20 00:18:28 +00:00
|
|
|
async fn resolve(
|
|
|
|
&self,
|
|
|
|
ctx: &ContextSelectionSet<'_>,
|
|
|
|
_field: &Positioned<Field>,
|
|
|
|
) -> Result<serde_json::Value> {
|
2020-09-12 09:29:52 +00:00
|
|
|
resolve_object(ctx, self).await
|
2020-03-19 09:20:12 +00:00
|
|
|
}
|
|
|
|
}
|