async-graphql/src/type.rs
2020-03-02 00:52:05 +08:00

134 lines
3.6 KiB
Rust

use crate::{ContextSelectionSet, ErrorWithPosition, QueryError, Result};
use anyhow::Error;
use graphql_parser::query::Value;
#[doc(hidden)]
pub trait GQLType {
fn type_name() -> String;
}
#[doc(hidden)]
pub trait GQLInputValue: GQLType + Sized {
fn parse(value: Value) -> Result<Self>;
fn parse_from_json(value: serde_json::Value) -> Result<Self>;
}
#[doc(hidden)]
#[async_trait::async_trait]
pub trait GQLOutputValue: GQLType {
async fn resolve(self, ctx: &ContextSelectionSet<'_>) -> Result<serde_json::Value>;
}
impl<T: GQLType> GQLType for Vec<T> {
fn type_name() -> String {
format!("[{}]!", T::type_name()).into()
}
}
impl<T: GQLInputValue> GQLInputValue for Vec<T> {
fn parse(value: Value) -> Result<Self> {
match value {
Value::List(values) => {
let mut result = Vec::new();
for value in values {
result.push(GQLInputValue::parse(value)?);
}
Ok(result)
}
_ => {
return Err(QueryError::ExpectedType {
expect: Self::type_name(),
actual: value,
}
.into())
}
}
}
fn parse_from_json(value: serde_json::Value) -> Result<Self> {
match value {
serde_json::Value::Array(values) => {
let mut result = Vec::new();
for value in values {
result.push(GQLInputValue::parse_from_json(value)?);
}
Ok(result)
}
_ => {
return Err(QueryError::ExpectedJsonType {
expect: Self::type_name(),
actual: value,
}
.into())
}
}
}
}
#[async_trait::async_trait]
impl<T: GQLOutputValue + Send> GQLOutputValue for Vec<T> {
async fn resolve(self, ctx: &ContextSelectionSet<'_>) -> Result<serde_json::Value> {
let mut res = Vec::new();
for item in self {
res.push(item.resolve(ctx).await?);
}
Ok(res.into())
}
}
impl<T: GQLType> GQLType for Option<T> {
fn type_name() -> String {
format!("{}", T::type_name().trim_end_matches("!")).into()
}
}
impl<T: GQLInputValue> GQLInputValue for Option<T> {
fn parse(value: Value) -> Result<Self> {
match value {
Value::Null => Ok(None),
_ => Ok(Some(GQLInputValue::parse(value)?)),
}
}
fn parse_from_json(value: serde_json::Value) -> Result<Self> {
match value {
serde_json::Value::Null => Ok(None),
_ => Ok(Some(GQLInputValue::parse_from_json(value)?)),
}
}
}
#[async_trait::async_trait]
impl<T: GQLOutputValue + Send> GQLOutputValue for Option<T> {
async fn resolve(self, ctx: &ContextSelectionSet<'_>) -> Result<serde_json::Value> {
if let Some(inner) = self {
inner.resolve(ctx).await
} else {
Ok(serde_json::Value::Null)
}
}
}
#[doc(hidden)]
pub trait GQLObject: GQLOutputValue {}
pub struct GQLEmptyMutation;
impl GQLType for GQLEmptyMutation {
fn type_name() -> String {
"EmptyMutation".to_string()
}
}
#[async_trait::async_trait]
impl GQLOutputValue for GQLEmptyMutation {
async fn resolve(self, ctx: &ContextSelectionSet<'_>) -> Result<serde_json::Value> {
anyhow::bail!(QueryError::NotConfiguredMutations.with_position(ctx.item.span.0));
}
}
impl GQLObject for GQLEmptyMutation {}
#[doc(hidden)]
pub trait GQLInputObject: GQLInputValue {}