From 203af1ce98bc6877fad0c995107549bddbea828d Mon Sep 17 00:00:00 2001 From: Christian Legnitto Date: Tue, 5 Dec 2017 15:56:17 -0800 Subject: [PATCH] Support `__typename` for unions See http://graphql.org/learn/queries/#meta-fields. Fixes https://github.com/graphql-rust/juniper/issues/112. --- .../src/executor_tests/interfaces_unions.rs | 3 ++ .../rules/fields_on_correct_type.rs | 32 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/juniper/src/executor_tests/interfaces_unions.rs b/juniper/src/executor_tests/interfaces_unions.rs index 0b53e137..1ac2e1da 100644 --- a/juniper/src/executor_tests/interfaces_unions.rs +++ b/juniper/src/executor_tests/interfaces_unions.rs @@ -204,6 +204,7 @@ mod union { let doc = r" { pets { + __typename ... on Dog { name woofs @@ -228,10 +229,12 @@ mod union { Value::object(vec![ ("pets", Value::list(vec![ Value::object(vec![ + ("__typename", Value::string("Dog")), ("name", Value::string("Odie")), ("woofs", Value::boolean(true)), ].into_iter().collect()), Value::object(vec![ + ("__typename", Value::string("Cat")), ("name", Value::string("Garfield")), ("meows", Value::boolean(false)), ].into_iter().collect()), diff --git a/juniper/src/validation/rules/fields_on_correct_type.rs b/juniper/src/validation/rules/fields_on_correct_type.rs index a48e4ddd..d2918915 100644 --- a/juniper/src/validation/rules/fields_on_correct_type.rs +++ b/juniper/src/validation/rules/fields_on_correct_type.rs @@ -1,4 +1,5 @@ use ast::Field; +use schema::meta::MetaType; use validation::{ValidatorContext, Visitor}; use parser::Spanning; @@ -16,6 +17,19 @@ impl<'a> Visitor<'a> for FieldsOnCorrectType { let type_name = parent_type.name().unwrap_or(""); if parent_type.field_by_name(field_name.item).is_none() { + + match *parent_type { + MetaType::Union(..) => { + // You can query for `__typename` on a union, + // but it isn't a field on the union...it is + // instead on the resulting object returned. + if field_name.item == "__typename" { + return; + } + } + _ => {} + } + context.report_error( &error_message(field_name.item, type_name), &[field_name.start.clone()], @@ -318,6 +332,24 @@ mod tests { ); } + #[test] + fn typename_on_union() { + expect_passes_rule( + factory, + r#" + fragment objectFieldSelection on Pet { + __typename + ... on Dog { + name + } + ... on Cat { + name + } + } + "#, + ); + } + #[test] fn valid_field_in_inline_fragment() { expect_passes_rule(