Deprecate graphql_object! and replace with impl_object
This commit deprecates the graphql_object macro and replaces all of it's uses with the new impl_object proc macro. (Except for the old macro tests). This commit also adds new integration tests for impl_object.
This commit is contained in:
parent
758f3f7d40
commit
a993c16b85
27 changed files with 1218 additions and 526 deletions
juniper
CHANGELOG.mdCargo.toml
src
executor_tests
integrations
macros
parser/tests
schema
tests
types
|
@ -1,10 +1,27 @@
|
||||||
# master
|
# master
|
||||||
|
|
||||||
- Refactored all crates to the 2018 edition. [#345](https://github.com/graphql-rust/juniper/pull/345)
|
### impl_object macro
|
||||||
|
|
||||||
|
The `graphql_object!` macro is deprecated and will be removed in the future.
|
||||||
|
It is replaced by the new [impl_object](https://docs.rs/juniper/latest/juniper/macro.impl_object.html) procedural macro.
|
||||||
|
|
||||||
|
[#333](https://github.com/graphql-rust/juniper/pull/333)
|
||||||
|
|
||||||
|
### 2018 Edition
|
||||||
|
|
||||||
|
All crates were refactored to the Rust 2018 edition.
|
||||||
|
|
||||||
|
This should not have any impact on your code, since juniper already was 2018 compatible.
|
||||||
|
|
||||||
|
[#345](https://github.com/graphql-rust/juniper/pull/345)
|
||||||
|
|
||||||
|
### Other changes
|
||||||
|
|
||||||
- The minimum required Rust version is now `1.31.0`.
|
- The minimum required Rust version is now `1.31.0`.
|
||||||
- The `ScalarValue` custom derive has been renamed to `GraphQLScalarValue`.
|
- The `ScalarValue` custom derive has been renamed to `GraphQLScalarValue`.
|
||||||
- Added built-in support for the canonical schema introspection query via
|
- Added built-in support for the canonical schema introspection query via
|
||||||
`juniper::introspect()`. [#307](https://github.com/graphql-rust/juniper/issues/307)
|
`juniper::introspect()`.
|
||||||
|
[#307](https://github.com/graphql-rust/juniper/issues/307)
|
||||||
- Fix introspection query validity
|
- Fix introspection query validity
|
||||||
The DirectiveLocation::InlineFragment had an invalid literal value,
|
The DirectiveLocation::InlineFragment had an invalid literal value,
|
||||||
which broke third party tools like apollo cli.
|
which broke third party tools like apollo cli.
|
||||||
|
|
|
@ -23,7 +23,6 @@ harness = false
|
||||||
path = "benches/bench.rs"
|
path = "benches/bench.rs"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
nightly = []
|
|
||||||
expose-test-schema = []
|
expose-test-schema = []
|
||||||
default = [
|
default = [
|
||||||
"chrono",
|
"chrono",
|
||||||
|
|
|
@ -5,15 +5,16 @@ use crate::value::{DefaultScalarValue, Object, Value};
|
||||||
|
|
||||||
struct TestType;
|
struct TestType;
|
||||||
|
|
||||||
graphql_object!(TestType: () |&self| {
|
#[crate::impl_object_internal]
|
||||||
field a() -> &str {
|
impl TestType {
|
||||||
|
fn a() -> &str {
|
||||||
"a"
|
"a"
|
||||||
}
|
}
|
||||||
|
|
||||||
field b() -> &str {
|
fn b() -> &str {
|
||||||
"b"
|
"b"
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
fn run_variable_query<F>(query: &str, vars: Variables<DefaultScalarValue>, f: F)
|
fn run_variable_query<F>(query: &str, vars: Variables<DefaultScalarValue>, f: F)
|
||||||
where
|
where
|
||||||
|
|
|
@ -17,15 +17,16 @@ enum Color {
|
||||||
}
|
}
|
||||||
struct TestType;
|
struct TestType;
|
||||||
|
|
||||||
graphql_object!(TestType: () |&self| {
|
#[crate::impl_object_internal]
|
||||||
field to_string(color: Color) -> String {
|
impl TestType {
|
||||||
|
fn to_string(color: Color) -> String {
|
||||||
format!("Color::{:?}", color)
|
format!("Color::{:?}", color)
|
||||||
}
|
}
|
||||||
|
|
||||||
field a_color() -> Color {
|
fn a_color() -> Color {
|
||||||
Color::Red
|
Color::Red
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
fn run_variable_query<F>(query: &str, vars: Variables<DefaultScalarValue>, f: F)
|
fn run_variable_query<F>(query: &str, vars: Variables<DefaultScalarValue>, f: F)
|
||||||
where
|
where
|
||||||
|
|
|
@ -7,34 +7,57 @@ mod field_execution {
|
||||||
struct DataType;
|
struct DataType;
|
||||||
struct DeepDataType;
|
struct DeepDataType;
|
||||||
|
|
||||||
graphql_object!(DataType: () |&self| {
|
#[crate::impl_object_internal]
|
||||||
field a() -> &str { "Apple" }
|
impl DataType {
|
||||||
field b() -> &str { "Banana" }
|
fn a() -> &str {
|
||||||
field c() -> &str { "Cookie" }
|
"Apple"
|
||||||
field d() -> &str { "Donut" }
|
}
|
||||||
field e() -> &str { "Egg" }
|
fn b() -> &str {
|
||||||
field f() -> &str { "Fish" }
|
"Banana"
|
||||||
|
}
|
||||||
|
fn c() -> &str {
|
||||||
|
"Cookie"
|
||||||
|
}
|
||||||
|
fn d() -> &str {
|
||||||
|
"Donut"
|
||||||
|
}
|
||||||
|
fn e() -> &str {
|
||||||
|
"Egg"
|
||||||
|
}
|
||||||
|
fn f() -> &str {
|
||||||
|
"Fish"
|
||||||
|
}
|
||||||
|
|
||||||
field pic(size: Option<i32>) -> String {
|
fn pic(size: Option<i32>) -> String {
|
||||||
format!("Pic of size: {}", size.unwrap_or(50))
|
format!("Pic of size: {}", size.unwrap_or(50))
|
||||||
}
|
}
|
||||||
|
|
||||||
field deep() -> DeepDataType {
|
fn deep() -> DeepDataType {
|
||||||
DeepDataType
|
DeepDataType
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
graphql_object!(DeepDataType: () |&self| {
|
#[crate::impl_object_internal]
|
||||||
field a() -> &str { "Already Been Done" }
|
impl DeepDataType {
|
||||||
field b() -> &str { "Boring" }
|
fn a() -> &str {
|
||||||
field c() -> Vec<Option<&str>> { vec![Some("Contrived"), None, Some("Confusing")] }
|
"Already Been Done"
|
||||||
|
}
|
||||||
|
fn b() -> &str {
|
||||||
|
"Boring"
|
||||||
|
}
|
||||||
|
fn c() -> Vec<Option<&str>> {
|
||||||
|
vec![Some("Contrived"), None, Some("Confusing")]
|
||||||
|
}
|
||||||
|
|
||||||
field deeper() -> Vec<Option<DataType>> { vec![Some(DataType), None, Some(DataType) ] }
|
fn deeper() -> Vec<Option<DataType>> {
|
||||||
});
|
vec![Some(DataType), None, Some(DataType)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test() {
|
fn test() {
|
||||||
let schema = RootNode::new(DataType, EmptyMutation::<()>::new());
|
let schema =
|
||||||
|
RootNode::<_, _, crate::DefaultScalarValue>::new(DataType, EmptyMutation::<()>::new());
|
||||||
let doc = r"
|
let doc = r"
|
||||||
query Example($size: Int) {
|
query Example($size: Int) {
|
||||||
a,
|
a,
|
||||||
|
@ -139,12 +162,21 @@ mod merge_parallel_fragments {
|
||||||
|
|
||||||
struct Type;
|
struct Type;
|
||||||
|
|
||||||
graphql_object!(Type: () |&self| {
|
#[crate::impl_object_internal]
|
||||||
field a() -> &str { "Apple" }
|
impl Type {
|
||||||
field b() -> &str { "Banana" }
|
fn a() -> &str {
|
||||||
field c() -> &str { "Cherry" }
|
"Apple"
|
||||||
field deep() -> Type { Type }
|
}
|
||||||
});
|
fn b() -> &str {
|
||||||
|
"Banana"
|
||||||
|
}
|
||||||
|
fn c() -> &str {
|
||||||
|
"Cherry"
|
||||||
|
}
|
||||||
|
fn deep() -> Type {
|
||||||
|
Type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test() {
|
fn test() {
|
||||||
|
@ -214,21 +246,43 @@ mod merge_parallel_inline_fragments {
|
||||||
struct Type;
|
struct Type;
|
||||||
struct Other;
|
struct Other;
|
||||||
|
|
||||||
graphql_object!(Type: () |&self| {
|
#[crate::impl_object_internal]
|
||||||
field a() -> &str { "Apple" }
|
impl Type {
|
||||||
field b() -> &str { "Banana" }
|
fn a() -> &str {
|
||||||
field c() -> &str { "Cherry" }
|
"Apple"
|
||||||
field deep() -> Type { Type }
|
}
|
||||||
field other() -> Vec<Other> { vec![Other, Other] }
|
fn b() -> &str {
|
||||||
});
|
"Banana"
|
||||||
|
}
|
||||||
|
fn c() -> &str {
|
||||||
|
"Cherry"
|
||||||
|
}
|
||||||
|
fn deep() -> Type {
|
||||||
|
Type
|
||||||
|
}
|
||||||
|
fn other() -> Vec<Other> {
|
||||||
|
vec![Other, Other]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
graphql_object!(Other: () |&self| {
|
#[crate::impl_object_internal]
|
||||||
field a() -> &str { "Apple" }
|
impl Other {
|
||||||
field b() -> &str { "Banana" }
|
fn a() -> &str {
|
||||||
field c() -> &str { "Cherry" }
|
"Apple"
|
||||||
field deep() -> Type { Type }
|
}
|
||||||
field other() -> Vec<Other> { vec![Other, Other] }
|
fn b() -> &str {
|
||||||
});
|
"Banana"
|
||||||
|
}
|
||||||
|
fn c() -> &str {
|
||||||
|
"Cherry"
|
||||||
|
}
|
||||||
|
fn deep() -> Type {
|
||||||
|
Type
|
||||||
|
}
|
||||||
|
fn other() -> Vec<Other> {
|
||||||
|
vec![Other, Other]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test() {
|
fn test() {
|
||||||
|
@ -342,9 +396,14 @@ mod threads_context_correctly {
|
||||||
|
|
||||||
impl Context for TestContext {}
|
impl Context for TestContext {}
|
||||||
|
|
||||||
graphql_object!(Schema: TestContext |&self| {
|
#[crate::impl_object_internal(
|
||||||
field a(&executor) -> String { executor.context().value.clone() }
|
Context = TestContext,
|
||||||
});
|
)]
|
||||||
|
impl Schema {
|
||||||
|
fn a(context: &TestContext) -> String {
|
||||||
|
context.value.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test() {
|
fn test() {
|
||||||
|
@ -403,36 +462,42 @@ mod dynamic_context_switching {
|
||||||
|
|
||||||
struct ItemRef;
|
struct ItemRef;
|
||||||
|
|
||||||
graphql_object!(Schema: OuterContext |&self| {
|
#[crate::impl_object_internal(Context = OuterContext)]
|
||||||
field item_opt(&executor, key: i32) -> Option<(&InnerContext, ItemRef)> {
|
impl Schema {
|
||||||
|
fn item_opt(context: &OuterContext, key: i32) -> Option<(&InnerContext, ItemRef)> {
|
||||||
executor.context().items.get(&key).map(|c| (c, ItemRef))
|
executor.context().items.get(&key).map(|c| (c, ItemRef))
|
||||||
}
|
}
|
||||||
|
|
||||||
field item_res(&executor, key: i32) -> FieldResult<(&InnerContext, ItemRef)> {
|
fn item_res(context: &OuterContext, key: i32) -> FieldResult<(&InnerContext, ItemRef)> {
|
||||||
let res = executor.context().items.get(&key)
|
let res = context
|
||||||
|
.items
|
||||||
|
.get(&key)
|
||||||
.ok_or(format!("Could not find key {}", key))
|
.ok_or(format!("Could not find key {}", key))
|
||||||
.map(|c| (c, ItemRef))?;
|
.map(|c| (c, ItemRef))?;
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
field item_res_opt(&executor, key: i32) -> FieldResult<Option<(&InnerContext, ItemRef)>> {
|
fn item_res_opt(
|
||||||
|
context: &OuterContext,
|
||||||
|
key: i32,
|
||||||
|
) -> FieldResult<Option<(&InnerContext, ItemRef)>> {
|
||||||
if key > 100 {
|
if key > 100 {
|
||||||
Err(format!("Key too large: {}", key))?;
|
Err(format!("Key too large: {}", key))?;
|
||||||
}
|
}
|
||||||
Ok(executor.context().items.get(&key)
|
Ok(context.items.get(&key).map(|c| (c, ItemRef)))
|
||||||
.map(|c| (c, ItemRef)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
field item_always(&executor, key: i32) -> (&InnerContext, ItemRef) {
|
fn item_always(context: &OuterContext, key: i32) -> (&InnerContext, ItemRef) {
|
||||||
executor.context().items.get(&key)
|
context.items.get(&key).map(|c| (c, ItemRef)).unwrap()
|
||||||
.map(|c| (c, ItemRef))
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
graphql_object!(ItemRef: InnerContext |&self| {
|
#[crate::impl_object_internal(Context = InnerContext)]
|
||||||
field value(&executor) -> String { executor.context().value.clone() }
|
impl ItemRef {
|
||||||
});
|
fn value(context: &InnerContext) -> String {
|
||||||
|
context.value.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_opt() {
|
fn test_opt() {
|
||||||
|
@ -736,19 +801,37 @@ mod propagates_errors_to_nullable_fields {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
graphql_object!(Schema: () |&self| {
|
#[crate::impl_object_internal]
|
||||||
field inner() -> Inner { Inner }
|
impl Schema {
|
||||||
field inners() -> Vec<Inner> { (0..5).map(|_| Inner).collect() }
|
fn inner() -> Inner {
|
||||||
field nullable_inners() -> Vec<Option<Inner>> { (0..5).map(|_| Some(Inner)).collect() }
|
Inner
|
||||||
});
|
}
|
||||||
|
fn inners() -> Vec<Inner> {
|
||||||
|
(0..5).map(|_| Inner).collect()
|
||||||
|
}
|
||||||
|
fn nullable_inners() -> Vec<Option<Inner>> {
|
||||||
|
(0..5).map(|_| Some(Inner)).collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
graphql_object!(Inner: () |&self| {
|
#[crate::impl_object_internal]
|
||||||
field nullable_field() -> Option<Inner> { Some(Inner) }
|
impl Inner {
|
||||||
field non_nullable_field() -> Inner { Inner }
|
fn nullable_field() -> Option<Inner> {
|
||||||
field nullable_error_field() -> FieldResult<Option<&str>> { Err("Error for nullableErrorField")? }
|
Some(Inner)
|
||||||
field non_nullable_error_field() -> FieldResult<&str> { Err("Error for nonNullableErrorField")? }
|
}
|
||||||
field custom_error_field() -> Result<&str, CustomError> { Err(CustomError::NotFound) }
|
fn non_nullable_field() -> Inner {
|
||||||
});
|
Inner
|
||||||
|
}
|
||||||
|
fn nullable_error_field() -> FieldResult<Option<&str>> {
|
||||||
|
Err("Error for nullableErrorField")?
|
||||||
|
}
|
||||||
|
fn non_nullable_error_field() -> FieldResult<&str> {
|
||||||
|
Err("Error for nonNullableErrorField")?
|
||||||
|
}
|
||||||
|
fn custom_error_field() -> Result<&str, CustomError> {
|
||||||
|
Err(CustomError::NotFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn nullable_first_level() {
|
fn nullable_first_level() {
|
||||||
|
@ -985,13 +1068,17 @@ mod named_operations {
|
||||||
|
|
||||||
struct Schema;
|
struct Schema;
|
||||||
|
|
||||||
graphql_object!(Schema: () |&self| {
|
#[crate::impl_object_internal]
|
||||||
field a() -> &str { "b" }
|
impl Schema {
|
||||||
});
|
fn a() -> &str {
|
||||||
|
"b"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn uses_inline_operation_if_no_name_provided() {
|
fn uses_inline_operation_if_no_name_provided() {
|
||||||
let schema = RootNode::new(Schema, EmptyMutation::<()>::new());
|
let schema =
|
||||||
|
RootNode::<_, _, crate::DefaultScalarValue>::new(Schema, EmptyMutation::<()>::new());
|
||||||
let doc = r"{ a }";
|
let doc = r"{ a }";
|
||||||
|
|
||||||
let vars = vec![].into_iter().collect();
|
let vars = vec![].into_iter().collect();
|
||||||
|
|
|
@ -37,12 +37,17 @@ mod interface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
graphql_object!(Dog: () |&self| {
|
#[crate::impl_object_internal(
|
||||||
field name() -> &str { &self.name }
|
interfaces = [&Pet]
|
||||||
field woofs() -> bool { self.woofs }
|
)]
|
||||||
|
impl Dog {
|
||||||
interfaces: [&Pet]
|
fn name(&self) -> &str {
|
||||||
});
|
&self.name
|
||||||
|
}
|
||||||
|
fn woofs(&self) -> bool {
|
||||||
|
self.woofs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct Cat {
|
struct Cat {
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -58,22 +63,28 @@ mod interface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
graphql_object!(Cat: () |&self| {
|
#[crate::impl_object_internal(
|
||||||
field name() -> &str { &self.name }
|
interfaces = [&Pet]
|
||||||
field meows() -> bool { self.meows }
|
)]
|
||||||
|
impl Cat {
|
||||||
interfaces: [&Pet]
|
fn name(&self) -> &str {
|
||||||
});
|
&self.name
|
||||||
|
}
|
||||||
|
fn meows(&self) -> bool {
|
||||||
|
self.meows
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct Schema {
|
struct Schema {
|
||||||
pets: Vec<Box<Pet>>,
|
pets: Vec<Box<Pet>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
graphql_object!(Schema: () |&self| {
|
#[crate::impl_object_internal]
|
||||||
field pets() -> Vec<&Pet> {
|
impl Schema {
|
||||||
|
fn pets(&self) -> Vec<&Pet> {
|
||||||
self.pets.iter().map(|p| p.as_ref()).collect()
|
self.pets.iter().map(|p| p.as_ref()).collect()
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test() {
|
fn test() {
|
||||||
|
@ -177,10 +188,15 @@ mod union {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
graphql_object!(Dog: () |&self| {
|
#[crate::impl_object_internal]
|
||||||
field name() -> &str { &self.name }
|
impl Dog {
|
||||||
field woofs() -> bool { self.woofs }
|
fn name(&self) -> &str {
|
||||||
});
|
&self.name
|
||||||
|
}
|
||||||
|
fn woofs(&self) -> bool {
|
||||||
|
self.woofs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct Cat {
|
struct Cat {
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -193,20 +209,26 @@ mod union {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
graphql_object!(Cat: () |&self| {
|
#[crate::impl_object_internal]
|
||||||
field name() -> &str { &self.name }
|
impl Cat {
|
||||||
field meows() -> bool { self.meows }
|
fn name(&self) -> &str {
|
||||||
});
|
&self.name
|
||||||
|
}
|
||||||
|
fn meows(&self) -> bool {
|
||||||
|
self.meows
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct Schema {
|
struct Schema {
|
||||||
pets: Vec<Box<Pet>>,
|
pets: Vec<Box<Pet>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
graphql_object!(Schema: () |&self| {
|
#[crate::impl_object_internal]
|
||||||
field pets() -> Vec<&Pet> {
|
impl Schema {
|
||||||
|
fn pets(&self) -> Vec<&Pet> {
|
||||||
self.pets.iter().map(|p| p.as_ref()).collect()
|
self.pets.iter().map(|p| p.as_ref()).collect()
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test() {
|
fn test() {
|
||||||
|
|
|
@ -64,14 +64,27 @@ enum EnumDeprecation {
|
||||||
|
|
||||||
struct Root;
|
struct Root;
|
||||||
|
|
||||||
graphql_object!(Root: () |&self| {
|
#[crate::impl_object_internal]
|
||||||
field default_name() -> DefaultName { DefaultName::Foo }
|
impl Root {
|
||||||
field named() -> Named { Named::Foo }
|
fn default_name() -> DefaultName {
|
||||||
field no_trailing_comma() -> NoTrailingComma { NoTrailingComma::Foo }
|
DefaultName::Foo
|
||||||
field enum_description() -> EnumDescription { EnumDescription::Foo }
|
}
|
||||||
field enum_value_description() -> EnumValueDescription { EnumValueDescription::Foo }
|
fn named() -> Named {
|
||||||
field enum_deprecation() -> EnumDeprecation { EnumDeprecation::Foo }
|
Named::Foo
|
||||||
});
|
}
|
||||||
|
fn no_trailing_comma() -> NoTrailingComma {
|
||||||
|
NoTrailingComma::Foo
|
||||||
|
}
|
||||||
|
fn enum_description() -> EnumDescription {
|
||||||
|
EnumDescription::Foo
|
||||||
|
}
|
||||||
|
fn enum_value_description() -> EnumValueDescription {
|
||||||
|
EnumValueDescription::Foo
|
||||||
|
}
|
||||||
|
fn enum_deprecation() -> EnumDeprecation {
|
||||||
|
EnumDeprecation::Foo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn run_type_info_query<F>(doc: &str, f: F)
|
fn run_type_info_query<F>(doc: &str, f: F)
|
||||||
where
|
where
|
||||||
|
|
|
@ -79,8 +79,9 @@ struct FieldWithDefaults {
|
||||||
field_two: i32,
|
field_two: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
graphql_object!(Root: () |&self| {
|
#[crate::impl_object_internal]
|
||||||
field test_field(
|
impl Root {
|
||||||
|
fn test_field(
|
||||||
a1: DefaultName,
|
a1: DefaultName,
|
||||||
a2: NoTrailingComma,
|
a2: NoTrailingComma,
|
||||||
a3: Derive,
|
a3: Derive,
|
||||||
|
@ -95,7 +96,7 @@ graphql_object!(Root: () |&self| {
|
||||||
) -> i32 {
|
) -> i32 {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
fn run_type_info_query<F>(doc: &str, f: F)
|
fn run_type_info_query<F>(doc: &str, f: F)
|
||||||
where
|
where
|
||||||
|
|
|
@ -51,22 +51,26 @@ graphql_interface!(Interface: () as "SampleInterface" |&self| {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
graphql_object!(Root: () |&self| {
|
/// The root query object in the schema
|
||||||
description: "The root query object in the schema"
|
#[crate::impl_object_internal(
|
||||||
|
interfaces = [&Interface]
|
||||||
interfaces: [Interface]
|
Scalar = crate::DefaultScalarValue,
|
||||||
|
)]
|
||||||
field sample_enum() -> Sample {
|
impl Root {
|
||||||
|
fn sample_enum() -> Sample {
|
||||||
Sample::One
|
Sample::One
|
||||||
}
|
}
|
||||||
|
|
||||||
field sample_scalar(
|
#[graphql(arguments(
|
||||||
first: i32 as "The first number",
|
first(description = "The first number",),
|
||||||
second = 123: i32 as "The second number"
|
second(description = "The second number", default = 123,),
|
||||||
) -> Scalar as "A sample scalar field on the object" {
|
))]
|
||||||
|
|
||||||
|
/// A sample scalar field on the object
|
||||||
|
fn sample_scalar(first: i32, second: i32) -> Scalar {
|
||||||
Scalar(first + second)
|
Scalar(first + second)
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_execution() {
|
fn test_execution() {
|
||||||
|
|
|
@ -62,59 +62,67 @@ struct InputWithDefaults {
|
||||||
a: i32,
|
a: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
graphql_object!(TestType: () |&self| {
|
#[crate::impl_object_internal]
|
||||||
field field_with_object_input(input: Option<TestInputObject>) -> String {
|
impl TestType {
|
||||||
|
fn field_with_object_input(input: Option<TestInputObject>) -> String {
|
||||||
format!("{:?}", input)
|
format!("{:?}", input)
|
||||||
}
|
}
|
||||||
|
|
||||||
field field_with_nullable_string_input(input: Option<String>) -> String {
|
fn field_with_nullable_string_input(input: Option<String>) -> String {
|
||||||
format!("{:?}", input)
|
format!("{:?}", input)
|
||||||
}
|
}
|
||||||
|
|
||||||
field field_with_non_nullable_string_input(input: String) -> String {
|
fn field_with_non_nullable_string_input(input: String) -> String {
|
||||||
format!("{:?}", input)
|
format!("{:?}", input)
|
||||||
}
|
}
|
||||||
|
|
||||||
field field_with_default_argument_value(input = ("Hello World".to_owned()): String) -> String {
|
#[graphql(
|
||||||
|
arguments(
|
||||||
|
input(
|
||||||
|
default = "Hello World".to_string(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
fn field_with_default_argument_value(input: String) -> String {
|
||||||
format!("{:?}", input)
|
format!("{:?}", input)
|
||||||
}
|
}
|
||||||
|
|
||||||
field field_with_nested_object_input(input: Option<TestNestedInputObject>) -> String {
|
fn field_with_nested_object_input(input: Option<TestNestedInputObject>) -> String {
|
||||||
format!("{:?}", input)
|
format!("{:?}", input)
|
||||||
}
|
}
|
||||||
|
|
||||||
field list(input: Option<Vec<Option<String>>>) -> String {
|
fn list(input: Option<Vec<Option<String>>>) -> String {
|
||||||
format!("{:?}", input)
|
format!("{:?}", input)
|
||||||
}
|
}
|
||||||
|
|
||||||
field nn_list(input: Vec<Option<String>>) -> String {
|
fn nn_list(input: Vec<Option<String>>) -> String {
|
||||||
format!("{:?}", input)
|
format!("{:?}", input)
|
||||||
}
|
}
|
||||||
|
|
||||||
field list_nn(input: Option<Vec<String>>) -> String {
|
fn list_nn(input: Option<Vec<String>>) -> String {
|
||||||
format!("{:?}", input)
|
format!("{:?}", input)
|
||||||
}
|
}
|
||||||
|
|
||||||
field nn_list_nn(input: Vec<String>) -> String {
|
fn nn_list_nn(input: Vec<String>) -> String {
|
||||||
format!("{:?}", input)
|
format!("{:?}", input)
|
||||||
}
|
}
|
||||||
|
|
||||||
field example_input(arg: ExampleInputObject) -> String {
|
fn example_input(arg: ExampleInputObject) -> String {
|
||||||
format!("a: {:?}, b: {:?}", arg.a, arg.b)
|
format!("a: {:?}, b: {:?}", arg.a, arg.b)
|
||||||
}
|
}
|
||||||
|
|
||||||
field input_with_defaults(arg: InputWithDefaults) -> String {
|
fn input_with_defaults(arg: InputWithDefaults) -> String {
|
||||||
format!("a: {:?}", arg.a)
|
format!("a: {:?}", arg.a)
|
||||||
}
|
}
|
||||||
|
|
||||||
field integer_input(value: i32) -> String {
|
fn integer_input(value: i32) -> String {
|
||||||
format!("value: {}", value)
|
format!("value: {}", value)
|
||||||
}
|
}
|
||||||
|
|
||||||
field float_input(value: f64) -> String {
|
fn float_input(value: f64) -> String {
|
||||||
format!("value: {}", value)
|
format!("value: {}", value)
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
fn run_variable_query<F>(query: &str, vars: Variables<DefaultScalarValue>, f: F)
|
fn run_variable_query<F>(query: &str, vars: Variables<DefaultScalarValue>, f: F)
|
||||||
where
|
where
|
||||||
|
|
|
@ -209,20 +209,22 @@ mod integration_test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serialization() {
|
fn test_serialization() {
|
||||||
struct Root;
|
struct Root;
|
||||||
graphql_object!(Root: () |&self| {
|
|
||||||
field exampleNaiveDate() -> NaiveDate {
|
#[crate::impl_object_internal]
|
||||||
|
impl Root {
|
||||||
|
fn exampleNaiveDate() -> NaiveDate {
|
||||||
NaiveDate::from_ymd(2015, 3, 14)
|
NaiveDate::from_ymd(2015, 3, 14)
|
||||||
}
|
}
|
||||||
field exampleNaiveDateTime() -> NaiveDateTime {
|
fn exampleNaiveDateTime() -> NaiveDateTime {
|
||||||
NaiveDate::from_ymd(2016, 7, 8).and_hms(9, 10, 11)
|
NaiveDate::from_ymd(2016, 7, 8).and_hms(9, 10, 11)
|
||||||
}
|
}
|
||||||
field exampleDateTimeFixedOffset() -> DateTime<FixedOffset> {
|
fn exampleDateTimeFixedOffset() -> DateTime<FixedOffset> {
|
||||||
DateTime::parse_from_rfc3339("1996-12-19T16:39:57-08:00").unwrap()
|
DateTime::parse_from_rfc3339("1996-12-19T16:39:57-08:00").unwrap()
|
||||||
}
|
}
|
||||||
field exampleDateTimeUtc() -> DateTime<Utc> {
|
fn exampleDateTimeUtc() -> DateTime<Utc> {
|
||||||
Utc.timestamp(61, 0)
|
Utc.timestamp(61, 0)
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
let doc = r#"
|
let doc = r#"
|
||||||
{
|
{
|
||||||
|
|
|
@ -61,13 +61,18 @@ impl Character for Droid {
|
||||||
fn id(&self) -> &str { &self.id }
|
fn id(&self) -> &str { &self.id }
|
||||||
}
|
}
|
||||||
|
|
||||||
juniper::graphql_object!(Human: Database as "Human" |&self| {
|
#[juniper::impl_object(Context = Database)]
|
||||||
field id() -> &str { &self.id }
|
impl Human {
|
||||||
});
|
fn id(&self) -> &str { &self.id }
|
||||||
|
}
|
||||||
|
|
||||||
juniper::graphql_object!(Droid: Database as "Droid" |&self| {
|
#[juniper::impl_object(
|
||||||
field id() -> &str { &self.id }
|
name = "Droid",
|
||||||
});
|
Context = Database,
|
||||||
|
)]
|
||||||
|
impl Droid {
|
||||||
|
fn id(&self) -> &str { &self.id }
|
||||||
|
}
|
||||||
|
|
||||||
// You can introduce lifetimes or generic parameters by < > before the name.
|
// You can introduce lifetimes or generic parameters by < > before the name.
|
||||||
juniper::graphql_interface!(<'a> &'a Character: Database as "Character" |&self| {
|
juniper::graphql_interface!(<'a> &'a Character: Database as "Character" |&self| {
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
/**
|
/**
|
||||||
|
## DEPRECATION WARNING
|
||||||
|
|
||||||
|
The `graphql_object!` macro is deprecated and will be removed soon.
|
||||||
|
Use the new[impl_object](https://docs.rs/juniper/latest/juniper/macro.impl_object.html) macro instead.
|
||||||
|
|
||||||
Expose GraphQL objects
|
Expose GraphQL objects
|
||||||
|
|
||||||
|
|
||||||
This is a short-hand macro that implements the `GraphQLType` trait for a given
|
This is a short-hand macro that implements the `GraphQLType` trait for a given
|
||||||
type. By using this macro instead of implementing it manually, you gain type
|
type. By using this macro instead of implementing it manually, you gain type
|
||||||
safety and reduce repetitive declarations.
|
safety and reduce repetitive declarations.
|
||||||
|
@ -308,7 +314,6 @@ arg_name: ArgType
|
||||||
```
|
```
|
||||||
|
|
||||||
[1]: struct.Executor.html
|
[1]: struct.Executor.html
|
||||||
|
|
||||||
*/
|
*/
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! graphql_object {
|
macro_rules! graphql_object {
|
||||||
|
|
|
@ -26,63 +26,111 @@ struct Point {
|
||||||
x: i32,
|
x: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
graphql_object!(Root: () |&self| {
|
#[crate::impl_object_internal]
|
||||||
field simple() -> i32 { 0 }
|
impl Root {
|
||||||
field exec_arg(&executor) -> i32 { 0 }
|
fn simple() -> i32 {
|
||||||
field exec_arg_and_more(&executor, arg: i32) -> i32 { 0 }
|
0
|
||||||
|
}
|
||||||
|
fn exec_arg(executor: &Executor) -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
fn exec_arg_and_more(executor: &Executor, arg: i32) -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
field single_arg(arg: i32) -> i32 { 0 }
|
fn single_arg(arg: i32) -> i32 {
|
||||||
field multi_args(
|
0
|
||||||
arg1: i32,
|
}
|
||||||
arg2: i32
|
|
||||||
) -> i32 { 0 }
|
|
||||||
field multi_args_trailing_comma(
|
|
||||||
arg1: i32,
|
|
||||||
arg2: i32,
|
|
||||||
) -> i32 { 0 }
|
|
||||||
|
|
||||||
field single_arg_descr(arg: i32 as "The arg") -> i32 { 0 }
|
fn multi_args(arg1: i32, arg2: i32) -> i32 {
|
||||||
field multi_args_descr(
|
0
|
||||||
arg1: i32 as "The first arg",
|
}
|
||||||
arg2: i32 as "The second arg"
|
|
||||||
) -> i32 { 0 }
|
|
||||||
field multi_args_descr_trailing_comma(
|
|
||||||
arg1: i32 as "The first arg",
|
|
||||||
arg2: i32 as "The second arg",
|
|
||||||
) -> i32 { 0 }
|
|
||||||
|
|
||||||
field attr_arg_descr(#[doc = "The arg"] arg: i32) -> i32 { 0 }
|
fn multi_args_trailing_comma(arg1: i32, arg2: i32) -> i32 {
|
||||||
field attr_arg_descr_collapse(
|
0
|
||||||
#[doc = "The arg"]
|
}
|
||||||
#[doc = "and more details"]
|
|
||||||
arg: i32,
|
|
||||||
) -> i32 { 0 }
|
|
||||||
|
|
||||||
field arg_with_default(arg = 123: i32) -> i32 { 0 }
|
#[graphql(arguments(arg(description = "The arg")))]
|
||||||
field multi_args_with_default(
|
fn single_arg_descr(arg: i32) -> i32 {
|
||||||
arg1 = 123: i32,
|
0
|
||||||
arg2 = 456: i32
|
}
|
||||||
) -> i32 { 0 }
|
|
||||||
field multi_args_with_default_trailing_comma(
|
|
||||||
arg1 = 123: i32,
|
|
||||||
arg2 = 456: i32,
|
|
||||||
) -> i32 { 0 }
|
|
||||||
|
|
||||||
field arg_with_default_descr(arg = 123: i32 as "The arg") -> i32 { 0 }
|
#[graphql(arguments(
|
||||||
field multi_args_with_default_descr(
|
arg1(description = "The first arg",),
|
||||||
arg1 = 123: i32 as "The first arg",
|
arg2(description = "The second arg")
|
||||||
arg2 = 456: i32 as "The second arg"
|
))]
|
||||||
) -> i32 { 0 }
|
fn multi_args_descr(arg1: i32, arg2: i32) -> i32 {
|
||||||
field multi_args_with_default_trailing_comma_descr(
|
0
|
||||||
arg1 = 123: i32 as "The first arg",
|
}
|
||||||
arg2 = 456: i32 as "The second arg",
|
|
||||||
) -> i32 { 0 }
|
|
||||||
|
|
||||||
field args_with_complex_default(
|
#[graphql(arguments(
|
||||||
arg1 = ("test".to_owned()): String as "A string default argument",
|
arg1(description = "The first arg",),
|
||||||
arg2 = (Point { x: 1 }): Point as "An input object default argument",
|
arg2(description = "The second arg")
|
||||||
) -> i32 { 0 }
|
))]
|
||||||
});
|
fn multi_args_descr_trailing_comma(arg1: i32, arg2: i32) -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: enable once [RFC 2565](https://github.com/rust-lang/rust/issues/60406) is implemented
|
||||||
|
// fn attr_arg_descr(#[doc = "The arg"] arg: i32) -> i32 { 0 }
|
||||||
|
// fn attr_arg_descr_collapse(
|
||||||
|
// #[doc = "The arg"]
|
||||||
|
// #[doc = "and more details"]
|
||||||
|
// arg: i32,
|
||||||
|
// ) -> i32 { 0 }
|
||||||
|
|
||||||
|
#[graphql(arguments(arg(default = 123,),))]
|
||||||
|
fn arg_with_default(arg: i32) -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql(arguments(arg1(default = 123,), arg2(default = 456,)))]
|
||||||
|
fn multi_args_with_default(arg1: i32, arg2: i32) -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql(arguments(arg1(default = 123,), arg2(default = 456,),))]
|
||||||
|
fn multi_args_with_default_trailing_comma(arg1: i32, arg2: i32) -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql(arguments(arg(default = 123, description = "The arg")))]
|
||||||
|
fn arg_with_default_descr(arg: i32) -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql(arguments(
|
||||||
|
arg1(default = 123, description = "The first arg"),
|
||||||
|
arg2(default = 456, description = "The second arg")
|
||||||
|
))]
|
||||||
|
fn multi_args_with_default_descr(arg1: i32, arg2: i32) -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql(arguments(
|
||||||
|
arg1(default = 123, description = "The first arg",),
|
||||||
|
arg2(default = 456, description = "The second arg",)
|
||||||
|
))]
|
||||||
|
fn multi_args_with_default_trailing_comma_descr(arg1: i32, arg2: i32) -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql(
|
||||||
|
arguments(
|
||||||
|
arg1(
|
||||||
|
default = "test".to_string(),
|
||||||
|
description = "A string default argument",
|
||||||
|
),
|
||||||
|
arg2(
|
||||||
|
default = Point{ x: 1 },
|
||||||
|
description = "An input object default argument",
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)]
|
||||||
|
fn args_with_complex_default(arg1: String, arg2: Point) -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn run_args_info_query<F>(field_name: &str, f: F)
|
fn run_args_info_query<F>(field_name: &str, f: F)
|
||||||
where
|
where
|
||||||
|
@ -509,71 +557,73 @@ fn introspect_field_multi_args_descr_trailing_comma() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
// TODO: enable once [RFC 2565](https://github.com/rust-lang/rust/issues/60406) is implemented
|
||||||
fn introspect_field_attr_arg_descr() {
|
// #[test]
|
||||||
run_args_info_query("attrArgDescr", |args| {
|
// fn introspect_field_attr_arg_descr() {
|
||||||
assert_eq!(args.len(), 1);
|
// run_args_info_query("attrArgDescr", |args| {
|
||||||
|
// assert_eq!(args.len(), 1);
|
||||||
|
|
||||||
assert!(args.contains(&Value::object(
|
// assert!(args.contains(&Value::object(
|
||||||
vec![
|
// vec![
|
||||||
("name", Value::scalar("arg")),
|
// ("name", Value::scalar("arg")),
|
||||||
("description", Value::scalar("The arg")),
|
// ("description", Value::scalar("The arg")),
|
||||||
("defaultValue", Value::null()),
|
// ("defaultValue", Value::null()),
|
||||||
(
|
// (
|
||||||
"type",
|
// "type",
|
||||||
Value::object(
|
// Value::object(
|
||||||
vec![
|
// vec![
|
||||||
("name", Value::null()),
|
// ("name", Value::null()),
|
||||||
(
|
// (
|
||||||
"ofType",
|
// "ofType",
|
||||||
Value::object(
|
// Value::object(
|
||||||
vec![("name", Value::scalar("Int"))].into_iter().collect(),
|
// vec![("name", Value::scalar("Int"))].into_iter().collect(),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
]
|
// ]
|
||||||
.into_iter()
|
// .into_iter()
|
||||||
.collect(),
|
// .collect(),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
]
|
// ]
|
||||||
.into_iter()
|
// .into_iter()
|
||||||
.collect(),
|
// .collect(),
|
||||||
)));
|
// )));
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[test]
|
// TODO: enable once [RFC 2565](https://github.com/rust-lang/rust/issues/60406) is implemented
|
||||||
fn introspect_field_attr_arg_descr_collapse() {
|
// #[test]
|
||||||
run_args_info_query("attrArgDescrCollapse", |args| {
|
// fn introspect_field_attr_arg_descr_collapse() {
|
||||||
assert_eq!(args.len(), 1);
|
// run_args_info_query("attrArgDescrCollapse", |args| {
|
||||||
|
// assert_eq!(args.len(), 1);
|
||||||
|
|
||||||
assert!(args.contains(&Value::object(
|
// assert!(args.contains(&Value::object(
|
||||||
vec![
|
// vec![
|
||||||
("name", Value::scalar("arg")),
|
// ("name", Value::scalar("arg")),
|
||||||
("description", Value::scalar("The arg\nand more details")),
|
// ("description", Value::scalar("The arg\nand more details")),
|
||||||
("defaultValue", Value::null()),
|
// ("defaultValue", Value::null()),
|
||||||
(
|
// (
|
||||||
"type",
|
// "type",
|
||||||
Value::object(
|
// Value::object(
|
||||||
vec![
|
// vec![
|
||||||
("name", Value::null()),
|
// ("name", Value::null()),
|
||||||
(
|
// (
|
||||||
"ofType",
|
// "ofType",
|
||||||
Value::object(
|
// Value::object(
|
||||||
vec![("name", Value::scalar("Int"))].into_iter().collect(),
|
// vec![("name", Value::scalar("Int"))].into_iter().collect(),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
]
|
// ]
|
||||||
.into_iter()
|
// .into_iter()
|
||||||
.collect(),
|
// .collect(),
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
]
|
// ]
|
||||||
.into_iter()
|
// .into_iter()
|
||||||
.collect(),
|
// .collect(),
|
||||||
)));
|
// )));
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn introspect_field_arg_with_default() {
|
fn introspect_field_arg_with_default() {
|
||||||
|
|
|
@ -20,49 +20,77 @@ Syntax to validate:
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
graphql_object!(Root: () |&self| {
|
#[crate::impl_object_internal(
|
||||||
field simple() -> i32 { 0 }
|
interfaces = [&Interface],
|
||||||
|
)]
|
||||||
field description() -> i32 as "Field description" { 0 }
|
impl Root {
|
||||||
|
fn simple() -> i32 {
|
||||||
field deprecated "Deprecation reason"
|
0
|
||||||
deprecated() -> i32 { 0 }
|
}
|
||||||
|
|
||||||
field deprecated "Deprecation reason"
|
|
||||||
deprecated_descr() -> i32 as "Field description" { 0 }
|
|
||||||
|
|
||||||
/// Field description
|
/// Field description
|
||||||
field attr_description() -> i32 { 0 }
|
fn description() -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql(deprecated = "Deprecation reason")]
|
||||||
|
fn deprecated() -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql(deprecated = "Deprecation reason", description = "Field description")]
|
||||||
|
fn deprecated_descr() -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Field description
|
||||||
|
fn attr_description() -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
/// Field description
|
/// Field description
|
||||||
/// with `collapse_docs` behavior
|
/// with `collapse_docs` behavior
|
||||||
field attr_description_collapse() -> i32 { 0 }
|
fn attr_description_collapse() -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the i32 representation of 0.
|
/// Get the i32 representation of 0.
|
||||||
///
|
///
|
||||||
/// - This comment is longer.
|
/// - This comment is longer.
|
||||||
/// - These two lines are rendered as bullets by GraphiQL.
|
/// - These two lines are rendered as bullets by GraphiQL.
|
||||||
/// - subsection
|
/// - subsection
|
||||||
field attr_description_long() -> i32 { 0 }
|
fn attr_description_long() -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
#[deprecated]
|
#[graphql(deprecated)]
|
||||||
field attr_deprecated() -> i32 { 0 }
|
fn attr_deprecated() -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
#[deprecated(note = "Deprecation reason")]
|
#[graphql(deprecated = "Deprecation reason")]
|
||||||
field attr_deprecated_reason() -> i32 { 0 }
|
fn attr_deprecated_reason() -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
/// Field description
|
/// Field description
|
||||||
#[deprecated(note = "Deprecation reason")]
|
#[graphql(deprecated = "Deprecation reason")]
|
||||||
field attr_deprecated_descr() -> i32 { 0 }
|
fn attr_deprecated_descr() -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
field with_field_result() -> FieldResult<i32> { Ok(0) }
|
fn with_field_result() -> FieldResult<i32> {
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
field with_return() -> i32 { return 0; }
|
fn with_return() -> i32 {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
field with_return_field_result() -> FieldResult<i32> { return Ok(0); }
|
fn with_return_field_result() -> FieldResult<i32> {
|
||||||
|
return Ok(0);
|
||||||
interfaces: [Interface]
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
graphql_interface!(Interface: () |&self| {
|
graphql_interface!(Interface: () |&self| {
|
||||||
field simple() -> i32 { 0 }
|
field simple() -> i32 { 0 }
|
||||||
|
|
269
juniper/src/macros/tests/impl_object.rs
Normal file
269
juniper/src/macros/tests/impl_object.rs
Normal file
|
@ -0,0 +1,269 @@
|
||||||
|
use super::util;
|
||||||
|
use crate::{graphql_value, EmptyMutation, RootNode};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct Context {
|
||||||
|
flag1: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::Context for Context {}
|
||||||
|
|
||||||
|
struct WithLifetime<'a> {
|
||||||
|
value: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[crate::impl_object_internal(Context=Context)]
|
||||||
|
impl<'a> WithLifetime<'a> {
|
||||||
|
fn value(&'a self) -> &'a str {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WithContext;
|
||||||
|
|
||||||
|
#[crate::impl_object_internal(Context=Context)]
|
||||||
|
impl WithContext {
|
||||||
|
fn ctx(ctx: &Context) -> bool {
|
||||||
|
ctx.flag1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct Query {
|
||||||
|
b: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[crate::impl_object_internal(
|
||||||
|
scalar = crate::DefaultScalarValue,
|
||||||
|
name = "Query",
|
||||||
|
context = Context,
|
||||||
|
)]
|
||||||
|
/// Query Description.
|
||||||
|
impl<'a> Query {
|
||||||
|
#[graphql(description = "With Self Description")]
|
||||||
|
fn with_self(&self) -> bool {
|
||||||
|
self.b
|
||||||
|
}
|
||||||
|
|
||||||
|
fn independent() -> i32 {
|
||||||
|
100
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_executor(_exec: &Executor<Context>) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_executor_and_self(&self, _exec: &Executor<Context>) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_context(_context: &Context) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_context_and_self(&self, _context: &Context) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql(name = "renamed")]
|
||||||
|
fn has_custom_name() -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql(description = "attr")]
|
||||||
|
fn has_description_attr() -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Doc description
|
||||||
|
fn has_description_doc_comment() -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_argument(arg1: bool) -> bool {
|
||||||
|
arg1
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql(arguments(default_arg(default = true)))]
|
||||||
|
fn default_argument(default_arg: bool) -> bool {
|
||||||
|
default_arg
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql(arguments(arg(description = "my argument description")))]
|
||||||
|
fn arg_with_description(arg: bool) -> bool {
|
||||||
|
arg
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_context_child(&self) -> WithContext {
|
||||||
|
WithContext
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_lifetime_child(&self) -> WithLifetime<'a> {
|
||||||
|
WithLifetime { value: "blub" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct Mutation;
|
||||||
|
|
||||||
|
#[crate::impl_object_internal(context = Context)]
|
||||||
|
impl Mutation {
|
||||||
|
fn empty() -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn impl_object_introspect() {
|
||||||
|
let res = util::run_info_query::<Query, Mutation, Context>("Query");
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
crate::graphql_value!({
|
||||||
|
"name": "Query",
|
||||||
|
"description": "Query Description.",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "withSelf",
|
||||||
|
"description": "With Self Description",
|
||||||
|
"args": [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "independent",
|
||||||
|
"description": None,
|
||||||
|
"args": [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "withExecutor",
|
||||||
|
"description": None,
|
||||||
|
"args": [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "withExecutorAndSelf",
|
||||||
|
"description": None,
|
||||||
|
"args": [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "withContext",
|
||||||
|
"description": None,
|
||||||
|
"args": [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "withContextAndSelf",
|
||||||
|
"description": None,
|
||||||
|
"args": [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "renamed",
|
||||||
|
"description": None,
|
||||||
|
"args": [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hasDescriptionAttr",
|
||||||
|
"description": "attr",
|
||||||
|
"args": [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hasDescriptionDocComment",
|
||||||
|
"description": "Doc description",
|
||||||
|
"args": [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hasArgument",
|
||||||
|
"description": None,
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"name": "arg1",
|
||||||
|
"description": None,
|
||||||
|
"type": {
|
||||||
|
"name": None,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "defaultArgument",
|
||||||
|
"description": None,
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"name": "defaultArg",
|
||||||
|
"description": None,
|
||||||
|
"type": {
|
||||||
|
"name": "Boolean",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "argWithDescription",
|
||||||
|
"description": None,
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"name": "arg",
|
||||||
|
"description": "my argument description",
|
||||||
|
"type": {
|
||||||
|
"name": None
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "withContextChild",
|
||||||
|
"description": None,
|
||||||
|
"args": [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "withLifetimeChild",
|
||||||
|
"description": None,
|
||||||
|
"args": [],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn impl_object_query() {
|
||||||
|
let doc = r#"
|
||||||
|
query {
|
||||||
|
withSelf
|
||||||
|
independent
|
||||||
|
withExecutor
|
||||||
|
withExecutorAndSelf
|
||||||
|
withContext
|
||||||
|
withContextAndSelf
|
||||||
|
renamed
|
||||||
|
hasArgument(arg1: true)
|
||||||
|
defaultArgument
|
||||||
|
argWithDescription(arg: true)
|
||||||
|
withContextChild {
|
||||||
|
ctx
|
||||||
|
}
|
||||||
|
withLifetimeChild {
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let schema = RootNode::new(Query { b: true }, EmptyMutation::<Context>::new());
|
||||||
|
let vars = std::collections::HashMap::new();
|
||||||
|
|
||||||
|
let (result, errs) = crate::execute(doc, None, &schema, &vars, &Context { flag1: true })
|
||||||
|
.expect("Execution failed");
|
||||||
|
assert_eq!(errs, []);
|
||||||
|
assert_eq!(
|
||||||
|
result,
|
||||||
|
graphql_value!({
|
||||||
|
"withSelf": true,
|
||||||
|
"independent": 100,
|
||||||
|
"withExecutor": true,
|
||||||
|
"withExecutorAndSelf": true,
|
||||||
|
"withContext": true,
|
||||||
|
"withContextAndSelf": true,
|
||||||
|
"renamed": true,
|
||||||
|
"hasArgument": true,
|
||||||
|
"defaultArgument": true,
|
||||||
|
"argWithDescription": true,
|
||||||
|
"withContextChild": { "ctx": true },
|
||||||
|
"withLifetimeChild": { "value": "blub" },
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
|
@ -42,9 +42,12 @@ struct ResolversWithTrailingComma;
|
||||||
|
|
||||||
struct Root;
|
struct Root;
|
||||||
|
|
||||||
graphql_object!(Concrete: () |&self| {
|
#[crate::impl_object_internal]
|
||||||
field simple() -> i32 { 0 }
|
impl Concrete {
|
||||||
});
|
fn simple() -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
graphql_interface!(CustomName: () as "ACustomNamedInterface" |&self| {
|
graphql_interface!(CustomName: () as "ACustomNamedInterface" |&self| {
|
||||||
field simple() -> i32 { 0 }
|
field simple() -> i32 { 0 }
|
||||||
|
@ -108,24 +111,40 @@ graphql_interface!(ResolversWithTrailingComma: () |&self| {
|
||||||
field simple() -> i32 { 0 }
|
field simple() -> i32 { 0 }
|
||||||
});
|
});
|
||||||
|
|
||||||
graphql_object!(<'a> Root: () as "Root" |&self| {
|
#[crate::impl_object_internal]
|
||||||
field custom_name() -> CustomName { CustomName {} }
|
impl<'a> Root {
|
||||||
|
fn custom_name() -> CustomName {
|
||||||
field with_lifetime() -> WithLifetime<'a> { WithLifetime { data: PhantomData } }
|
CustomName {}
|
||||||
field with_generics() -> WithGenerics<i32> { WithGenerics { data: 123 } }
|
|
||||||
|
|
||||||
field description_first() -> DescriptionFirst { DescriptionFirst {} }
|
|
||||||
field fields_first() -> FieldsFirst { FieldsFirst {} }
|
|
||||||
field interfaces_first() -> InterfacesFirst { InterfacesFirst {} }
|
|
||||||
|
|
||||||
field commas_with_trailing() -> CommasWithTrailing { CommasWithTrailing {} }
|
|
||||||
field commas_on_meta() -> CommasOnMeta { CommasOnMeta {} }
|
|
||||||
|
|
||||||
field resolvers_with_trailing_comma() -> ResolversWithTrailingComma {
|
|
||||||
ResolversWithTrailingComma {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
fn with_lifetime() -> WithLifetime<'a> {
|
||||||
|
WithLifetime { data: PhantomData }
|
||||||
|
}
|
||||||
|
fn with_generics() -> WithGenerics<i32> {
|
||||||
|
WithGenerics { data: 123 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description_first() -> DescriptionFirst {
|
||||||
|
DescriptionFirst {}
|
||||||
|
}
|
||||||
|
fn fields_first() -> FieldsFirst {
|
||||||
|
FieldsFirst {}
|
||||||
|
}
|
||||||
|
fn interfaces_first() -> InterfacesFirst {
|
||||||
|
InterfacesFirst {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn commas_with_trailing() -> CommasWithTrailing {
|
||||||
|
CommasWithTrailing {}
|
||||||
|
}
|
||||||
|
fn commas_on_meta() -> CommasOnMeta {
|
||||||
|
CommasOnMeta {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolvers_with_trailing_comma() -> ResolversWithTrailingComma {
|
||||||
|
ResolversWithTrailingComma {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn run_type_info_query<F>(type_name: &str, f: F)
|
fn run_type_info_query<F>(type_name: &str, f: F)
|
||||||
where
|
where
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
mod args;
|
mod args;
|
||||||
mod field;
|
mod field;
|
||||||
|
mod impl_object;
|
||||||
mod interface;
|
mod interface;
|
||||||
mod object;
|
mod object;
|
||||||
mod scalar;
|
mod scalar;
|
||||||
mod union;
|
mod union;
|
||||||
|
mod util;
|
||||||
|
|
|
@ -18,41 +18,29 @@ Syntax to validate:
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct Interface;
|
|
||||||
|
|
||||||
struct CustomName;
|
struct CustomName;
|
||||||
|
graphql_object!(CustomName: () as "ACustomNamedType" |&self| {
|
||||||
|
field simple() -> i32 { 0 }
|
||||||
|
});
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
struct WithLifetime<'a> {
|
struct WithLifetime<'a> {
|
||||||
data: PhantomData<&'a i32>,
|
data: PhantomData<&'a i32>,
|
||||||
}
|
}
|
||||||
|
graphql_object!(<'a> WithLifetime<'a>: () as "WithLifetime" |&self| {
|
||||||
|
field simple() -> i32 { 0 }
|
||||||
|
});
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
struct WithGenerics<T> {
|
struct WithGenerics<T> {
|
||||||
data: T,
|
data: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DescriptionFirst;
|
|
||||||
struct FieldsFirst;
|
|
||||||
struct InterfacesFirst;
|
|
||||||
|
|
||||||
struct CommasWithTrailing;
|
|
||||||
struct CommasOnMeta;
|
|
||||||
|
|
||||||
struct Root;
|
|
||||||
|
|
||||||
graphql_object!(CustomName: () as "ACustomNamedType" |&self| {
|
|
||||||
field simple() -> i32 { 0 }
|
|
||||||
});
|
|
||||||
|
|
||||||
graphql_object!(<'a> WithLifetime<'a>: () as "WithLifetime" |&self| {
|
|
||||||
field simple() -> i32 { 0 }
|
|
||||||
});
|
|
||||||
|
|
||||||
graphql_object!(<T> WithGenerics<T>: () as "WithGenerics" |&self| {
|
graphql_object!(<T> WithGenerics<T>: () as "WithGenerics" |&self| {
|
||||||
field simple() -> i32 { 0 }
|
field simple() -> i32 { 0 }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
struct Interface;
|
||||||
|
struct DescriptionFirst;
|
||||||
graphql_interface!(Interface: () |&self| {
|
graphql_interface!(Interface: () |&self| {
|
||||||
field simple() -> i32 { 0 }
|
field simple() -> i32 { 0 }
|
||||||
|
|
||||||
|
@ -60,7 +48,6 @@ graphql_interface!(Interface: () |&self| {
|
||||||
DescriptionFirst => Some(DescriptionFirst {}),
|
DescriptionFirst => Some(DescriptionFirst {}),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
graphql_object!(DescriptionFirst: () |&self| {
|
graphql_object!(DescriptionFirst: () |&self| {
|
||||||
description: "A description"
|
description: "A description"
|
||||||
|
|
||||||
|
@ -69,6 +56,7 @@ graphql_object!(DescriptionFirst: () |&self| {
|
||||||
interfaces: [Interface]
|
interfaces: [Interface]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
struct FieldsFirst;
|
||||||
graphql_object!(FieldsFirst: () |&self| {
|
graphql_object!(FieldsFirst: () |&self| {
|
||||||
field simple() -> i32 { 0 }
|
field simple() -> i32 { 0 }
|
||||||
|
|
||||||
|
@ -77,6 +65,7 @@ graphql_object!(FieldsFirst: () |&self| {
|
||||||
interfaces: [Interface]
|
interfaces: [Interface]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
struct InterfacesFirst;
|
||||||
graphql_object!(InterfacesFirst: ()|&self| {
|
graphql_object!(InterfacesFirst: ()|&self| {
|
||||||
interfaces: [Interface]
|
interfaces: [Interface]
|
||||||
|
|
||||||
|
@ -85,6 +74,7 @@ graphql_object!(InterfacesFirst: ()|&self| {
|
||||||
description: "A description"
|
description: "A description"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
struct CommasWithTrailing;
|
||||||
graphql_object!(CommasWithTrailing: () |&self| {
|
graphql_object!(CommasWithTrailing: () |&self| {
|
||||||
interfaces: [Interface],
|
interfaces: [Interface],
|
||||||
|
|
||||||
|
@ -93,6 +83,8 @@ graphql_object!(CommasWithTrailing: () |&self| {
|
||||||
description: "A description",
|
description: "A description",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
struct CommasOnMeta;
|
||||||
|
|
||||||
graphql_object!(CommasOnMeta: () |&self| {
|
graphql_object!(CommasOnMeta: () |&self| {
|
||||||
interfaces: [Interface],
|
interfaces: [Interface],
|
||||||
description: "A description",
|
description: "A description",
|
||||||
|
@ -100,6 +92,8 @@ graphql_object!(CommasOnMeta: () |&self| {
|
||||||
field simple() -> i32 { 0 }
|
field simple() -> i32 { 0 }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
struct Root;
|
||||||
|
|
||||||
struct InnerContext;
|
struct InnerContext;
|
||||||
impl Context for InnerContext {}
|
impl Context for InnerContext {}
|
||||||
|
|
||||||
|
|
|
@ -78,12 +78,21 @@ graphql_scalar!(ScalarDescription {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
graphql_object!(Root: () |&self| {
|
#[crate::impl_object_internal]
|
||||||
field default_name() -> DefaultName { DefaultName(0) }
|
impl Root {
|
||||||
field other_order() -> OtherOrder { OtherOrder(0) }
|
fn default_name() -> DefaultName {
|
||||||
field named() -> Named { Named(0) }
|
DefaultName(0)
|
||||||
field scalar_description() -> ScalarDescription { ScalarDescription(0) }
|
}
|
||||||
});
|
fn other_order() -> OtherOrder {
|
||||||
|
OtherOrder(0)
|
||||||
|
}
|
||||||
|
fn named() -> Named {
|
||||||
|
Named(0)
|
||||||
|
}
|
||||||
|
fn scalar_description() -> ScalarDescription {
|
||||||
|
ScalarDescription(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn run_type_info_query<F>(doc: &str, f: F)
|
fn run_type_info_query<F>(doc: &str, f: F)
|
||||||
where
|
where
|
||||||
|
|
|
@ -46,23 +46,26 @@ enum ResolversWithTrailingComma {
|
||||||
|
|
||||||
struct Root;
|
struct Root;
|
||||||
|
|
||||||
graphql_object!(Concrete: () |&self| {
|
#[crate::impl_object_internal]
|
||||||
field simple() -> i32 { 123 }
|
impl Concrete {
|
||||||
});
|
fn simple() -> i32 {
|
||||||
|
123
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
graphql_union!(CustomName: () as "ACustomNamedUnion" |&self| {
|
graphql_union!(CustomName: () as "ACustomNamedUnion" |&self| {
|
||||||
instance_resolvers: |&_| {
|
instance_resolvers: |&_| {
|
||||||
&Concrete => match *self { CustomName::Concrete(ref c) => Some(c) }
|
&Concrete => match *self { CustomName::Concrete(ref c) => Some(c) }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
graphql_union!(<'a> WithLifetime<'a>: () as "WithLifetime" |&self| {
|
graphql_union!(<'a> WithLifetime<'a>: () as "WithLifetime" |&self| {
|
||||||
instance_resolvers: |&_| {
|
instance_resolvers: |&_| {
|
||||||
Concrete => match *self { WithLifetime::Int(_) => Some(Concrete) }
|
Concrete => match *self { WithLifetime::Int(_) => Some(Concrete) }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
graphql_union!(<T> WithGenerics<T>: () as "WithGenerics" |&self| {
|
graphql_union!(<T> WithGenerics<T>: () as "WithGenerics" |&self| {
|
||||||
instance_resolvers: |&_| {
|
instance_resolvers: |&_| {
|
||||||
Concrete => match *self { WithGenerics::Generic(_) => Some(Concrete) }
|
Concrete => match *self { WithGenerics::Generic(_) => Some(Concrete) }
|
||||||
}
|
}
|
||||||
|
@ -96,17 +99,30 @@ graphql_union!(ResolversWithTrailingComma: () |&self| {
|
||||||
description: "A description"
|
description: "A description"
|
||||||
});
|
});
|
||||||
|
|
||||||
graphql_object!(<'a> Root: () as "Root" |&self| {
|
#[crate::impl_object_internal]
|
||||||
field custom_name() -> CustomName { CustomName::Concrete(Concrete) }
|
impl<'a> Root {
|
||||||
field with_lifetime() -> WithLifetime<'a> { WithLifetime::Int(PhantomData) }
|
fn custom_name() -> CustomName {
|
||||||
field with_generics() -> WithGenerics<i32> { WithGenerics::Generic(123) }
|
CustomName::Concrete(Concrete)
|
||||||
field description_first() -> DescriptionFirst { DescriptionFirst::Concrete(Concrete) }
|
}
|
||||||
field resolvers_first() -> ResolversFirst { ResolversFirst::Concrete(Concrete) }
|
fn with_lifetime() -> WithLifetime<'a> {
|
||||||
field commas_with_trailing() -> CommasWithTrailing { CommasWithTrailing::Concrete(Concrete) }
|
WithLifetime::Int(PhantomData)
|
||||||
field resolvers_with_trailing_comma() -> ResolversWithTrailingComma {
|
}
|
||||||
|
fn with_generics() -> WithGenerics<i32> {
|
||||||
|
WithGenerics::Generic(123)
|
||||||
|
}
|
||||||
|
fn description_first() -> DescriptionFirst {
|
||||||
|
DescriptionFirst::Concrete(Concrete)
|
||||||
|
}
|
||||||
|
fn resolvers_first() -> ResolversFirst {
|
||||||
|
ResolversFirst::Concrete(Concrete)
|
||||||
|
}
|
||||||
|
fn commas_with_trailing() -> CommasWithTrailing {
|
||||||
|
CommasWithTrailing::Concrete(Concrete)
|
||||||
|
}
|
||||||
|
fn resolvers_with_trailing_comma() -> ResolversWithTrailingComma {
|
||||||
ResolversWithTrailingComma::Concrete(Concrete)
|
ResolversWithTrailingComma::Concrete(Concrete)
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
fn run_type_info_query<F>(type_name: &str, f: F)
|
fn run_type_info_query<F>(type_name: &str, f: F)
|
||||||
where
|
where
|
||||||
|
|
54
juniper/src/macros/tests/util.rs
Normal file
54
juniper/src/macros/tests/util.rs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
use crate::{DefaultScalarValue, GraphQLType, RootNode, Value, Variables};
|
||||||
|
use std::default::Default;
|
||||||
|
|
||||||
|
pub fn run_query<Query, Mutation, Context>(query: &str) -> Value
|
||||||
|
where
|
||||||
|
Query: GraphQLType<DefaultScalarValue, TypeInfo = (), Context = Context> + Default,
|
||||||
|
Mutation: GraphQLType<DefaultScalarValue, TypeInfo = (), Context = Context> + Default,
|
||||||
|
Context: Default,
|
||||||
|
{
|
||||||
|
let schema = RootNode::new(Query::default(), Mutation::default());
|
||||||
|
let (result, errs) =
|
||||||
|
crate::execute(query, None, &schema, &Variables::new(), &Context::default())
|
||||||
|
.expect("Execution failed");
|
||||||
|
|
||||||
|
assert_eq!(errs, []);
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_info_query<Query, Mutation, Context>(type_name: &str) -> Value
|
||||||
|
where
|
||||||
|
Query: GraphQLType<DefaultScalarValue, TypeInfo = (), Context = Context> + Default,
|
||||||
|
Mutation: GraphQLType<DefaultScalarValue, TypeInfo = (), Context = Context> + Default,
|
||||||
|
Context: Default,
|
||||||
|
{
|
||||||
|
let query = format!(
|
||||||
|
r#"
|
||||||
|
{{
|
||||||
|
__type(name: "{}") {{
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
fields {{
|
||||||
|
name
|
||||||
|
description
|
||||||
|
args {{
|
||||||
|
name
|
||||||
|
description
|
||||||
|
type {{
|
||||||
|
name
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
"#,
|
||||||
|
type_name
|
||||||
|
);
|
||||||
|
let result = run_query::<Query, Mutation, Context>(&query);
|
||||||
|
result
|
||||||
|
.as_object_value()
|
||||||
|
.expect("Result is not an object")
|
||||||
|
.get_field_value("__type")
|
||||||
|
.expect("__type field missing")
|
||||||
|
.clone()
|
||||||
|
}
|
|
@ -31,27 +31,31 @@ struct Foo {
|
||||||
|
|
||||||
struct Query;
|
struct Query;
|
||||||
|
|
||||||
graphql_object!(Query: () where Scalar = <S> |&self| {
|
#[crate::impl_object_internal(Scalar = S)]
|
||||||
field int_field() -> i32 {
|
impl<'a, S> Query
|
||||||
|
where
|
||||||
|
S: crate::ScalarValue + 'a,
|
||||||
|
{
|
||||||
|
fn int_field() -> i32 {
|
||||||
42
|
42
|
||||||
}
|
}
|
||||||
|
|
||||||
field float_field() -> f64 {
|
fn float_field() -> f64 {
|
||||||
3.14
|
3.14
|
||||||
}
|
}
|
||||||
|
|
||||||
field string_field() -> String {
|
fn string_field() -> String {
|
||||||
"".into()
|
"".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
field bool_field() -> bool {
|
fn bool_field() -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
field enum_field(_foo: Foo) -> Enum {
|
fn enum_field(_foo: Foo) -> Enum {
|
||||||
Enum::EnumValue
|
Enum::EnumValue
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
fn scalar_meta<T>(name: &'static str) -> MetaType<DefaultScalarValue>
|
fn scalar_meta<T>(name: &'static str) -> MetaType<DefaultScalarValue>
|
||||||
where
|
where
|
||||||
|
|
|
@ -73,52 +73,68 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
graphql_object!(<'a> SchemaType<'a, S>: SchemaType<'a, S> as "__Schema"
|
#[crate::impl_object_internal(
|
||||||
where Scalar = <S: 'a> |&self|
|
name = "__Schema"
|
||||||
|
Context = SchemaType<'a, S>,
|
||||||
|
Scalar = S,
|
||||||
|
)]
|
||||||
|
impl<'a, S> SchemaType<'a, S>
|
||||||
|
where
|
||||||
|
S: crate::ScalarValue + 'a,
|
||||||
{
|
{
|
||||||
field types() -> Vec<TypeType<S>> {
|
fn types(&self) -> Vec<TypeType<S>> {
|
||||||
self.type_list()
|
self.type_list()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|t| t.to_concrete().map(|t| t.name() != Some("_EmptyMutation")).unwrap_or(false))
|
.filter(|t| {
|
||||||
.collect()
|
t.to_concrete()
|
||||||
|
.map(|t| t.name() != Some("_EmptyMutation"))
|
||||||
|
.unwrap_or(false)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
field query_type() -> TypeType<S> {
|
fn query_type(&self) -> TypeType<S> {
|
||||||
self.query_type()
|
self.query_type()
|
||||||
}
|
}
|
||||||
|
|
||||||
field mutation_type() -> Option<TypeType<S>> {
|
fn mutation_type(&self) -> Option<TypeType<S>> {
|
||||||
self.mutation_type()
|
self.mutation_type()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Included for compatibility with the introspection query in GraphQL.js
|
// Included for compatibility with the introspection query in GraphQL.js
|
||||||
field subscription_type() -> Option<TypeType<S>> {
|
fn subscription_type(&self) -> Option<TypeType<S>> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
field directives() -> Vec<&DirectiveType<S>> {
|
fn directives(&self) -> Vec<&DirectiveType<S>> {
|
||||||
self.directive_list()
|
self.directive_list()
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
graphql_object!(<'a> TypeType<'a, S>: SchemaType<'a, S> as "__Type"
|
#[crate::impl_object_internal(
|
||||||
where Scalar = <S: 'a> |&self|
|
name = "__Type"
|
||||||
|
Context = SchemaType<'a, S>,
|
||||||
|
Scalar = S,
|
||||||
|
)]
|
||||||
|
impl<'a, S> TypeType<'a, S>
|
||||||
|
where
|
||||||
|
S: crate::ScalarValue + 'a,
|
||||||
{
|
{
|
||||||
field name() -> Option<&str> {
|
fn name(&self) -> Option<&str> {
|
||||||
match *self {
|
match *self {
|
||||||
TypeType::Concrete(t) => t.name(),
|
TypeType::Concrete(t) => t.name(),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
field description() -> Option<&String> {
|
fn description(&self) -> Option<&String> {
|
||||||
match *self {
|
match *self {
|
||||||
TypeType::Concrete(t) => t.description(),
|
TypeType::Concrete(t) => t.description(),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
field kind() -> TypeKind {
|
fn kind(&self) -> TypeKind {
|
||||||
match *self {
|
match *self {
|
||||||
TypeType::Concrete(t) => t.type_kind(),
|
TypeType::Concrete(t) => t.type_kind(),
|
||||||
TypeType::List(_) => TypeKind::List,
|
TypeType::List(_) => TypeKind::List,
|
||||||
|
@ -126,190 +142,242 @@ graphql_object!(<'a> TypeType<'a, S>: SchemaType<'a, S> as "__Type"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
field fields(include_deprecated = false: bool) -> Option<Vec<&Field<S>>> {
|
#[graphql(arguments(include_deprecated(default = false)))]
|
||||||
|
fn fields(&self, include_deprecated: bool) -> Option<Vec<&Field<S>>> {
|
||||||
match *self {
|
match *self {
|
||||||
TypeType::Concrete(&MetaType::Interface(InterfaceMeta { ref fields, .. })) |
|
TypeType::Concrete(&MetaType::Interface(InterfaceMeta { ref fields, .. }))
|
||||||
TypeType::Concrete(&MetaType::Object(ObjectMeta { ref fields, .. })) =>
|
| TypeType::Concrete(&MetaType::Object(ObjectMeta { ref fields, .. })) => {
|
||||||
Some(fields
|
Some(
|
||||||
.iter()
|
fields
|
||||||
.filter(|f| include_deprecated || !f.deprecation_status.is_deprecated())
|
.iter()
|
||||||
.filter(|f| !f.name.starts_with("__"))
|
.filter(|f| include_deprecated || !f.deprecation_status.is_deprecated())
|
||||||
.collect()),
|
.filter(|f| !f.name.starts_with("__"))
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
field of_type() -> Option<&Box<TypeType<S>>> {
|
fn of_type(&self) -> Option<&Box<TypeType<S>>> {
|
||||||
match *self {
|
match *self {
|
||||||
TypeType::Concrete(_) => None,
|
TypeType::Concrete(_) => None,
|
||||||
TypeType::List(ref l) | TypeType::NonNull(ref l) => Some(l),
|
TypeType::List(ref l) | TypeType::NonNull(ref l) => Some(l),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
field input_fields() -> Option<&Vec<Argument<S>>> {
|
fn input_fields(&self) -> Option<&Vec<Argument<S>>> {
|
||||||
match *self {
|
match *self {
|
||||||
TypeType::Concrete(&MetaType::InputObject(InputObjectMeta { ref input_fields, .. })) =>
|
TypeType::Concrete(&MetaType::InputObject(InputObjectMeta {
|
||||||
Some(input_fields),
|
ref input_fields,
|
||||||
|
..
|
||||||
|
})) => Some(input_fields),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
field interfaces(&executor) -> Option<Vec<TypeType<S>>> {
|
fn interfaces(&self, schema: &SchemaType<'a, S>) -> Option<Vec<TypeType<S>>> {
|
||||||
match *self {
|
match *self {
|
||||||
TypeType::Concrete(&MetaType::Object(ObjectMeta { ref interface_names, .. })) => {
|
TypeType::Concrete(&MetaType::Object(ObjectMeta {
|
||||||
let schema = executor.context();
|
ref interface_names,
|
||||||
Some(interface_names
|
..
|
||||||
|
})) => Some(
|
||||||
|
interface_names
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|n| schema.type_by_name(n))
|
.filter_map(|n| schema.type_by_name(n))
|
||||||
.collect())
|
.collect(),
|
||||||
}
|
),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
field possible_types(&executor) -> Option<Vec<TypeType<S>>> {
|
fn possible_types(&self, schema: &SchemaType<'a, S>) -> Option<Vec<TypeType<S>>> {
|
||||||
let schema = executor.context();
|
|
||||||
match *self {
|
match *self {
|
||||||
TypeType::Concrete(&MetaType::Union(UnionMeta { ref of_type_names, .. })) => {
|
TypeType::Concrete(&MetaType::Union(UnionMeta {
|
||||||
Some(of_type_names
|
ref of_type_names, ..
|
||||||
|
})) => Some(
|
||||||
|
of_type_names
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|tn| schema.type_by_name(tn))
|
.filter_map(|tn| schema.type_by_name(tn))
|
||||||
.collect())
|
.collect(),
|
||||||
}
|
),
|
||||||
TypeType::Concrete(&MetaType::Interface(InterfaceMeta{name: ref iface_name, .. })) => {
|
TypeType::Concrete(&MetaType::Interface(InterfaceMeta {
|
||||||
Some(schema.concrete_type_list()
|
name: ref iface_name,
|
||||||
|
..
|
||||||
|
})) => Some(
|
||||||
|
schema
|
||||||
|
.concrete_type_list()
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|&ct|
|
.filter_map(|&ct| {
|
||||||
if let MetaType::Object(ObjectMeta{
|
if let MetaType::Object(ObjectMeta {
|
||||||
ref name,
|
ref name,
|
||||||
ref interface_names,
|
ref interface_names,
|
||||||
..
|
..
|
||||||
}) = *ct {
|
}) = *ct
|
||||||
|
{
|
||||||
if interface_names.contains(&iface_name.to_string()) {
|
if interface_names.contains(&iface_name.to_string()) {
|
||||||
schema.type_by_name(name)
|
schema.type_by_name(name)
|
||||||
} else { None }
|
} else {
|
||||||
} else { None }
|
None
|
||||||
)
|
}
|
||||||
.collect())
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[graphql(arguments(include_deprecated(default = false)))]
|
||||||
|
fn enum_values(&self, include_deprecated: bool) -> Option<Vec<&EnumValue>> {
|
||||||
|
match *self {
|
||||||
|
TypeType::Concrete(&MetaType::Enum(EnumMeta { ref values, .. })) => {
|
||||||
|
Some(
|
||||||
|
values
|
||||||
|
.iter()
|
||||||
|
.filter(|f| include_deprecated || !f.deprecation_status.is_deprecated())
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
field enum_values(include_deprecated = false: bool) -> Option<Vec<&EnumValue>> {
|
#[crate::impl_object_internal(
|
||||||
match *self {
|
name = "__Field",
|
||||||
TypeType::Concrete(&MetaType::Enum(EnumMeta { ref values, .. })) =>
|
Context = SchemaType<'a, S>,
|
||||||
Some(values
|
Scalar = S,
|
||||||
.iter()
|
)]
|
||||||
.filter(|f| include_deprecated || !f.deprecation_status.is_deprecated())
|
impl<'a, S> Field<'a, S>
|
||||||
.collect()),
|
where
|
||||||
_ => None,
|
S: crate::ScalarValue + 'a,
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
graphql_object!(<'a> Field<'a, S>: SchemaType<'a, S> as "__Field"
|
|
||||||
where Scalar = <S: 'a> |&self|
|
|
||||||
{
|
{
|
||||||
field name() -> &String {
|
fn name(&self) -> &String {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
field description() -> &Option<String> {
|
fn description(&self) -> &Option<String> {
|
||||||
&self.description
|
&self.description
|
||||||
}
|
}
|
||||||
|
|
||||||
field args() -> Vec<&Argument<S>> {
|
fn args(&self) -> Vec<&Argument<S>> {
|
||||||
self.arguments.as_ref().map_or_else(Vec::new, |v| v.iter().collect())
|
self.arguments
|
||||||
|
.as_ref()
|
||||||
|
.map_or_else(Vec::new, |v| v.iter().collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
field type(&executor) -> TypeType<S> {
|
#[graphql(name = "type")]
|
||||||
executor.context().make_type(&self.field_type)
|
fn _type(&self, context: &SchemaType<'a, S>) -> TypeType<S> {
|
||||||
|
context.make_type(&self.field_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
field is_deprecated() -> bool {
|
fn is_deprecated(&self) -> bool {
|
||||||
self.deprecation_status.is_deprecated()
|
self.deprecation_status.is_deprecated()
|
||||||
}
|
}
|
||||||
|
|
||||||
field deprecation_reason() -> Option<&String> {
|
fn deprecation_reason(&self) -> Option<&String> {
|
||||||
self.deprecation_status.reason()
|
self.deprecation_status.reason()
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
graphql_object!(<'a> Argument<'a, S>: SchemaType<'a, S> as "__InputValue"
|
#[crate::impl_object_internal(
|
||||||
where Scalar = <S: 'a> |&self|
|
name = "__InputValue",
|
||||||
|
Context = SchemaType<'a, S>,
|
||||||
|
Scalar = S,
|
||||||
|
)]
|
||||||
|
impl<'a, S> Argument<'a, S>
|
||||||
|
where
|
||||||
|
S: crate::ScalarValue + 'a,
|
||||||
{
|
{
|
||||||
field name() -> &String {
|
fn name(&self) -> &String {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
field description() -> &Option<String> {
|
fn description(&self) -> &Option<String> {
|
||||||
&self.description
|
&self.description
|
||||||
}
|
}
|
||||||
|
|
||||||
field type(&executor) -> TypeType<S> {
|
#[graphql(name = "type")]
|
||||||
executor.context().make_type(&self.arg_type)
|
fn _type(&self, context: &SchemaType<'a, S>) -> TypeType<S> {
|
||||||
|
context.make_type(&self.arg_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
field default_value() -> Option<String> {
|
fn default_value(&self) -> Option<String> {
|
||||||
self.default_value.as_ref().map(|v| format!("{}", v))
|
self.default_value.as_ref().map(|v| format!("{}", v))
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
graphql_object!(EnumValue: () as "__EnumValue" where Scalar = <S> |&self| {
|
#[crate::impl_object_internal(
|
||||||
field name() -> &String {
|
name = "__EnumValue",
|
||||||
|
Scalar = S,
|
||||||
|
)]
|
||||||
|
impl<'a, S> EnumValue
|
||||||
|
where
|
||||||
|
S: crate::ScalarValue + 'a,
|
||||||
|
{
|
||||||
|
fn name(&self) -> &String {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
field description() -> &Option<String> {
|
fn description(&self) -> &Option<String> {
|
||||||
&self.description
|
&self.description
|
||||||
}
|
}
|
||||||
|
|
||||||
field is_deprecated() -> bool {
|
fn is_deprecated(&self) -> bool {
|
||||||
self.deprecation_status.is_deprecated()
|
self.deprecation_status.is_deprecated()
|
||||||
}
|
}
|
||||||
|
|
||||||
field deprecation_reason() -> Option<&String> {
|
fn deprecation_reason(&self) -> Option<&String> {
|
||||||
self.deprecation_status.reason()
|
self.deprecation_status.reason()
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
graphql_object!(<'a> DirectiveType<'a, S>: SchemaType<'a, S> as "__Directive"
|
#[crate::impl_object_internal(
|
||||||
where Scalar = <S: 'a> |&self|
|
name = "__Directive",
|
||||||
|
Context = SchemaType<'a, S>,
|
||||||
|
Scalar = S,
|
||||||
|
)]
|
||||||
|
impl<'a, S> DirectiveType<'a, S>
|
||||||
|
where
|
||||||
|
S: crate::ScalarValue + 'a,
|
||||||
{
|
{
|
||||||
field name() -> &String {
|
fn name(&self) -> &String {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
field description() -> &Option<String> {
|
fn description(&self) -> &Option<String> {
|
||||||
&self.description
|
&self.description
|
||||||
}
|
}
|
||||||
|
|
||||||
field locations() -> &Vec<DirectiveLocation> {
|
fn locations(&self) -> &Vec<DirectiveLocation> {
|
||||||
&self.locations
|
&self.locations
|
||||||
}
|
}
|
||||||
|
|
||||||
field args() -> &Vec<Argument<S>> {
|
fn args(&self) -> &Vec<Argument<S>> {
|
||||||
&self.arguments
|
&self.arguments
|
||||||
}
|
}
|
||||||
|
|
||||||
// Included for compatibility with the introspection query in GraphQL.js
|
// Included for compatibility with the introspection query in GraphQL.js
|
||||||
field deprecated "Use the locations array instead"
|
#[graphql(deprecated = "Use the locations array instead")]
|
||||||
on_operation() -> bool {
|
fn on_operation(&self) -> bool {
|
||||||
self.locations.contains(&DirectiveLocation::Query)
|
self.locations.contains(&DirectiveLocation::Query)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Included for compatibility with the introspection query in GraphQL.js
|
// Included for compatibility with the introspection query in GraphQL.js
|
||||||
field deprecated "Use the locations array instead"
|
#[graphql(deprecated = "Use the locations array instead")]
|
||||||
on_fragment() -> bool {
|
fn on_fragment(&self) -> bool {
|
||||||
self.locations.contains(&DirectiveLocation::FragmentDefinition) ||
|
self.locations
|
||||||
self.locations.contains(&DirectiveLocation::InlineFragment) ||
|
.contains(&DirectiveLocation::FragmentDefinition)
|
||||||
self.locations.contains(&DirectiveLocation::FragmentSpread)
|
|| self.locations.contains(&DirectiveLocation::InlineFragment)
|
||||||
|
|| self.locations.contains(&DirectiveLocation::FragmentSpread)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Included for compatibility with the introspection query in GraphQL.js
|
// Included for compatibility with the introspection query in GraphQL.js
|
||||||
field deprecated "Use the locations array instead"
|
#[graphql(deprecated = "Use the locations array instead")]
|
||||||
on_field() -> bool {
|
fn on_field(&self) -> bool {
|
||||||
self.locations.contains(&DirectiveLocation::Field)
|
self.locations.contains(&DirectiveLocation::Field)
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
|
@ -29,80 +29,93 @@ graphql_interface!(<'a> &'a Character: Database as "Character" |&self| {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
graphql_object!(<'a> &'a Human: Database as "Human" |&self| {
|
#[crate::impl_object_internal(
|
||||||
description: "A humanoid creature in the Star Wars universe."
|
Context = Database,
|
||||||
|
Scalar = crate::DefaultScalarValue,
|
||||||
interfaces: [&Character]
|
interfaces = [&dyn Character],
|
||||||
|
)]
|
||||||
field id() -> &str as "The id of the human"{
|
/// A humanoid creature in the Star Wars universe.
|
||||||
|
impl<'a> &'a Human {
|
||||||
|
/// The id of the human
|
||||||
|
fn id(&self) -> &str {
|
||||||
self.id()
|
self.id()
|
||||||
}
|
}
|
||||||
|
|
||||||
field name() -> Option<&str> as "The name of the human" {
|
/// The name of the human
|
||||||
|
fn name(&self) -> Option<&str> {
|
||||||
Some(self.name())
|
Some(self.name())
|
||||||
}
|
}
|
||||||
|
|
||||||
field friends(&executor) -> Vec<&Character>
|
/// The friends of the human
|
||||||
as "The friends of the human" {
|
fn friends(&self, ctx: &Database) -> Vec<&Character> {
|
||||||
executor.context().get_friends(self.as_character())
|
ctx.get_friends(self.as_character())
|
||||||
}
|
}
|
||||||
|
|
||||||
field appears_in() -> &[Episode] as "Which movies they appear in" {
|
/// Which movies they appear in
|
||||||
|
fn appears_in(&self) -> &[Episode] {
|
||||||
self.appears_in()
|
self.appears_in()
|
||||||
}
|
}
|
||||||
|
|
||||||
field home_planet() -> &Option<String> as "The home planet of the human" {
|
/// The home planet of the human
|
||||||
|
fn home_planet(&self) -> &Option<String> {
|
||||||
self.home_planet()
|
self.home_planet()
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
graphql_object!(<'a> &'a Droid: Database as "Droid" |&self| {
|
#[crate::impl_object_internal(
|
||||||
description: "A mechanical creature in the Star Wars universe."
|
Context = Database,
|
||||||
|
Scalar = crate::DefaultScalarValue,
|
||||||
interfaces: [&Character]
|
interfaces = [&dyn Character],
|
||||||
|
)]
|
||||||
field id() -> &str as "The id of the droid" {
|
/// A mechanical creature in the Star Wars universe.
|
||||||
|
impl<'a> &'a Droid {
|
||||||
|
/// The id of the droid
|
||||||
|
fn id(&self) -> &str {
|
||||||
self.id()
|
self.id()
|
||||||
}
|
}
|
||||||
|
|
||||||
field name() -> Option<&str> as "The name of the droid" {
|
/// The name of the droid
|
||||||
|
fn name(&self) -> Option<&str> {
|
||||||
Some(self.name())
|
Some(self.name())
|
||||||
}
|
}
|
||||||
|
|
||||||
field friends(&executor) -> Vec<&Character>
|
/// The friends of the droid
|
||||||
as "The friends of the droid" {
|
fn friends(&self, ctx: &Database) -> Vec<&Character> {
|
||||||
executor.context().get_friends(self.as_character())
|
ctx.get_friends(self.as_character())
|
||||||
}
|
}
|
||||||
|
|
||||||
field appears_in() -> &[Episode] as "Which movies they appear in" {
|
/// Which movies they appear in
|
||||||
|
fn appears_in(&self) -> &[Episode] {
|
||||||
self.appears_in()
|
self.appears_in()
|
||||||
}
|
}
|
||||||
|
|
||||||
field primary_function() -> &Option<String> as "The primary function of the droid" {
|
/// The primary function of the droid
|
||||||
|
fn primary_function(&self) -> &Option<String> {
|
||||||
self.primary_function()
|
self.primary_function()
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
graphql_object!(Database: Database as "Query" |&self| {
|
#[crate::impl_object_internal(
|
||||||
description: "The root query object of the schema"
|
name = "Query",
|
||||||
|
Context = Database,
|
||||||
field human(
|
Scalar = crate::DefaultScalarValue,
|
||||||
id: String as "id of the human"
|
)]
|
||||||
) -> Option<&Human> {
|
/// The root query object of the schema
|
||||||
|
impl Database {
|
||||||
|
#[graphql(arguments(id(description = "id of the human")))]
|
||||||
|
fn human(&self, id: String) -> Option<&Human> {
|
||||||
self.get_human(&id)
|
self.get_human(&id)
|
||||||
}
|
}
|
||||||
|
|
||||||
field droid(
|
#[graphql(arguments(id(description = "id of the droid")))]
|
||||||
id: String as "id of the droid"
|
fn droid(&self, id: String) -> Option<&Droid> {
|
||||||
) -> Option<&Droid> {
|
|
||||||
self.get_droid(&id)
|
self.get_droid(&id)
|
||||||
}
|
}
|
||||||
|
|
||||||
field hero(
|
#[graphql(arguments(episode(
|
||||||
episode: Option<Episode> as
|
description = "If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode"
|
||||||
"If omitted, returns the hero of the whole saga. If provided, returns \
|
)))]
|
||||||
the hero of that particular episode"
|
fn hero(&self, episode: Option<Episode>) -> Option<&Character> {
|
||||||
) -> Option<&Character> {
|
|
||||||
Some(self.get_hero(episode).as_character())
|
Some(self.get_hero(episode).as_character())
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
|
@ -344,56 +344,56 @@ pub(crate) fn schema_introspection_result() -> value::Value {
|
||||||
{
|
{
|
||||||
"kind": "ENUM",
|
"kind": "ENUM",
|
||||||
"name": "__TypeKind",
|
"name": "__TypeKind",
|
||||||
"description": "GraphQL type kind\nThe GraphQL specification defines a number of type kinds - the meta type of a type.",
|
"description": "GraphQL type kind\n\nThe GraphQL specification defines a number of type kinds - the meta type of a type.",
|
||||||
"fields": Null,
|
"fields": Null,
|
||||||
"inputFields": Null,
|
"inputFields": Null,
|
||||||
"interfaces": Null,
|
"interfaces": Null,
|
||||||
"enumValues": [
|
"enumValues": [
|
||||||
{
|
{
|
||||||
"name": "SCALAR",
|
"name": "SCALAR",
|
||||||
"description": "## Scalar types\nScalar types appear as the leaf nodes of GraphQL queries. Strings, numbers, and booleans are the built in types, and while it's possible to define your own, it's relatively uncommon.",
|
"description": "## Scalar types\n\nScalar types appear as the leaf nodes of GraphQL queries. Strings, numbers, and booleans are the built in types, and while it's possible to define your own, it's relatively uncommon.",
|
||||||
"isDeprecated": false,
|
"isDeprecated": false,
|
||||||
"deprecationReason": Null
|
"deprecationReason": Null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "OBJECT",
|
"name": "OBJECT",
|
||||||
"description": "## Object types\nThe most common type to be implemented by users. Objects have fields and can implement interfaces.",
|
"description": "## Object types\n\nThe most common type to be implemented by users. Objects have fields and can implement interfaces.",
|
||||||
"isDeprecated": false,
|
"isDeprecated": false,
|
||||||
"deprecationReason": Null
|
"deprecationReason": Null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "INTERFACE",
|
"name": "INTERFACE",
|
||||||
"description": "## Interface types\nInterface types are used to represent overlapping fields between multiple types, and can be queried for their concrete type.",
|
"description": "## Interface types\n\nInterface types are used to represent overlapping fields between multiple types, and can be queried for their concrete type.",
|
||||||
"isDeprecated": false,
|
"isDeprecated": false,
|
||||||
"deprecationReason": Null
|
"deprecationReason": Null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "UNION",
|
"name": "UNION",
|
||||||
"description": "## Union types\nUnions are similar to interfaces but can not contain any fields on their own.",
|
"description": "## Union types\n\nUnions are similar to interfaces but can not contain any fields on their own.",
|
||||||
"isDeprecated": false,
|
"isDeprecated": false,
|
||||||
"deprecationReason": Null
|
"deprecationReason": Null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "ENUM",
|
"name": "ENUM",
|
||||||
"description": "## Enum types\nLike scalars, enum types appear as the leaf nodes of GraphQL queries.",
|
"description": "## Enum types\n\nLike scalars, enum types appear as the leaf nodes of GraphQL queries.",
|
||||||
"isDeprecated": false,
|
"isDeprecated": false,
|
||||||
"deprecationReason": Null
|
"deprecationReason": Null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "INPUT_OBJECT",
|
"name": "INPUT_OBJECT",
|
||||||
"description": "## Input objects\nRepresents complex values provided in queries _into_ the system.",
|
"description": "## Input objects\n\nRepresents complex values provided in queries _into_ the system.",
|
||||||
"isDeprecated": false,
|
"isDeprecated": false,
|
||||||
"deprecationReason": Null
|
"deprecationReason": Null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "LIST",
|
"name": "LIST",
|
||||||
"description": "## List types\nRepresent lists of other types. This library provides implementations for vectors and slices, but other Rust types can be extended to serve as GraphQL lists.",
|
"description": "## List types\n\nRepresent lists of other types. This library provides implementations for vectors and slices, but other Rust types can be extended to serve as GraphQL lists.",
|
||||||
"isDeprecated": false,
|
"isDeprecated": false,
|
||||||
"deprecationReason": Null
|
"deprecationReason": Null
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "NON_NULL",
|
"name": "NON_NULL",
|
||||||
"description": "## Non-null types\nIn GraphQL, nullable types are the default. By putting a `!` after a type, it becomes non-nullable.",
|
"description": "## Non-null types\n\nIn GraphQL, nullable types are the default. By putting a `!` after a type, it becomes non-nullable.",
|
||||||
"isDeprecated": false,
|
"isDeprecated": false,
|
||||||
"deprecationReason": Null
|
"deprecationReason": Null
|
||||||
}
|
}
|
||||||
|
@ -827,6 +827,7 @@ pub(crate) fn schema_introspection_result() -> value::Value {
|
||||||
"args": [
|
"args": [
|
||||||
{
|
{
|
||||||
"name": "id",
|
"name": "id",
|
||||||
|
"description": Null,
|
||||||
"description": "id of the droid",
|
"description": "id of the droid",
|
||||||
"type": {
|
"type": {
|
||||||
"kind": "NON_NULL",
|
"kind": "NON_NULL",
|
||||||
|
|
|
@ -12,33 +12,33 @@ use crate::schema::meta::{Argument, MetaType};
|
||||||
|
|
||||||
/// GraphQL type kind
|
/// GraphQL type kind
|
||||||
///
|
///
|
||||||
/// The GraphQL specification defines a number of type kinds - the meta type
|
/// The GraphQL specification defines a number of type kinds - the meta type\
|
||||||
/// of a type.
|
/// of a type.
|
||||||
#[derive(Clone, Eq, PartialEq, Debug, GraphQLEnum)]
|
#[derive(Clone, Eq, PartialEq, Debug, GraphQLEnum)]
|
||||||
#[graphql(name = "__TypeKind")]
|
#[graphql(name = "__TypeKind")]
|
||||||
pub enum TypeKind {
|
pub enum TypeKind {
|
||||||
/// ## Scalar types
|
/// ## Scalar types
|
||||||
///
|
///
|
||||||
/// Scalar types appear as the leaf nodes of GraphQL queries. Strings,
|
/// Scalar types appear as the leaf nodes of GraphQL queries. Strings,\
|
||||||
/// numbers, and booleans are the built in types, and while it's possible
|
/// numbers, and booleans are the built in types, and while it's possible\
|
||||||
/// to define your own, it's relatively uncommon.
|
/// to define your own, it's relatively uncommon.
|
||||||
Scalar,
|
Scalar,
|
||||||
|
|
||||||
/// ## Object types
|
/// ## Object types
|
||||||
///
|
///
|
||||||
/// The most common type to be implemented by users. Objects have fields
|
/// The most common type to be implemented by users. Objects have fields\
|
||||||
/// and can implement interfaces.
|
/// and can implement interfaces.
|
||||||
Object,
|
Object,
|
||||||
|
|
||||||
/// ## Interface types
|
/// ## Interface types
|
||||||
///
|
///
|
||||||
/// Interface types are used to represent overlapping fields between
|
/// Interface types are used to represent overlapping fields between\
|
||||||
/// multiple types, and can be queried for their concrete type.
|
/// multiple types, and can be queried for their concrete type.
|
||||||
Interface,
|
Interface,
|
||||||
|
|
||||||
/// ## Union types
|
/// ## Union types
|
||||||
///
|
///
|
||||||
/// Unions are similar to interfaces but can not contain any fields on
|
/// Unions are similar to interfaces but can not contain any fields on\
|
||||||
/// their own.
|
/// their own.
|
||||||
Union,
|
Union,
|
||||||
|
|
||||||
|
@ -55,14 +55,14 @@ pub enum TypeKind {
|
||||||
|
|
||||||
/// ## List types
|
/// ## List types
|
||||||
///
|
///
|
||||||
/// Represent lists of other types. This library provides implementations
|
/// Represent lists of other types. This library provides implementations\
|
||||||
/// for vectors and slices, but other Rust types can be extended to serve
|
/// for vectors and slices, but other Rust types can be extended to serve\
|
||||||
/// as GraphQL lists.
|
/// as GraphQL lists.
|
||||||
List,
|
List,
|
||||||
|
|
||||||
/// ## Non-null types
|
/// ## Non-null types
|
||||||
///
|
///
|
||||||
/// In GraphQL, nullable types are the default. By putting a `!` after a
|
/// In GraphQL, nullable types are the default. By putting a `!` after a\
|
||||||
/// type, it becomes non-nullable.
|
/// type, it becomes non-nullable.
|
||||||
#[graphql(name = "NON_NULL")]
|
#[graphql(name = "NON_NULL")]
|
||||||
NonNull,
|
NonNull,
|
||||||
|
|
Loading…
Add table
Reference in a new issue