use std::{borrow::Cow, pin::Pin}; use indexmap::IndexMap; use crate::{ futures_util::Stream, parser::types::Field, registry::{MetaType, MetaTypeId, Registry}, CacheControl, ContainerType, Context, ContextSelectionSet, OutputType, Positioned, Response, ServerResult, SimpleObject, SubscriptionType, Value, }; #[doc(hidden)] pub struct MergedObject(pub A, pub B); #[async_trait::async_trait] impl ContainerType for MergedObject where A: ContainerType, B: ContainerType, { async fn resolve_field(&self, ctx: &Context<'_>) -> ServerResult> { match self.0.resolve_field(ctx).await { Ok(Some(value)) => Ok(Some(value)), Ok(None) => self.1.resolve_field(ctx).await, Err(err) => Err(err), } } async fn find_entity(&self, ctx: &Context<'_>, params: &Value) -> ServerResult> { match self.0.find_entity(ctx, params).await { Ok(Some(value)) => Ok(Some(value)), Ok(None) => self.1.find_entity(ctx, params).await, Err(err) => Err(err), } } } #[async_trait::async_trait] impl OutputType for MergedObject where A: OutputType, B: OutputType, { 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_output_type::(MetaTypeId::Object, |registry| { let mut fields = IndexMap::new(); let mut cc = CacheControl::default(); if let MetaType::Object { fields: b_fields, cache_control: b_cc, .. } = registry.create_fake_output_type::() { fields.extend(b_fields); cc = cc.merge(&b_cc); } if let MetaType::Object { fields: a_fields, cache_control: a_cc, .. } = registry.create_fake_output_type::() { fields.extend(a_fields); cc = cc.merge(&a_cc); } MetaType::Object { name: Self::type_name().to_string(), description: None, fields, cache_control: cc, extends: false, keys: None, visible: None, is_subscription: false, rust_typename: std::any::type_name::(), } }) } async fn resolve( &self, _ctx: &ContextSelectionSet<'_>, _field: &Positioned, ) -> ServerResult { unreachable!() } } #[async_trait::async_trait] impl SubscriptionType for MergedObject where A: SubscriptionType, B: SubscriptionType, { 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_subscription_type::(|registry| { let mut fields = IndexMap::new(); let mut cc = CacheControl::default(); if let MetaType::Object { fields: b_fields, cache_control: b_cc, .. } = registry.create_fake_subscription_type::() { fields.extend(b_fields); cc = cc.merge(&b_cc); } if let MetaType::Object { fields: a_fields, cache_control: a_cc, .. } = registry.create_fake_subscription_type::() { fields.extend(a_fields); cc = cc.merge(&a_cc); } MetaType::Object { name: Self::type_name().to_string(), description: None, fields, cache_control: cc, extends: false, keys: None, visible: None, is_subscription: false, rust_typename: std::any::type_name::(), } }) } fn create_field_stream<'a>( &'a self, _ctx: &'a Context<'_>, ) -> Option + Send + 'a>>> { unreachable!() } } #[doc(hidden)] #[derive(SimpleObject, Default)] #[graphql(internal, fake)] pub struct MergedObjectTail; impl SubscriptionType for MergedObjectTail { fn type_name() -> Cow<'static, str> { Cow::Borrowed("MergedSubscriptionTail") } fn create_type_info(registry: &mut Registry) -> String { registry.create_subscription_type::(|_| MetaType::Object { name: "MergedSubscriptionTail".to_string(), description: None, fields: Default::default(), cache_control: Default::default(), extends: false, keys: None, visible: None, is_subscription: false, rust_typename: std::any::type_name::(), }) } fn create_field_stream<'a>( &'a self, _ctx: &'a Context<'_>, ) -> Option + Send + 'a>>> { unreachable!() } }