diff --git a/integration_tests/codegen_fail/fail/union/enum_non_object_variant.stderr b/integration_tests/codegen_fail/fail/union/enum_non_object_variant.stderr index 1da87bdd8..add99e411 100644 --- a/integration_tests/codegen_fail/fail/union/enum_non_object_variant.stderr +++ b/integration_tests/codegen_fail/fail/union/enum_non_object_variant.stderr @@ -1,12 +1,3 @@ -error[E0277]: the trait bound `Test: juniper::types::marker::GraphQLObjectType` is not satisfied - --> $DIR/enum_non_object_variant.rs:9:10 - | -9 | #[derive(GraphQLUnion)] - | ^^^^^^^^^^^^ the trait `juniper::types::marker::GraphQLObjectType` is not implemented for `Test` - | - = note: required by `juniper::types::marker::GraphQLObjectType::mark` - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0277]: the trait bound `Test: juniper::types::marker::GraphQLObjectType<__S>` is not satisfied --> $DIR/enum_non_object_variant.rs:9:10 | diff --git a/integration_tests/codegen_fail/fail/union/enum_same_type_ugly.stderr b/integration_tests/codegen_fail/fail/union/enum_same_type_ugly.stderr index 236daf7f2..16a967e31 100644 --- a/integration_tests/codegen_fail/fail/union/enum_same_type_ugly.stderr +++ b/integration_tests/codegen_fail/fail/union/enum_same_type_ugly.stderr @@ -1,4 +1,4 @@ -error[E0119]: conflicting implementations of trait `::mark::_::{{closure}}#0::MutuallyExclusive` for type `std::string::String`: +error[E0119]: conflicting implementations of trait `>::mark::_::{{closure}}#0::MutuallyExclusive` for type `std::string::String`: --> $DIR/enum_same_type_ugly.rs:3:10 | 3 | #[derive(GraphQLUnion)] diff --git a/integration_tests/codegen_fail/fail/union/struct_non_object_variant.stderr b/integration_tests/codegen_fail/fail/union/struct_non_object_variant.stderr index 53d7ad7e5..ca3363722 100644 --- a/integration_tests/codegen_fail/fail/union/struct_non_object_variant.stderr +++ b/integration_tests/codegen_fail/fail/union/struct_non_object_variant.stderr @@ -1,12 +1,3 @@ -error[E0277]: the trait bound `Test: juniper::types::marker::GraphQLObjectType` is not satisfied - --> $DIR/struct_non_object_variant.rs:9:10 - | -9 | #[derive(GraphQLUnion)] - | ^^^^^^^^^^^^ the trait `juniper::types::marker::GraphQLObjectType` is not implemented for `Test` - | - = note: required by `juniper::types::marker::GraphQLObjectType::mark` - = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0277]: the trait bound `Test: juniper::types::marker::GraphQLObjectType<__S>` is not satisfied --> $DIR/struct_non_object_variant.rs:9:10 | diff --git a/integration_tests/codegen_fail/fail/union/struct_same_type_ugly.stderr b/integration_tests/codegen_fail/fail/union/struct_same_type_ugly.stderr index e901067c5..4babd863e 100644 --- a/integration_tests/codegen_fail/fail/union/struct_same_type_ugly.stderr +++ b/integration_tests/codegen_fail/fail/union/struct_same_type_ugly.stderr @@ -1,4 +1,4 @@ -error[E0119]: conflicting implementations of trait `::mark::_::{{closure}}#0::MutuallyExclusive` for type `std::string::String`: +error[E0119]: conflicting implementations of trait `>::mark::_::{{closure}}#0::MutuallyExclusive` for type `std::string::String`: --> $DIR/struct_same_type_ugly.rs:3:10 | 3 | #[derive(GraphQLUnion)] diff --git a/integration_tests/codegen_fail/fail/union/trait_non_object_variant.stderr b/integration_tests/codegen_fail/fail/union/trait_non_object_variant.stderr index 98e0193b3..a0940e829 100644 --- a/integration_tests/codegen_fail/fail/union/trait_non_object_variant.stderr +++ b/integration_tests/codegen_fail/fail/union/trait_non_object_variant.stderr @@ -1,12 +1,3 @@ -error[E0277]: the trait bound `Test: juniper::types::marker::GraphQLObjectType` is not satisfied - --> $DIR/trait_non_object_variant.rs:9:1 - | -9 | #[graphql_union] - | ^^^^^^^^^^^^^^^^ the trait `juniper::types::marker::GraphQLObjectType` is not implemented for `Test` - | - = note: required by `juniper::types::marker::GraphQLObjectType::mark` - = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0277]: the trait bound `Test: juniper::types::marker::GraphQLObjectType<__S>` is not satisfied --> $DIR/trait_non_object_variant.rs:9:1 | diff --git a/integration_tests/codegen_fail/fail/union/trait_same_type_ugly.stderr b/integration_tests/codegen_fail/fail/union/trait_same_type_ugly.stderr index 39684e76d..1b57de71b 100644 --- a/integration_tests/codegen_fail/fail/union/trait_same_type_ugly.stderr +++ b/integration_tests/codegen_fail/fail/union/trait_same_type_ugly.stderr @@ -1,4 +1,4 @@ -error[E0119]: conflicting implementations of trait `<(dyn Character + std::marker::Send + std::marker::Sync + '__obj) as juniper::types::marker::GraphQLUnion>::mark::_::{{closure}}#0::MutuallyExclusive` for type `std::string::String`: +error[E0119]: conflicting implementations of trait `<(dyn Character + std::marker::Send + std::marker::Sync + '__obj) as juniper::types::marker::GraphQLUnion<__S>>::mark::_::{{closure}}#0::MutuallyExclusive` for type `std::string::String`: --> $DIR/trait_same_type_ugly.rs:3:1 | 3 | #[graphql_union] diff --git a/integration_tests/juniper_tests/src/codegen/union_attr.rs b/integration_tests/juniper_tests/src/codegen/union_attr.rs index 7377dbea3..2581512cd 100644 --- a/integration_tests/juniper_tests/src/codegen/union_attr.rs +++ b/integration_tests/juniper_tests/src/codegen/union_attr.rs @@ -556,6 +556,97 @@ mod explicit_scalar { } } +mod custom_scalar { + use crate::custom_scalar::MyScalarValue; + + use super::*; + + #[graphql_union(scalar = MyScalarValue)] + trait Character { + fn as_human(&self) -> Option<&Human> { + None + } + fn as_droid(&self) -> Option<&Droid> { + None + } + } + + impl Character for Human { + fn as_human(&self) -> Option<&Human> { + Some(&self) + } + } + + impl Character for Droid { + fn as_droid(&self) -> Option<&Droid> { + Some(&self) + } + } + + type DynCharacter<'a> = dyn Character + Send + Sync + 'a; + + enum QueryRoot { + Human, + Droid, + } + + #[graphql_object(scalar = MyScalarValue)] + impl QueryRoot { + fn character(&self) -> Box> { + let ch: Box> = match self { + Self::Human => Box::new(Human { + id: "human-32".to_string(), + home_planet: "earth".to_string(), + }), + Self::Droid => Box::new(Droid { + id: "droid-99".to_string(), + primary_function: "run".to_string(), + }), + }; + ch + } + } + + const DOC: &str = r#"{ + character { + ... on Human { + humanId: id + homePlanet + } + ... on Droid { + droidId: id + primaryFunction + } + } + }"#; + + #[tokio::test] + async fn resolves_human() { + let schema = schema::<_, MyScalarValue, _>(QueryRoot::Human); + + assert_eq!( + execute(DOC, None, &schema, &Variables::new(), &()).await, + Ok(( + graphql_value!({"character": {"humanId": "human-32", "homePlanet": "earth"}}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_droid() { + let schema = schema::<_, MyScalarValue, _>(QueryRoot::Droid); + + assert_eq!( + execute(DOC, None, &schema, &Variables::new(), &()).await, + Ok(( + graphql_value!({"character": {"droidId": "droid-99", "primaryFunction": "run"}}), + vec![], + )), + ); + } +} + mod inferred_custom_context { use super::*; diff --git a/integration_tests/juniper_tests/src/codegen/union_derive.rs b/integration_tests/juniper_tests/src/codegen/union_derive.rs index 55d4c047a..655ca9954 100644 --- a/integration_tests/juniper_tests/src/codegen/union_derive.rs +++ b/integration_tests/juniper_tests/src/codegen/union_derive.rs @@ -485,6 +485,79 @@ mod explicit_scalar { } } +mod custom_scalar { + use crate::custom_scalar::MyScalarValue; + + use super::*; + + #[derive(GraphQLUnion)] + #[graphql(scalar = MyScalarValue)] + enum Character { + A(Human), + B(Droid), + } + + enum QueryRoot { + Human, + Droid, + } + + #[graphql_object(scalar = MyScalarValue)] + impl QueryRoot { + fn character(&self) -> Character { + match self { + Self::Human => Character::A(Human { + id: "human-32".to_string(), + home_planet: "earth".to_string(), + }), + Self::Droid => Character::B(Droid { + id: "droid-99".to_string(), + primary_function: "run".to_string(), + }), + } + } + } + + const DOC: &str = r#"{ + character { + ... on Human { + humanId: id + homePlanet + } + ... on Droid { + droidId: id + primaryFunction + } + } + }"#; + + #[tokio::test] + async fn resolves_human() { + let schema = schema::<_, MyScalarValue, _>(QueryRoot::Human); + + assert_eq!( + execute(DOC, None, &schema, &Variables::new(), &()).await, + Ok(( + graphql_value!({"character": {"humanId": "human-32", "homePlanet": "earth"}}), + vec![], + )), + ); + } + + #[tokio::test] + async fn resolves_droid() { + let schema = schema::<_, MyScalarValue, _>(QueryRoot::Droid); + + assert_eq!( + execute(DOC, None, &schema, &Variables::new(), &()).await, + Ok(( + graphql_value!({"character": {"droidId": "droid-99", "primaryFunction": "run"}}), + vec![], + )), + ); + } +} + mod custom_context { use super::*; diff --git a/integration_tests/juniper_tests/src/custom_scalar.rs b/integration_tests/juniper_tests/src/custom_scalar.rs index 4d14e1352..cc17169e5 100644 --- a/integration_tests/juniper_tests/src/custom_scalar.rs +++ b/integration_tests/juniper_tests/src/custom_scalar.rs @@ -10,7 +10,7 @@ use juniper::{ use std::fmt; #[derive(Debug, Clone, PartialEq, juniper::GraphQLScalarValue)] -enum MyScalarValue { +pub(crate) enum MyScalarValue { Int(i32), Long(i64), Float(f64), @@ -59,7 +59,7 @@ impl ScalarValue for MyScalarValue { } #[derive(Default, Debug)] -struct MyScalarValueVisitor; +pub(crate) struct MyScalarValueVisitor; impl<'de> de::Visitor<'de> for MyScalarValueVisitor { type Value = MyScalarValue; diff --git a/juniper/src/types/marker.rs b/juniper/src/types/marker.rs index 5e2fc909e..24d4b58f0 100644 --- a/juniper/src/types/marker.rs +++ b/juniper/src/types/marker.rs @@ -37,7 +37,7 @@ pub trait GraphQLObjectType: GraphQLType { /// [4]: https://spec.graphql.org/June2018/#sec-Objects /// [5]: https://spec.graphql.org/June2018/#sec-Input-Objects /// [6]: https://spec.graphql.org/June2018/#sec-Interfaces -pub trait GraphQLUnion: GraphQLType { +pub trait GraphQLUnion: GraphQLType { /// An arbitrary function without meaning. /// /// May contain compile timed check logic which ensures that types are used correctly according diff --git a/juniper_codegen/src/graphql_union/mod.rs b/juniper_codegen/src/graphql_union/mod.rs index 2d8132c28..af06d112a 100644 --- a/juniper_codegen/src/graphql_union/mod.rs +++ b/juniper_codegen/src/graphql_union/mod.rs @@ -414,11 +414,6 @@ impl ToTokens for UnionDefinition { .as_ref() .map(|scl| quote! { #scl }) .unwrap_or_else(|| quote! { __S }); - let default_scalar = self - .scalar - .as_ref() - .map(|scl| quote! { #scl }) - .unwrap_or_else(|| quote! { #crate_path::DefaultScalarValue }); let description = self .description @@ -493,13 +488,10 @@ impl ToTokens for UnionDefinition { let (_, ty_generics, _) = self.generics.split_for_impl(); - let mut base_generics = self.generics.clone(); + let mut ext_generics = self.generics.clone(); if self.is_trait_object { - base_generics.params.push(parse_quote! { '__obj }); + ext_generics.params.push(parse_quote! { '__obj }); } - let (impl_generics, _, _) = base_generics.split_for_impl(); - - let mut ext_generics = base_generics.clone(); if self.scalar.is_none() { ext_generics.params.push(parse_quote! { #scalar }); ext_generics @@ -618,13 +610,13 @@ impl ToTokens for UnionDefinition { let union_impl = quote! { #[automatically_derived] - impl#impl_generics #crate_path::marker::GraphQLUnion for #ty_full { + impl#ext_impl_generics #crate_path::marker::GraphQLUnion<#scalar> for #ty_full + #where_clause + { fn mark() { #all_variants_unique - #( <#var_types as #crate_path::marker::GraphQLObjectType< - #default_scalar, - >>::mark(); )* + #( <#var_types as #crate_path::marker::GraphQLObjectType<#scalar>>::mark(); )* } } };