use crate::{
ast::{FromInputValue, InputValue, Selection, ToInputValue},
executor::{ExecutionResult, Executor, Registry},
schema::meta::MetaType,
types::{
async_await::GraphQLValueAsync,
base::{GraphQLType, GraphQLValue},
},
value::{ScalarValue, Value},
};
impl<S, T> GraphQLType<S> for Option<T>
where
T: GraphQLType<S>,
S: ScalarValue,
{
fn name(_: &Self::TypeInfo) -> Option<&'static str> {
None
}
fn meta<'r>(info: &Self::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S>
where
S: 'r,
{
registry.build_nullable_type::<T>(info).into_meta()
}
}
impl<S, T> GraphQLValue<S> for Option<T>
where
S: ScalarValue,
T: GraphQLValue<S>,
{
type Context = T::Context;
type TypeInfo = T::TypeInfo;
fn type_name(&self, _: &Self::TypeInfo) -> Option<&'static str> {
None
}
fn resolve(
&self,
info: &Self::TypeInfo,
_: Option<&[Selection<S>]>,
executor: &Executor<Self::Context, S>,
) -> ExecutionResult<S> {
match *self {
Some(ref obj) => executor.resolve(info, obj),
None => Ok(Value::null()),
}
}
}
impl<S, T> GraphQLValueAsync<S> for Option<T>
where
T: GraphQLValueAsync<S>,
T::TypeInfo: Sync,
T::Context: Sync,
S: ScalarValue + Send + Sync,
{
fn resolve_async<'a>(
&'a self,
info: &'a Self::TypeInfo,
_: Option<&'a [Selection<S>]>,
executor: &'a Executor<Self::Context, S>,
) -> crate::BoxFuture<'a, ExecutionResult<S>> {
let f = async move {
let value = match self {
Some(obj) => executor.resolve_into_value_async(info, obj).await,
None => Value::null(),
};
Ok(value)
};
Box::pin(f)
}
}
impl<S, T> FromInputValue<S> for Option<T>
where
T: FromInputValue<S>,
S: ScalarValue,
{
fn from_input_value(v: &InputValue<S>) -> Option<Option<T>> {
match v {
&InputValue::Null => Some(None),
v => v.convert().map(Some),
}
}
}
impl<S, T> ToInputValue<S> for Option<T>
where
T: ToInputValue<S>,
S: ScalarValue,
{
fn to_input_value(&self) -> InputValue<S> {
match *self {
Some(ref v) => v.to_input_value(),
None => InputValue::null(),
}
}
}
impl<S, T> GraphQLType<S> for Vec<T>
where
T: GraphQLType<S>,
S: ScalarValue,
{
fn name(_: &Self::TypeInfo) -> Option<&'static str> {
None
}
fn meta<'r>(info: &Self::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S>
where
S: 'r,
{
registry.build_list_type::<T>(info).into_meta()
}
}
impl<S, T> GraphQLValue<S> for Vec<T>
where
T: GraphQLValue<S>,
S: ScalarValue,
{
type Context = T::Context;
type TypeInfo = T::TypeInfo;
fn type_name(&self, _: &Self::TypeInfo) -> Option<&'static str> {
None
}
fn resolve(
&self,
info: &Self::TypeInfo,
_: Option<&[Selection<S>]>,
executor: &Executor<Self::Context, S>,
) -> ExecutionResult<S> {
resolve_into_list(executor, info, self.iter())
}
}
impl<S, T> GraphQLValueAsync<S> for Vec<T>
where
T: GraphQLValueAsync<S>,
T::TypeInfo: Sync,
T::Context: Sync,
S: ScalarValue + Send + Sync,
{
fn resolve_async<'a>(
&'a self,
info: &'a Self::TypeInfo,
_: Option<&'a [Selection<S>]>,
executor: &'a Executor<Self::Context, S>,
) -> crate::BoxFuture<'a, ExecutionResult<S>> {
let f = resolve_into_list_async(executor, info, self.iter());
Box::pin(f)
}
}
impl<T, S> FromInputValue<S> for Vec<T>
where
T: FromInputValue<S>,
S: ScalarValue,
{
fn from_input_value(v: &InputValue<S>) -> Option<Vec<T>>
where {
match *v {
InputValue::List(ref ls) => {
let v: Vec<_> = ls.iter().filter_map(|i| i.item.convert()).collect();
if v.len() == ls.len() {
Some(v)
} else {
None
}
}
ref other => other.convert().map(|e| vec![e]),
}
}
}
impl<T, S> ToInputValue<S> for Vec<T>
where
T: ToInputValue<S>,
S: ScalarValue,
{
fn to_input_value(&self) -> InputValue<S> {
InputValue::list(self.iter().map(T::to_input_value).collect())
}
}
impl<S, T> GraphQLType<S> for [T]
where
S: ScalarValue,
T: GraphQLType<S>,
{
fn name(_: &Self::TypeInfo) -> Option<&'static str> {
None
}
fn meta<'r>(info: &Self::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S>
where
S: 'r,
{
registry.build_list_type::<T>(info).into_meta()
}
}
impl<S, T> GraphQLValue<S> for [T]
where
S: ScalarValue,
T: GraphQLValue<S>,
{
type Context = T::Context;
type TypeInfo = T::TypeInfo;
fn type_name(&self, _: &Self::TypeInfo) -> Option<&'static str> {
None
}
fn resolve(
&self,
info: &Self::TypeInfo,
_: Option<&[Selection<S>]>,
executor: &Executor<Self::Context, S>,
) -> ExecutionResult<S> {
resolve_into_list(executor, info, self.iter())
}
}
impl<S, T> GraphQLValueAsync<S> for [T]
where
T: GraphQLValueAsync<S>,
T::TypeInfo: Sync,
T::Context: Sync,
S: ScalarValue + Send + Sync,
{
fn resolve_async<'a>(
&'a self,
info: &'a Self::TypeInfo,
_: Option<&'a [Selection<S>]>,
executor: &'a Executor<Self::Context, S>,
) -> crate::BoxFuture<'a, ExecutionResult<S>> {
let f = resolve_into_list_async(executor, info, self.iter());
Box::pin(f)
}
}
impl<'a, T, S> ToInputValue<S> for &'a [T]
where
T: ToInputValue<S>,
S: ScalarValue,
{
fn to_input_value(&self) -> InputValue<S> {
InputValue::list(self.iter().map(T::to_input_value).collect())
}
}
fn resolve_into_list<'t, S, T, I>(
executor: &Executor<T::Context, S>,
info: &T::TypeInfo,
iter: I,
) -> ExecutionResult<S>
where
S: ScalarValue,
I: Iterator<Item = &'t T> + ExactSizeIterator,
T: GraphQLValue<S> + ?Sized + 't,
{
let stop_on_null = executor
.current_type()
.list_contents()
.expect("Current type is not a list type")
.is_non_null();
let mut result = Vec::with_capacity(iter.len());
for o in iter {
let val = executor.resolve(info, o)?;
if stop_on_null && val.is_null() {
return Ok(val);
} else {
result.push(val)
}
}
Ok(Value::list(result))
}
async fn resolve_into_list_async<'a, 't, S, T, I>(
executor: &'a Executor<'a, 'a, T::Context, S>,
info: &'a T::TypeInfo,
items: I,
) -> ExecutionResult<S>
where
I: Iterator<Item = &'t T> + ExactSizeIterator,
T: GraphQLValueAsync<S> + ?Sized + 't,
T::TypeInfo: Sync,
T::Context: Sync,
S: ScalarValue + Send + Sync,
{
use futures::stream::{FuturesOrdered, StreamExt as _};
use std::iter::FromIterator;
let stop_on_null = executor
.current_type()
.list_contents()
.expect("Current type is not a list type")
.is_non_null();
let iter = items.map(|it| async move { executor.resolve_into_value_async(info, it).await });
let mut futures = FuturesOrdered::from_iter(iter);
let mut values = Vec::with_capacity(futures.len());
while let Some(value) = futures.next().await {
if stop_on_null && value.is_null() {
return Ok(value);
}
values.push(value);
}
Ok(Value::list(values))
}