Skip to content

fix unions with custom scalar values #681

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
error[E0277]: the trait bound `Test: juniper::types::marker::GraphQLObjectType<juniper::value::scalar::DefaultScalarValue>` is not satisfied
--> $DIR/enum_non_object_variant.rs:9:10
|
9 | #[derive(GraphQLUnion)]
| ^^^^^^^^^^^^ the trait `juniper::types::marker::GraphQLObjectType<juniper::value::scalar::DefaultScalarValue>` 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
|
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0119]: conflicting implementations of trait `<Character as juniper::types::marker::GraphQLUnion>::mark::_::{{closure}}#0::MutuallyExclusive` for type `std::string::String`:
error[E0119]: conflicting implementations of trait `<Character as juniper::types::marker::GraphQLUnion<__S>>::mark::_::{{closure}}#0::MutuallyExclusive` for type `std::string::String`:
--> $DIR/enum_same_type_ugly.rs:3:10
|
3 | #[derive(GraphQLUnion)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
error[E0277]: the trait bound `Test: juniper::types::marker::GraphQLObjectType<juniper::value::scalar::DefaultScalarValue>` is not satisfied
--> $DIR/struct_non_object_variant.rs:9:10
|
9 | #[derive(GraphQLUnion)]
| ^^^^^^^^^^^^ the trait `juniper::types::marker::GraphQLObjectType<juniper::value::scalar::DefaultScalarValue>` 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
|
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0119]: conflicting implementations of trait `<Character as juniper::types::marker::GraphQLUnion>::mark::_::{{closure}}#0::MutuallyExclusive` for type `std::string::String`:
error[E0119]: conflicting implementations of trait `<Character as juniper::types::marker::GraphQLUnion<__S>>::mark::_::{{closure}}#0::MutuallyExclusive` for type `std::string::String`:
--> $DIR/struct_same_type_ugly.rs:3:10
|
3 | #[derive(GraphQLUnion)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
error[E0277]: the trait bound `Test: juniper::types::marker::GraphQLObjectType<juniper::value::scalar::DefaultScalarValue>` is not satisfied
--> $DIR/trait_non_object_variant.rs:9:1
|
9 | #[graphql_union]
| ^^^^^^^^^^^^^^^^ the trait `juniper::types::marker::GraphQLObjectType<juniper::value::scalar::DefaultScalarValue>` 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
|
Expand Down
Original file line number Diff line number Diff line change
@@ -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]
Expand Down
91 changes: 91 additions & 0 deletions integration_tests/juniper_tests/src/codegen/union_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<DynCharacter<'_>> {
let ch: Box<DynCharacter<'_>> = 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::*;

Expand Down
73 changes: 73 additions & 0 deletions integration_tests/juniper_tests/src/codegen/union_derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;

Expand Down
4 changes: 2 additions & 2 deletions integration_tests/juniper_tests/src/custom_scalar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion juniper/src/types/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub trait GraphQLObjectType<S: ScalarValue>: GraphQLType<S> {
/// [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<S: ScalarValue>: GraphQLType<S> {
/// An arbitrary function without meaning.
///
/// May contain compile timed check logic which ensures that types are used correctly according
Expand Down
20 changes: 6 additions & 14 deletions juniper_codegen/src/graphql_union/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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(); )*
}
}
};
Expand Down