Skip to content

Commit ddc1488

Browse files
authored
Codegen reimplementation for GraphQL unions (#666)
- reimplement #[derive(GraphQLUnion)] macro to support: - both structs and enums - generics in type definition - multiple #[graphql] attributes - external resolver functions - remove From trait impls generation for enum variants - reimplement #[graphql_union] macro to support: - traits - generics in trait definition - multiple attributes - external resolver functions - GraphQLType implemetation for a raw trait object - GraphQLTypeAsync implemetation (#549) - add marker::GraphQLUnion trait - rewrite "2.5 Unions" section in Book (Juniper user documentation) - rewrite `codegen` and `codegen_fail` integration tests for GraphQL unions Additionally: - re-export `futures` crate in `juniper` for convenient reuse in the generated code without requiring library user to provide `futures` crate by himself (#663) - use unit type () as default context for EmptyMutation and EmptySubscriptions - relax Sized trait bound on some GraphQLType and GraphQLTypeAsync definitions, implementations and usages
1 parent 31d0888 commit ddc1488

File tree

99 files changed

+5656
-1530
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

99 files changed

+5656
-1530
lines changed

docs/book/content/types/unions.md

+347-88
Large diffs are not rendered by default.

docs/book/tests/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ build = "build.rs"
99
juniper = { path = "../../../juniper" }
1010
juniper_iron = { path = "../../../juniper_iron" }
1111
juniper_subscriptions = { path = "../../../juniper_subscriptions" }
12+
13+
derive_more = "0.99.7"
1214
futures = "0.3"
1315
tokio = { version = "0.2", features = ["rt-core", "blocking", "stream", "rt-util"] }
1416
iron = "0.5.0"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
use juniper::graphql_union;
2+
3+
#[graphql_union]
4+
enum Character {}
5+
6+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
error: #[graphql_union] attribute is applicable to trait definitions only
2+
--> $DIR/attr_wrong_item.rs:3:1
3+
|
4+
3 | #[graphql_union]
5+
| ^^^^^^^^^^^^^^^^
6+
|
7+
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)

integration_tests/codegen_fail/fail/union/derive_enum_field.rs

-12
This file was deleted.

integration_tests/codegen_fail/fail/union/derive_enum_field.stderr

-8
This file was deleted.

integration_tests/codegen_fail/fail/union/derive_no_fields.rs

-4
This file was deleted.

integration_tests/codegen_fail/fail/union/derive_no_fields.stderr

-7
This file was deleted.

integration_tests/codegen_fail/fail/union/derive_same_type.stderr

-10
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
use juniper::GraphQLUnion;
2+
3+
#[derive(GraphQLUnion)]
4+
union Character { id: i32 }
5+
6+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
error: GraphQL union can only be derived for enums and structs
2+
--> $DIR/derive_wrong_item.rs:4:1
3+
|
4+
4 | union Character { id: i32 }
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
use juniper::{GraphQLObject, GraphQLUnion};
2+
3+
#[derive(GraphQLUnion)]
4+
#[graphql(on Human = resolve_fn1)]
5+
enum Character {
6+
#[graphql(with = resolve_fn2)]
7+
A(Human),
8+
}
9+
10+
#[derive(GraphQLObject)]
11+
pub struct Human {
12+
id: String,
13+
}
14+
15+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
error: GraphQL union variant `Human` already has external resolver function `resolve_fn1` declared on the enum
2+
--> $DIR/enum_external_resolver_fn_conflicts_with_variant_external_resolver_fn.rs:6:15
3+
|
4+
6 | #[graphql(with = resolve_fn2)]
5+
| ^^^^
6+
|
7+
= note: https://spec.graphql.org/June2018/#sec-Unions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use juniper::{GraphQLObject, GraphQLUnion};
2+
3+
#[derive(GraphQLUnion)]
4+
enum __Character {
5+
A(Human),
6+
}
7+
8+
#[derive(GraphQLObject)]
9+
pub struct Human {
10+
id: String,
11+
}
12+
13+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
error: All types and directives defined within a schema must not have a name which begins with `__` (two underscores), as this is used exclusively by GraphQL’s introspection system.
2+
--> $DIR/enum_name_double_underscored.rs:4:6
3+
|
4+
4 | enum __Character {
5+
| ^^^^^^^^^^^
6+
|
7+
= note: https://spec.graphql.org/June2018/#sec-Schema
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
use juniper::GraphQLUnion;
2+
3+
#[derive(GraphQLUnion)]
4+
enum Character {}
5+
6+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
error: GraphQL union expects at least one union variant
2+
--> $DIR/enum_no_fields.rs:4:1
3+
|
4+
4 | enum Character {}
5+
| ^^^^^^^^^^^^^^^^^
6+
|
7+
= note: https://spec.graphql.org/June2018/#sec-Unions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
use juniper::{GraphQLEnum, GraphQLUnion};
2+
3+
#[derive(GraphQLEnum)]
4+
pub enum Test {
5+
A,
6+
B,
7+
}
8+
9+
#[derive(GraphQLUnion)]
10+
enum Character {
11+
Test(Test),
12+
}
13+
14+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error[E0277]: the trait bound `Test: juniper::types::marker::GraphQLObjectType<juniper::value::scalar::DefaultScalarValue>` is not satisfied
2+
--> $DIR/enum_non_object_variant.rs:9:10
3+
|
4+
9 | #[derive(GraphQLUnion)]
5+
| ^^^^^^^^^^^^ the trait `juniper::types::marker::GraphQLObjectType<juniper::value::scalar::DefaultScalarValue>` is not implemented for `Test`
6+
|
7+
= note: required by `juniper::types::marker::GraphQLObjectType::mark`
8+
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
9+
10+
error[E0277]: the trait bound `Test: juniper::types::marker::GraphQLObjectType<__S>` is not satisfied
11+
--> $DIR/enum_non_object_variant.rs:9:10
12+
|
13+
9 | #[derive(GraphQLUnion)]
14+
| ^^^^^^^^^^^^ the trait `juniper::types::marker::GraphQLObjectType<__S>` is not implemented for `Test`
15+
|
16+
= note: required by `juniper::types::marker::GraphQLObjectType::mark`
17+
= note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use juniper::GraphQLUnion;
2+
3+
#[derive(GraphQLUnion)]
4+
enum Character {
5+
A(u8),
6+
B(u8),
7+
}
8+
9+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error: GraphQL union must have a different type for each union variant
2+
--> $DIR/enum_same_type_pretty.rs:4:1
3+
|
4+
4 | / enum Character {
5+
5 | | A(u8),
6+
6 | | B(u8),
7+
7 | | }
8+
| |_^
9+
|
10+
= note: https://spec.graphql.org/June2018/#sec-Unions

integration_tests/codegen_fail/fail/union/derive_same_type.rs renamed to integration_tests/codegen_fail/fail/union/enum_same_type_ugly.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
#[derive(juniper::GraphQLUnion)]
1+
use juniper::GraphQLUnion;
2+
3+
#[derive(GraphQLUnion)]
24
enum Character {
35
A(std::string::String),
46
B(String),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
error[E0119]: conflicting implementations of trait `<Character as juniper::types::marker::GraphQLUnion>::mark::_::{{closure}}#0::MutuallyExclusive` for type `std::string::String`:
2+
--> $DIR/enum_same_type_ugly.rs:3:10
3+
|
4+
3 | #[derive(GraphQLUnion)]
5+
| ^^^^^^^^^^^^
6+
| |
7+
| first implementation here
8+
| conflicting implementation for `std::string::String`
9+
|
10+
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use juniper::{GraphQLObject, GraphQLUnion};
2+
3+
#[derive(GraphQLUnion)]
4+
enum Character1 {
5+
A { human: Human },
6+
}
7+
8+
#[derive(GraphQLUnion)]
9+
enum Character2 {
10+
A(Human, u8),
11+
}
12+
13+
#[derive(GraphQLObject)]
14+
pub struct Human {
15+
id: String,
16+
}
17+
18+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: GraphQL union enum allows only unnamed variants with a single field, e.g. `Some(T)`
2+
--> $DIR/enum_wrong_variant_field.rs:5:5
3+
|
4+
5 | A { human: Human },
5+
| ^
6+
|
7+
= note: https://spec.graphql.org/June2018/#sec-Unions
8+
9+
error: GraphQL union enum allows only unnamed variants with a single field, e.g. `Some(T)`
10+
--> $DIR/enum_wrong_variant_field.rs:10:6
11+
|
12+
10 | A(Human, u8),
13+
| ^^^^^^^^^^^
14+
|
15+
= note: https://spec.graphql.org/June2018/#sec-Unions

integration_tests/codegen_fail/fail/union/impl_enum_field.rs

-23
This file was deleted.

integration_tests/codegen_fail/fail/union/impl_enum_field.stderr

-8
This file was deleted.

integration_tests/codegen_fail/fail/union/impl_no_fields.rs

-10
This file was deleted.

integration_tests/codegen_fail/fail/union/impl_no_fields.stderr

-9
This file was deleted.

integration_tests/codegen_fail/fail/union/impl_same_type.rs.disabled

-32
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use juniper::{GraphQLObject, GraphQLUnion};
2+
3+
#[derive(GraphQLUnion)]
4+
#[graphql(on Human = __Character::a)]
5+
struct __Character;
6+
7+
impl __Character {
8+
fn a(&self, _: &()) -> Option<&Human> {
9+
None
10+
}
11+
}
12+
13+
#[derive(GraphQLObject)]
14+
pub struct Human {
15+
id: String,
16+
}
17+
18+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
error: All types and directives defined within a schema must not have a name which begins with `__` (two underscores), as this is used exclusively by GraphQL’s introspection system.
2+
--> $DIR/struct_name_double_underscored.rs:5:8
3+
|
4+
5 | struct __Character;
5+
| ^^^^^^^^^^^
6+
|
7+
= note: https://spec.graphql.org/June2018/#sec-Schema
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
use juniper::GraphQLUnion;
2+
3+
#[derive(GraphQLUnion)]
4+
struct Character;
5+
6+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
error: GraphQL union expects at least one union variant
2+
--> $DIR/struct_no_fields.rs:4:1
3+
|
4+
4 | struct Character;
5+
| ^^^^^^^^^^^^^^^^^
6+
|
7+
= note: https://spec.graphql.org/June2018/#sec-Unions

0 commit comments

Comments
 (0)