From 3306f85a8ab46118da3606d72a40b6e0a4000367 Mon Sep 17 00:00:00 2001 From: Sunli Date: Thu, 28 Oct 2021 16:56:08 +0800 Subject: [PATCH] Subscription typename - [GraphQL - October 2021] #681 --- derive/src/merged_object.rs | 1 + derive/src/merged_subscription.rs | 1 + derive/src/object.rs | 2 ++ derive/src/simple_object.rs | 2 ++ derive/src/subscription.rs | 1 + src/registry/mod.rs | 3 +++ src/types/connection/connection_type.rs | 1 + src/types/connection/edge.rs | 1 + src/types/empty_mutation.rs | 1 + src/types/empty_subscription.rs | 1 + src/types/maybe_undefined.rs | 2 +- src/types/merged_object.rs | 1 + src/validation/rules/fields_on_correct_type.rs | 5 +++++ src/validation/test_harness.rs | 14 ++++++++++++-- src/validation/visitor.rs | 11 +++++++++++ 15 files changed, 44 insertions(+), 3 deletions(-) diff --git a/derive/src/merged_object.rs b/derive/src/merged_object.rs index f6ccc3fb..3ea5b313 100644 --- a/derive/src/merged_object.rs +++ b/derive/src/merged_object.rs @@ -90,6 +90,7 @@ pub fn generate(object_args: &args::MergedObject) -> GeneratorResult GeneratorResult GeneratorResult GeneratorResult>, visible: Option, + is_subscription: bool, }, Interface { name: String, @@ -375,6 +376,7 @@ impl Registry { extends: false, keys: None, visible: None, + is_subscription: false, }, ); let ty = f(self); @@ -508,6 +510,7 @@ impl Registry { extends: false, keys: None, visible: None, + is_subscription: false, }, ); diff --git a/src/types/connection/connection_type.rs b/src/types/connection/connection_type.rs index 9080004a..ff0193c6 100644 --- a/src/types/connection/connection_type.rs +++ b/src/types/connection/connection_type.rs @@ -190,6 +190,7 @@ where extends: false, keys: None, visible: None, + is_subscription: false, } }) } diff --git a/src/types/connection/edge.rs b/src/types/connection/edge.rs index f6c893bb..afa69142 100644 --- a/src/types/connection/edge.rs +++ b/src/types/connection/edge.rs @@ -107,6 +107,7 @@ where extends: false, keys: None, visible: None, + is_subscription: false, } }) } diff --git a/src/types/empty_mutation.rs b/src/types/empty_mutation.rs index 481a3cb5..da90a82c 100644 --- a/src/types/empty_mutation.rs +++ b/src/types/empty_mutation.rs @@ -45,6 +45,7 @@ impl Type for EmptyMutation { extends: false, keys: None, visible: None, + is_subscription: false, }) } } diff --git a/src/types/empty_subscription.rs b/src/types/empty_subscription.rs index 0c98e473..10d28950 100644 --- a/src/types/empty_subscription.rs +++ b/src/types/empty_subscription.rs @@ -25,6 +25,7 @@ impl Type for EmptySubscription { extends: false, keys: None, visible: None, + is_subscription: true, }) } } diff --git a/src/types/maybe_undefined.rs b/src/types/maybe_undefined.rs index 81a6048f..b9768cb3 100644 --- a/src/types/maybe_undefined.rs +++ b/src/types/maybe_undefined.rs @@ -6,7 +6,7 @@ use crate::{registry, InputType, InputValueError, InputValueResult, Type, Value} /// Similar to `Option`, but it has three states, `undefined`, `null` and `x`. /// -/// **Reference:** +/// **Reference:** /// /// # Examples /// diff --git a/src/types/merged_object.rs b/src/types/merged_object.rs index c3cb026c..7b236ee4 100644 --- a/src/types/merged_object.rs +++ b/src/types/merged_object.rs @@ -50,6 +50,7 @@ impl Type for MergedObject { extends: false, keys: None, visible: None, + is_subscription: false, } }) } diff --git a/src/validation/rules/fields_on_correct_type.rs b/src/validation/rules/fields_on_correct_type.rs index 343f75f9..1b4ad9ef 100644 --- a/src/validation/rules/fields_on_correct_type.rs +++ b/src/validation/rules/fields_on_correct_type.rs @@ -329,4 +329,9 @@ mod tests { "#, ); } + + #[test] + fn typename_in_subscription_root() { + expect_fails_rule!(factory, "subscription { __typename }"); + } } diff --git a/src/validation/test_harness.rs b/src/validation/test_harness.rs index 30bf611b..c691be7a 100644 --- a/src/validation/test_harness.rs +++ b/src/validation/test_harness.rs @@ -4,6 +4,7 @@ use once_cell::sync::Lazy; +use crate::futures_util::Stream; use crate::parser::types::ExecutableDocument; use crate::validation::visitor::{visit, RuleError, Visitor, VisitorContext}; use crate::*; @@ -345,8 +346,17 @@ impl MutationRoot { } } -static TEST_HARNESS: Lazy> = - Lazy::new(|| Schema::new(QueryRoot, MutationRoot, EmptySubscription)); +pub struct SubscriptionRoot; + +#[Subscription(internal)] +impl SubscriptionRoot { + async fn values(&self) -> impl Stream { + futures_util::stream::once(async move { 10 }) + } +} + +static TEST_HARNESS: Lazy> = + Lazy::new(|| Schema::new(QueryRoot, MutationRoot, SubscriptionRoot)); pub(crate) fn validate<'a, V, F>( doc: &'a ExecutableDocument, diff --git a/src/validation/visitor.rs b/src/validation/visitor.rs index 772d4518..0a6024c7 100644 --- a/src/validation/visitor.rs +++ b/src/validation/visitor.rs @@ -611,6 +611,17 @@ fn visit_selection<'a, V: Visitor<'a>>( visit_field(v, ctx, field); }, ); + } else if ctx.current_type().map(|ty| match ty { + MetaType::Object { + is_subscription, .. + } => *is_subscription, + _ => false, + }) == Some(true) + { + ctx.report_error( + vec![field.pos], + "Unknown field \"__typename\" on type \"Subscription\".", + ); } } Selection::FragmentSpread(fragment_spread) => {