2020-09-06 06:16:36 +00:00
|
|
|
use crate::parser::types::Field;
|
2020-08-09 04:35:15 +00:00
|
|
|
use crate::registry::{MetaType, Registry};
|
2020-09-12 09:29:52 +00:00
|
|
|
use crate::resolver_utils::{resolve_object, ObjectType};
|
2020-08-09 04:35:15 +00:00
|
|
|
use crate::{
|
2020-09-13 03:41:15 +00:00
|
|
|
CacheControl, Context, ContextSelectionSet, Error, GQLSimpleObject, GQLSubscription,
|
2020-09-14 01:46:22 +00:00
|
|
|
OutputValueType, Positioned, QueryError, Result, SubscriptionType, Type,
|
2020-08-09 04:35:15 +00:00
|
|
|
};
|
2020-09-14 01:46:22 +00:00
|
|
|
use futures::{future::Either, stream, Stream, StreamExt};
|
2020-08-09 04:35:15 +00:00
|
|
|
use indexmap::IndexMap;
|
|
|
|
use std::borrow::Cow;
|
2020-08-27 07:35:48 +00:00
|
|
|
use std::pin::Pin;
|
2020-08-09 04:35:15 +00:00
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub struct MergedObject<A, B>(pub A, pub B);
|
|
|
|
|
2020-08-10 02:47:30 +00:00
|
|
|
impl<A, B> Default for MergedObject<A, B>
|
|
|
|
where
|
|
|
|
A: Default,
|
|
|
|
B: Default,
|
|
|
|
{
|
|
|
|
fn default() -> Self {
|
|
|
|
Self(A::default(), B::default())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-27 07:35:48 +00:00
|
|
|
impl<A: Type, B: Type> Type for MergedObject<A, B> {
|
2020-08-09 04:35:15 +00:00
|
|
|
fn type_name() -> Cow<'static, str> {
|
|
|
|
Cow::Owned(format!("{}_{}", A::type_name(), B::type_name()))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn create_type_info(registry: &mut Registry) -> String {
|
|
|
|
registry.create_type::<Self, _>(|registry| {
|
|
|
|
let mut fields = IndexMap::new();
|
|
|
|
let mut cc = CacheControl::default();
|
|
|
|
|
2020-08-10 02:47:30 +00:00
|
|
|
A::create_type_info(registry);
|
2020-08-09 04:35:15 +00:00
|
|
|
if let Some(MetaType::Object {
|
|
|
|
fields: a_fields,
|
|
|
|
cache_control: a_cc,
|
|
|
|
..
|
|
|
|
}) = registry.types.remove(&*A::type_name())
|
|
|
|
{
|
|
|
|
fields.extend(a_fields);
|
|
|
|
cc.merge(&a_cc);
|
|
|
|
}
|
|
|
|
|
2020-08-10 02:47:30 +00:00
|
|
|
B::create_type_info(registry);
|
2020-08-09 04:35:15 +00:00
|
|
|
if let Some(MetaType::Object {
|
|
|
|
fields: b_fields,
|
|
|
|
cache_control: b_cc,
|
|
|
|
..
|
|
|
|
}) = registry.types.remove(&*B::type_name())
|
|
|
|
{
|
|
|
|
fields.extend(b_fields);
|
|
|
|
cc.merge(&b_cc);
|
|
|
|
}
|
|
|
|
|
|
|
|
MetaType::Object {
|
|
|
|
name: Self::type_name().to_string(),
|
|
|
|
description: None,
|
|
|
|
fields,
|
|
|
|
cache_control: cc,
|
|
|
|
extends: false,
|
|
|
|
keys: None,
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[async_trait::async_trait]
|
|
|
|
impl<A, B> ObjectType for MergedObject<A, B>
|
|
|
|
where
|
|
|
|
A: ObjectType + Send + Sync,
|
|
|
|
B: ObjectType + Send + Sync,
|
|
|
|
{
|
|
|
|
async fn resolve_field(&self, ctx: &Context<'_>) -> Result<serde_json::Value> {
|
|
|
|
match self.0.resolve_field(ctx).await {
|
|
|
|
Ok(value) => Ok(value),
|
|
|
|
Err(Error::Query {
|
|
|
|
err: QueryError::FieldNotFound { .. },
|
|
|
|
..
|
|
|
|
}) => self.1.resolve_field(ctx).await,
|
|
|
|
Err(err) => Err(err),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[async_trait::async_trait]
|
|
|
|
impl<A, B> OutputValueType for MergedObject<A, B>
|
|
|
|
where
|
|
|
|
A: ObjectType + Send + Sync,
|
|
|
|
B: ObjectType + Send + Sync,
|
|
|
|
{
|
|
|
|
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-08-09 04:35:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-27 07:35:48 +00:00
|
|
|
impl<A, B> SubscriptionType for MergedObject<A, B>
|
|
|
|
where
|
|
|
|
A: SubscriptionType + Send + Sync,
|
|
|
|
B: SubscriptionType + Send + Sync,
|
|
|
|
{
|
2020-09-13 17:52:36 +00:00
|
|
|
fn create_field_stream<'a>(
|
|
|
|
&'a self,
|
|
|
|
ctx: &'a Context<'a>,
|
|
|
|
) -> Pin<Box<dyn Stream<Item = Result<serde_json::Value>> + Send + 'a>> {
|
|
|
|
let left_stream = self.0.create_field_stream(ctx);
|
|
|
|
let mut right_stream = Some(self.1.create_field_stream(ctx));
|
2020-09-14 01:46:22 +00:00
|
|
|
Box::pin(left_stream.flat_map(move |res| match res {
|
|
|
|
Err(Error::Query {
|
|
|
|
err: QueryError::FieldNotFound { .. },
|
|
|
|
..
|
|
|
|
}) if right_stream.is_some() => Either::Right(right_stream.take().unwrap()),
|
|
|
|
other => Either::Left(stream::once(async { other })),
|
|
|
|
}))
|
2020-08-27 07:35:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-09 04:35:15 +00:00
|
|
|
#[doc(hidden)]
|
2020-09-13 03:41:15 +00:00
|
|
|
#[derive(GQLSimpleObject, Default)]
|
|
|
|
#[graphql(internal)]
|
2020-08-09 04:35:15 +00:00
|
|
|
pub struct MergedObjectTail;
|
2020-08-27 07:35:48 +00:00
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
#[derive(Default)]
|
|
|
|
pub struct MergedObjectSubscriptionTail;
|
|
|
|
|
2020-09-13 03:41:15 +00:00
|
|
|
#[GQLSubscription(internal)]
|
2020-08-27 07:35:48 +00:00
|
|
|
impl MergedObjectSubscriptionTail {}
|