use crate::context::QueryEnv; use crate::parser::types::{Selection, TypeCondition}; use crate::{Context, ContextSelectionSet, Response, Result, Schema, SchemaEnv, Type}; use futures::{Future, Stream}; use std::pin::Pin; /// Represents a GraphQL subscription object #[async_trait::async_trait] pub trait SubscriptionType: Type { /// This function returns true of type `EmptySubscription` only #[doc(hidden)] fn is_empty() -> bool { false } #[doc(hidden)] async fn create_field_stream( &self, ctx: &Context<'_>, schema_env: SchemaEnv, query_env: QueryEnv, ) -> Result + Send>>>; } type BoxCreateStreamFuture<'a> = Pin> + Send + 'a>>; pub(crate) fn create_subscription_stream<'a, Query, Mutation, Subscription>( schema: &'a Schema, environment: QueryEnv, ctx: &'a ContextSelectionSet<'_>, streams: &'a mut Vec + Send>>>, ) -> BoxCreateStreamFuture<'a> where Query: Send + Sync, Mutation: Send + Sync, Subscription: SubscriptionType + Send + Sync + 'static + Sized, { Box::pin(async move { for selection in &ctx.item.node.items { if ctx.is_skip(selection.node.directives())? { continue; } match &selection.node { Selection::Field(field) => streams.push( schema .subscription .create_field_stream( &ctx.with_field(field), schema.env.clone(), environment.clone(), ) .await?, ), Selection::FragmentSpread(fragment_spread) => { if let Some(fragment) = ctx .query_env .document .fragments .get(&fragment_spread.node.fragment_name.node) { create_subscription_stream( schema, environment.clone(), &ctx.with_selection_set(&fragment.node.selection_set), streams, ) .await?; } } Selection::InlineFragment(inline_fragment) => { if let Some(TypeCondition { on: name }) = inline_fragment .node .type_condition .as_ref() .map(|v| &v.node) { if name.node.as_str() == Subscription::type_name() { create_subscription_stream( schema, environment.clone(), &ctx.with_selection_set(&inline_fragment.node.selection_set), streams, ) .await?; } } else { create_subscription_stream( schema, environment.clone(), &ctx.with_selection_set(&inline_fragment.node.selection_set), streams, ) .await?; } } } } Ok(()) }) } #[async_trait::async_trait] impl SubscriptionType for &T { async fn create_field_stream( &self, ctx: &Context<'_>, schema_env: SchemaEnv, query_env: QueryEnv, ) -> Result + Send>>> { T::create_field_stream(*self, ctx, schema_env, query_env).await } }