Fix attributes naming on fields and arguments for interfaces and unions (#806)

Additionally:
- revive macros/tests/object
- revive executor_tests/interfaces_unions
This commit is contained in:
Kai Ren 2020-11-14 14:41:01 +01:00 committed by GitHub
parent bcbf44ecbd
commit 3472fe6d10
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 213 additions and 344 deletions

View file

@ -167,7 +167,7 @@ use juniper::{graphql_interface, GraphQLObject};
trait Character {
fn id(&self) -> &str;
#[graphql_interface(ignore)] // or `#[graphql_interface(skip)]`, your choice
#[graphql(ignore)] // or `#[graphql(skip)]`, your choice
fn ignored(&self) -> u32 { 0 }
}
@ -205,26 +205,26 @@ use juniper::graphql_interface;
/// This doc is absent in GraphQL schema.
trait Character {
// Renames the field in GraphQL schema.
#[graphql_interface(name = "myId")]
#[graphql(name = "myId")]
// Deprecates the field in GraphQL schema.
// Usual Rust `#[deprecated]` attribute is supported too as field deprecation,
// but `deprecated` attribute argument takes precedence over it, if specified.
#[graphql_interface(deprecated = "Do not use it.")]
#[graphql(deprecated = "Do not use it.")]
// Describes the field in GraphQL schema.
#[graphql_interface(description = "ID of my own character.")]
#[graphql(description = "ID of my own character.")]
// Usual Rust docs are supported too as field description,
// but `description` attribute argument takes precedence over them, if specified.
/// This description is absent in GraphQL schema.
fn id(
&self,
// Renames the argument in GraphQL schema.
#[graphql_interface(name = "myNum")]
#[graphql(name = "myNum")]
// Describes the argument in GraphQL schema.
#[graphql_interface(description = "ID number of my own character.")]
#[graphql(description = "ID number of my own character.")]
// Specifies the default value for the argument.
// The concrete value may be omitted, and the `Default::default` one
// will be used in such case.
#[graphql_interface(default = 5)]
#[graphql(default = 5)]
num: i32,
) -> &str;
}
@ -254,7 +254,7 @@ trait Character { // while still can be specified via `Context =
fn id(&self, context: &Database) -> Option<&str>;
// Otherwise, you may mark it explicitly as a context argument.
fn name(&self, #[graphql_interface(context)] db: &Database) -> Option<&str>;
fn name(&self, #[graphql(context)] db: &Database) -> Option<&str>;
}
#[derive(GraphQLObject)]
@ -307,7 +307,7 @@ trait Character<S: ScalarValue> {
// Otherwise, you may mark it explicitly as an executor argument.
async fn name<'b>(
&'b self,
#[graphql_interface(executor)] another: &Executor<'_, '_, (), S>,
#[graphql(executor)] another: &Executor<'_, '_, (), S>,
) -> &'b str
where
S: Send + Sync;
@ -319,7 +319,7 @@ struct Human {
id: String,
name: String,
}
#[graphql_interface(Scalar = S)]
#[graphql_interface(scalar = S)]
impl<S: ScalarValue> Character<S> for Human {
async fn id<'a>(&self, executor: &'a Executor<'_, '_, (), S>) -> &'a str
where
@ -356,12 +356,12 @@ struct Database {
}
impl juniper::Context for Database {}
#[graphql_interface(for = [Human, Droid], Context = Database)]
#[graphql_interface(for = [Human, Droid], context = Database)]
#[graphql_interface(on Droid = get_droid)] // enables downcasting `Droid` via `get_droid()` function
trait Character {
fn id(&self) -> &str;
#[graphql_interface(downcast)] // makes method a downcast to `Human`, not a field
#[graphql(downcast)] // makes method a downcast to `Human`, not a field
// NOTICE: The method signature may optionally contain `&Database` context argument.
fn as_human(&self) -> Option<&Human> {
None
@ -419,7 +419,7 @@ By default, `#[graphql_interface]` macro generates code, which is generic over a
use juniper::{graphql_interface, DefaultScalarValue, GraphQLObject};
#[graphql_interface(for = [Human, Droid])]
#[graphql_interface(Scalar = DefaultScalarValue)] // removing this line will fail compilation
#[graphql_interface(scalar = DefaultScalarValue)] // removing this line will fail compilation
trait Character {
fn id(&self) -> &str;
}
@ -430,7 +430,7 @@ struct Human {
id: String,
home_planet: String,
}
#[graphql_interface(Scalar = DefaultScalarValue)]
#[graphql_interface(scalar = DefaultScalarValue)]
impl Character for Human {
fn id(&self) -> &str {
&self.id
@ -443,7 +443,7 @@ struct Droid {
id: String,
primary_function: String,
}
#[graphql_interface(Scalar = DefaultScalarValue)]
#[graphql_interface(scalar = DefaultScalarValue)]
impl Character for Droid {
fn id(&self) -> &str {
&self.id

View file

@ -316,7 +316,7 @@ struct Database {
}
impl juniper::Context for Database {}
#[graphql_union(Context = Database)]
#[graphql_union(context = Database)]
trait Character {
// NOTICE: The method signature may optionally contain `&Context`.
fn as_human<'db>(&self, ctx: &'db Database) -> Option<&'db Human> { None }
@ -363,7 +363,7 @@ struct Droid {
trait Character {
fn as_human(&self) -> Option<&Human> { None }
fn as_droid(&self) -> Option<&Droid> { None }
#[graphql_union(ignore)] // or `#[graphql_union(skip)]`, your choice
#[graphql(ignore)] // or `#[graphql(skip)]`, your choice
fn id(&self) -> &str;
}
@ -410,13 +410,13 @@ struct Database {
}
impl juniper::Context for Database {}
#[graphql_union(Context = Database)]
#[graphql_union(context = Database)]
#[graphql_union(
on Human = DynCharacter::get_human,
on Droid = get_droid,
)]
trait Character {
#[graphql_union(ignore)] // or `#[graphql_union(skip)]`, your choice
#[graphql(ignore)] // or `#[graphql(skip)]`, your choice
fn id(&self) -> &str;
}

View file

@ -22,7 +22,7 @@ impl Character for ObjA {
trait Character {
fn id(&self, num: i32) -> &str;
#[graphql_interface(downcast)]
#[graphql(downcast)]
fn as_obja(&self) -> Option<&ObjA>;
}

View file

@ -5,7 +5,7 @@ error: GraphQL interface trait method `as_obja` conflicts with the external down
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: https://spec.graphql.org/June2018/#sec-Interfaces
= note: use `#[graphql_interface(ignore)]` attribute argument to ignore this trait method for interface implementers downcasting
= note: use `#[graphql(ignore)]` attribute argument to ignore this trait method for interface implementers downcasting
error[E0412]: cannot find type `CharacterValue` in this scope
--> $DIR/downcast_method_conflicts_with_external_downcast_fn.rs:4:18

View file

@ -6,7 +6,7 @@ trait Character {
0
}
#[graphql_interface(downcast)]
#[graphql(downcast)]
fn a(&self, ctx: &(), rand: u8) -> Option<&Human> {
None
}

View file

@ -6,7 +6,7 @@ trait Character {
0
}
#[graphql_interface(downcast)]
#[graphql(downcast)]
fn a(&self, ctx: &(), rand: u8) -> &Human {
unimplemented!()
}

View file

@ -15,7 +15,7 @@ trait Character {
"funA"
}
#[graphql_interface(name = "id")]
#[graphql(name = "id")]
fn id2(&self) -> &str {
"funB"
}

View file

@ -5,4 +5,4 @@ error: GraphQL union trait method `a` conflicts with the external resolver funct
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: https://spec.graphql.org/June2018/#sec-Unions
= note: use `#[graphql_union(ignore)]` attribute to ignore this trait method for union variants resolution
= note: use `#[graphql(ignore)]` attribute to ignore this trait method for union variants resolution

View file

@ -2,7 +2,7 @@ use juniper::{graphql_union, GraphQLObject};
#[graphql_union]
trait Character {
#[graphql_union(with = something)]
#[graphql(with = something)]
fn a(&self) -> Option<&Human>;
}

View file

@ -1,8 +1,8 @@
error: GraphQL union cannot use #[graphql_union(with = ...)] attribute on a trait method
--> $DIR/trait_with_attr_on_method.rs:5:21
error: GraphQL union cannot use #[graphql(with = ...)] attribute on a trait method
--> $DIR/trait_with_attr_on_method.rs:5:15
|
5 | #[graphql_union(with = something)]
| ^^^^
5 | #[graphql(with = something)]
| ^^^^
|
= note: https://spec.graphql.org/June2018/#sec-Unions
= note: instead use #[graphql_union(ignore)] on the method with #[graphql_union(on ... = ...)] on the trait itself
= note: instead use #[graphql(ignore)] on the method with #[graphql_union(on ... = ...)] on the trait itself

View file

@ -2451,9 +2451,9 @@ mod default_argument {
trait Character {
async fn id(
&self,
#[graphql_interface(default)] first: String,
#[graphql_interface(default = "second".to_string())] second: String,
#[graphql_interface(default = "t")] third: String,
#[graphql(default)] first: String,
#[graphql(default = "second".to_string())] second: String,
#[graphql(default = "t")] third: String,
) -> String;
}
@ -2741,14 +2741,14 @@ mod explicit_name_description_and_deprecation {
#[graphql_interface(name = "MyChar", desc = "My character.", for = Human)]
trait Character {
/// Rust `id` docs.
#[graphql_interface(name = "myId", desc = "My character ID.", deprecated = "Not used.")]
#[graphql(name = "myId", desc = "My character ID.", deprecated = "Not used.")]
#[deprecated(note = "Should be omitted.")]
fn id(
&self,
#[graphql_interface(name = "myName", desc = "My argument.", default)] n: Option<String>,
#[graphql(name = "myName", desc = "My argument.", default)] n: Option<String>,
) -> &str;
#[graphql_interface(deprecated)]
#[graphql(deprecated)]
#[deprecated(note = "Should be omitted.")]
fn a(&self) -> &str {
"a"
@ -3605,7 +3605,7 @@ mod explicit_custom_context {
async fn info<'b>(&'b self, ctx: &()) -> &'b str;
fn more<'c>(&'c self, #[graphql_interface(context)] custom: &CustomContext) -> &'c str;
fn more<'c>(&'c self, #[graphql(context)] custom: &CustomContext) -> &'c str;
}
#[graphql_interface(dyn = DynHero, for = [Human, Droid])]
@ -3615,7 +3615,7 @@ mod explicit_custom_context {
async fn info<'b>(&'b self, ctx: &()) -> &'b str;
fn more<'c>(&'c self, #[graphql_interface(context)] custom: &CustomContext) -> &'c str;
fn more<'c>(&'c self, #[graphql(context)] custom: &CustomContext) -> &'c str;
}
#[derive(GraphQLObject)]
@ -4118,7 +4118,7 @@ mod inferred_custom_context_from_downcast {
#[graphql_interface(for = [Human, Droid])]
trait Character {
#[graphql_interface(downcast)]
#[graphql(downcast)]
fn as_human<'s>(&'s self, _: &Database) -> Option<&'s Human>;
async fn id(&self) -> &str;
@ -4126,7 +4126,7 @@ mod inferred_custom_context_from_downcast {
#[graphql_interface(dyn = DynHero, for = [Human, Droid])]
trait Hero {
#[graphql_interface(downcast)]
#[graphql(downcast)]
fn as_droid<'db>(&self, db: &'db Database) -> Option<&'db Droid>;
async fn info(&self) -> &str;
@ -4390,7 +4390,7 @@ mod executor {
async fn info<'b>(
&'b self,
#[graphql_interface(executor)] another: &Executor<'_, '_, (), S>,
#[graphql(executor)] another: &Executor<'_, '_, (), S>,
) -> &'b str
where
S: Send + Sync;
@ -4407,7 +4407,7 @@ mod executor {
async fn info<'b>(
&'b self,
#[graphql_interface(executor)] another: &Executor<'_, '_, (), S>,
#[graphql(executor)] another: &Executor<'_, '_, (), S>,
) -> &'b str
where
S: Send + Sync;
@ -4631,12 +4631,12 @@ mod ignored_method {
trait Character {
fn id(&self) -> &str;
#[graphql_interface(ignore)]
#[graphql(ignore)]
fn ignored(&self) -> Option<&Human> {
None
}
#[graphql_interface(skip)]
#[graphql(skip)]
fn skipped(&self) {}
}
@ -4734,7 +4734,7 @@ mod downcast_method {
trait Character {
fn id(&self) -> &str;
#[graphql_interface(downcast)]
#[graphql(downcast)]
fn as_human(&self) -> Option<&Human> {
None
}
@ -4744,7 +4744,7 @@ mod downcast_method {
trait Hero {
fn info(&self) -> &str;
#[graphql_interface(downcast)]
#[graphql(downcast)]
fn as_droid(&self) -> Option<&Droid> {
None
}

View file

@ -842,11 +842,11 @@ mod ignored_method {
fn as_human(&self) -> Option<&Human> {
None
}
#[graphql_union(ignore)]
#[graphql(ignore)]
fn ignored(&self) -> Option<&Ewok> {
None
}
#[graphql_union(skip)]
#[graphql(skip)]
fn skipped(&self) {}
}
@ -1030,11 +1030,11 @@ mod full_featured {
fn as_droid(&self) -> Option<&DroidCustomContext> {
None
}
#[graphql_union(ignore)]
#[graphql(ignore)]
fn as_ewok(&self) -> Option<&EwokCustomContext> {
None
}
#[graphql_union(ignore)]
#[graphql(ignore)]
fn ignored(&self) {}
}

View file

@ -1,35 +1,31 @@
mod interface {
use crate::{
graphql_interface, graphql_object,
schema::model::RootNode,
types::scalars::{EmptyMutation, EmptySubscription},
value::Value,
};
#[graphql_interface(for = [Cat, Dog])]
trait Pet {
fn name(&self) -> &str;
#[graphql(downcast)]
fn as_dog(&self) -> Option<&Dog> {
None
}
#[graphql(downcast)]
fn as_cat(&self) -> Option<&Cat> {
None
}
}
graphql_interface!(<'a> &'a dyn Pet: () as "Pet" |&self| {
field name() -> &str { self.name() }
instance_resolvers: |&_| {
&Dog => self.as_dog(),
&Cat => self.as_cat(),
}
});
struct Dog {
name: String,
woofs: bool,
}
#[graphql_interface]
impl Pet for Dog {
fn name(&self) -> &str {
&self.name
@ -39,9 +35,7 @@ mod interface {
}
}
#[crate::graphql_object(
interfaces = [&dyn Pet]
)]
#[graphql_object(impl = PetValue)]
impl Dog {
fn name(&self) -> &str {
&self.name
@ -56,6 +50,7 @@ mod interface {
meows: bool,
}
#[graphql_interface]
impl Pet for Cat {
fn name(&self) -> &str {
&self.name
@ -65,9 +60,7 @@ mod interface {
}
}
#[crate::graphql_object(
interfaces = [&dyn Pet]
)]
#[graphql_object(impl = PetValue)]
impl Cat {
fn name(&self) -> &str {
&self.name
@ -78,13 +71,13 @@ mod interface {
}
struct Schema {
pets: Vec<Box<dyn Pet>>,
pets: Vec<PetValue>,
}
#[crate::graphql_object]
#[graphql_object]
impl Schema {
fn pets(&self) -> Vec<&dyn Pet> {
self.pets.iter().map(|p| p.as_ref()).collect()
fn pets(&self) -> &Vec<PetValue> {
&self.pets
}
}
@ -93,14 +86,16 @@ mod interface {
let schema = RootNode::new(
Schema {
pets: vec![
Box::new(Dog {
Dog {
name: "Odie".to_owned(),
woofs: true,
}),
Box::new(Cat {
}
.into(),
Cat {
name: "Garfield".to_owned(),
meows: false,
}),
}
.into(),
],
},
EmptyMutation::<()>::new(),
@ -162,12 +157,13 @@ mod interface {
mod union {
use crate::{
graphql_object, graphql_union,
schema::model::RootNode,
types::scalars::{EmptyMutation, EmptySubscription},
value::Value,
};
#[crate::graphql_union]
#[graphql_union]
trait Pet {
fn as_dog(&self) -> Option<&Dog> {
None
@ -188,7 +184,7 @@ mod union {
}
}
#[crate::graphql_object]
#[graphql_object]
impl Dog {
fn name(&self) -> &str {
&self.name
@ -209,7 +205,7 @@ mod union {
}
}
#[crate::graphql_object]
#[graphql_object]
impl Cat {
fn name(&self) -> &str {
&self.name
@ -220,12 +216,12 @@ mod union {
}
struct Schema {
pets: Vec<Box<dyn Pet>>,
pets: Vec<Box<dyn Pet + Send + Sync>>,
}
#[crate::graphql_object]
#[graphql_object]
impl Schema {
fn pets(&self) -> Vec<&dyn Pet> {
fn pets(&self) -> Vec<&(dyn Pet + Send + Sync)> {
self.pets.iter().map(|p| p.as_ref()).collect()
}
}

View file

@ -4,8 +4,6 @@ mod executor;
mod introspection;
mod variables;
// FIXME: re-enable
#[cfg(TODO)]
mod interfaces_unions;
mod async_await;

View file

@ -151,13 +151,13 @@ impl Interface for Root {
trait Interface {
fn simple(&self) -> i32;
#[graphql_interface(desc = "Field description")]
#[graphql(desc = "Field description")]
fn description(&self) -> i32;
#[graphql_interface(deprecated = "Deprecation reason")]
#[graphql(deprecated = "Deprecation reason")]
fn deprecated(&self) -> i32;
#[graphql_interface(desc = "Field description", deprecated = "Deprecation reason")]
#[graphql(desc = "Field description", deprecated = "Deprecation reason")]
fn deprecated_descr(&self) -> i32;
/// Field description

View file

@ -1,18 +1,4 @@
// TODO: make sure proc macro tests cover all
// variants of the below
/*
use std::marker::PhantomData;
use crate::{
ast::InputValue,
executor::{Context, FieldResult},
schema::model::RootNode,
types::scalars::{EmptyMutation, EmptySubscription},
value::{DefaultScalarValue, Object, Value},
};
Syntax to validate:
* Order of items: fields, description, interfaces
@ -20,125 +6,125 @@ Syntax to validate:
* Custom name vs. default name
* Optional commas between items
* Nullable/fallible context switching
*/
*/
#![allow(dead_code)]
use std::marker::PhantomData;
use crate::{
ast::InputValue,
executor::{Context, FieldResult},
graphql_interface, graphql_object,
schema::model::RootNode,
types::scalars::{EmptyMutation, EmptySubscription},
value::{DefaultScalarValue, Object, Value},
GraphQLObject,
};
/*
struct CustomName;
graphql_object!(CustomName: () as "ACustomNamedType" |&self| {
field simple() -> i32 { 0 }
});
#[allow(dead_code)]
#[graphql_object(name = "ACustomNamedType")]
impl CustomName {
fn simple() -> i32 {
0
}
}
struct WithLifetime<'a> {
data: PhantomData<&'a i32>,
}
graphql_object!(<'a> WithLifetime<'a>: () as "WithLifetime" |&self| {
field simple() -> i32 { 0 }
});
#[allow(dead_code)]
#[graphql_object]
impl<'a> WithLifetime<'a> {
fn simple() -> i32 {
0
}
}
struct WithGenerics<T> {
data: T,
}
graphql_object!(<T> WithGenerics<T>: () as "WithGenerics" |&self| {
field simple() -> i32 { 0 }
});
struct Interface;
struct DescriptionFirst;
graphql_interface!(Interface: () |&self| {
field simple() -> i32 { 0 }
instance_resolvers: |_| {
DescriptionFirst => Some(DescriptionFirst {}),
#[graphql_object]
impl<T> WithGenerics<T> {
fn simple() -> i32 {
0
}
});
graphql_object!(DescriptionFirst: () |&self| {
description: "A description"
}
field simple() -> i32 { 0 }
#[graphql_interface(for = SimpleObject)]
trait Interface {
fn simple(&self) -> i32 {
0
}
}
interfaces: [Interface]
});
#[derive(GraphQLObject)]
#[graphql(impl = InterfaceValue, description = "A description")]
struct SimpleObject {
simple: i32,
}
struct FieldsFirst;
graphql_object!(FieldsFirst: () |&self| {
field simple() -> i32 { 0 }
description: "A description"
interfaces: [Interface]
});
struct InterfacesFirst;
graphql_object!(InterfacesFirst: ()|&self| {
interfaces: [Interface]
field simple() -> i32 { 0 }
description: "A description"
});
struct CommasWithTrailing;
graphql_object!(CommasWithTrailing: () |&self| {
interfaces: [Interface],
field simple() -> i32 { 0 },
description: "A description",
});
struct CommasOnMeta;
graphql_object!(CommasOnMeta: () |&self| {
interfaces: [Interface],
description: "A description",
field simple() -> i32 { 0 }
});
struct Root;
#[graphql_interface]
impl Interface for SimpleObject {}
struct InnerContext;
impl Context for InnerContext {}
struct InnerType;
graphql_object!(InnerType: InnerContext | &self | {});
#[derive(GraphQLObject)]
#[graphql(context = InnerContext)]
struct InnerType {
a: i32,
}
struct CtxSwitcher;
graphql_object!(CtxSwitcher: InnerContext |&self| {
field ctx_switch_always(&executor) -> (&InnerContext, InnerType) {
(executor.context(), InnerType)
#[graphql_object(context = InnerContext)]
impl CtxSwitcher {
fn ctx_switch_always() -> (&InnerContext, InnerType) {
(executor.context(), InnerType { a: 0 })
}
field ctx_switch_opt(&executor) -> Option<(&InnerContext, InnerType)> {
Some((executor.context(), InnerType))
fn ctx_switch_opt() -> Option<(&InnerContext, InnerType)> {
Some((executor.context(), InnerType { a: 0 }))
}
field ctx_switch_res(&executor) -> FieldResult<(&InnerContext, InnerType)> {
Ok((executor.context(), InnerType))
fn ctx_switch_res() -> FieldResult<(&InnerContext, InnerType)> {
Ok((executor.context(), InnerType { a: 0 }))
}
field ctx_switch_res_opt(&executor) -> FieldResult<Option<(&InnerContext, InnerType)>> {
Ok(Some((executor.context(), InnerType)))
fn ctx_switch_res_opt() -> FieldResult<Option<(&InnerContext, InnerType)>> {
Ok(Some((executor.context(), InnerType { a: 0 })))
}
});
}
graphql_object!(<'a> Root: InnerContext as "Root" |&self| {
field custom_name() -> CustomName { CustomName {} }
struct Root;
field with_lifetime() -> WithLifetime<'a> { WithLifetime { data: PhantomData } }
field with_generics() -> WithGenerics<i32> { WithGenerics { data: 123 } }
#[graphql_object(context = InnerContext)]
impl Root {
fn custom_name() -> CustomName {
CustomName {}
}
field description_first() -> DescriptionFirst { DescriptionFirst {} }
field fields_first() -> FieldsFirst { FieldsFirst {} }
field interfaces_first() -> InterfacesFirst { InterfacesFirst {} }
fn with_lifetime() -> WithLifetime<'static> {
WithLifetime { data: PhantomData }
}
fn with_generics() -> WithGenerics<i32> {
WithGenerics { data: 123 }
}
field commas_with_trailing() -> CommasWithTrailing { CommasWithTrailing {} }
field commas_on_meta() -> CommasOnMeta { CommasOnMeta {} }
fn description_first() -> SimpleObject {
SimpleObject { simple: 0 }
}
fn interface() -> InterfaceValue {
SimpleObject { simple: 0 }.into()
}
field ctx_switcher() -> CtxSwitcher { CtxSwitcher {} }
});
fn ctx_switcher() -> CtxSwitcher {
CtxSwitcher {}
}
}
fn run_type_info_query<F>(type_name: &str, f: F)
where
@ -170,7 +156,7 @@ where
let schema = RootNode::new(
Root {},
EmptyMutation::<InnerContext>::new(),
EmptySubscription::<()>::new(),
EmptySubscription::<InnerContext>::new(),
);
let vars = vec![("typeName".to_owned(), InputValue::scalar(type_name))]
.into_iter()
@ -215,7 +201,11 @@ fn introspect_custom_name() {
assert!(fields.contains(&graphql_value!({
"name": "simple",
"type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "Int" } }
"type": {
"kind": "NON_NULL",
"name": None,
"ofType": { "kind": "SCALAR", "name": "Int" }
}
})));
});
}
@ -235,7 +225,9 @@ fn introspect_with_lifetime() {
assert!(fields.contains(&graphql_value!({
"name": "simple",
"type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "Int" } }
"type": {
"kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "Int" }
}
})));
});
}
@ -255,17 +247,19 @@ fn introspect_with_generics() {
assert!(fields.contains(&graphql_value!({
"name": "simple",
"type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "Int" } }
"type": {
"kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "Int" }
}
})));
});
}
#[test]
fn introspect_description_first() {
run_type_info_query("DescriptionFirst", |object, fields| {
fn introspect_simple_object() {
run_type_info_query("SimpleObject", |object, fields| {
assert_eq!(
object.get_field_value("name"),
Some(&Value::scalar("DescriptionFirst"))
Some(&Value::scalar("SimpleObject"))
);
assert_eq!(
object.get_field_value("description"),
@ -285,127 +279,9 @@ fn introspect_description_first() {
assert!(fields.contains(&graphql_value!({
"name": "simple",
"type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "Int" } }
})));
});
}
#[test]
fn introspect_fields_first() {
run_type_info_query("FieldsFirst", |object, fields| {
assert_eq!(
object.get_field_value("name"),
Some(&Value::scalar("FieldsFirst"))
);
assert_eq!(
object.get_field_value("description"),
Some(&Value::scalar("A description"))
);
assert_eq!(
object.get_field_value("interfaces"),
Some(&Value::list(vec![Value::object(
vec![
("name", Value::scalar("Interface")),
("kind", Value::scalar("INTERFACE")),
]
.into_iter()
.collect(),
)]))
);
assert!(fields.contains(&graphql_value!({
"name": "simple",
"type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "Int" } }
})));
});
}
#[test]
fn introspect_interfaces_first() {
run_type_info_query("InterfacesFirst", |object, fields| {
assert_eq!(
object.get_field_value("name"),
Some(&Value::scalar("InterfacesFirst"))
);
assert_eq!(
object.get_field_value("description"),
Some(&Value::scalar("A description"))
);
assert_eq!(
object.get_field_value("interfaces"),
Some(&Value::list(vec![Value::object(
vec![
("name", Value::scalar("Interface")),
("kind", Value::scalar("INTERFACE")),
]
.into_iter()
.collect(),
)]))
);
assert!(fields.contains(&graphql_value!({
"name": "simple",
"type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "Int" } }
})));
});
}
#[test]
fn introspect_commas_with_trailing() {
run_type_info_query("CommasWithTrailing", |object, fields| {
assert_eq!(
object.get_field_value("name"),
Some(&Value::scalar("CommasWithTrailing"))
);
assert_eq!(
object.get_field_value("description"),
Some(&Value::scalar("A description"))
);
assert_eq!(
object.get_field_value("interfaces"),
Some(&Value::list(vec![Value::object(
vec![
("name", Value::scalar("Interface")),
("kind", Value::scalar("INTERFACE")),
]
.into_iter()
.collect(),
)]))
);
assert!(fields.contains(&graphql_value!({
"name": "simple",
"type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "Int" } }
})));
});
}
#[test]
fn introspect_commas_on_meta() {
run_type_info_query("CommasOnMeta", |object, fields| {
assert_eq!(
object.get_field_value("name"),
Some(&Value::scalar("CommasOnMeta"))
);
assert_eq!(
object.get_field_value("description"),
Some(&Value::scalar("A description"))
);
assert_eq!(
object.get_field_value("interfaces"),
Some(&Value::list(vec![Value::object(
vec![
("name", Value::scalar("Interface")),
("kind", Value::scalar("INTERFACE")),
]
.into_iter()
.collect(),
)]))
);
assert!(fields.contains(&graphql_value!({
"name": "simple",
"type": { "kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "Int" } }
"type": {
"kind": "NON_NULL", "name": None, "ofType": { "kind": "SCALAR", "name": "Int" }
}
})));
});
}
@ -456,4 +332,3 @@ fn introspect_ctx_switch() {
})));
});
}
*/

View file

@ -63,7 +63,7 @@ pub trait Character {
/// Which movies they appear in
fn appears_in(&self) -> &[Episode];
#[graphql_interface(ignore)]
#[graphql(ignore)]
fn friends_ids(&self) -> &[String];
}

View file

@ -360,7 +360,7 @@ enum TraitMethod {
impl TraitMethod {
/// Parses this [`TraitMethod`] from the given trait method definition.
///
/// Returns [`None`] if the trait method marked with `#[graphql_interface(ignore)]` attribute,
/// Returns [`None`] if the trait method marked with `#[graphql(ignore)]` attribute,
/// or parsing fails.
#[must_use]
fn parse(method: &mut syn::TraitItemMethod) -> Option<Self> {
@ -369,10 +369,10 @@ impl TraitMethod {
// Remove repeated attributes from the method, to omit incorrect expansion.
method.attrs = mem::take(&mut method.attrs)
.into_iter()
.filter(|attr| !path_eq_single(&attr.path, "graphql_interface"))
.filter(|attr| !path_eq_single(&attr.path, "graphql"))
.collect();
let meta = MethodMeta::from_attrs("graphql_interface", &method_attrs)
let meta = MethodMeta::from_attrs("graphql", &method_attrs)
.map_err(|e| proc_macro_error::emit_error!(e))
.ok()?;
@ -514,10 +514,10 @@ impl TraitMethod {
// Remove repeated attributes from the method, to omit incorrect expansion.
argument.attrs = mem::take(&mut argument.attrs)
.into_iter()
.filter(|attr| !path_eq_single(&attr.path, "graphql_interface"))
.filter(|attr| !path_eq_single(&attr.path, "graphql"))
.collect();
let meta = ArgumentMeta::from_attrs("graphql_interface", &argument_attrs)
let meta = ArgumentMeta::from_attrs("graphql", &argument_attrs)
.map_err(|e| proc_macro_error::emit_error!(e))
.ok()?;
@ -551,8 +551,8 @@ impl TraitMethod {
"trait method argument should be declared as a single identifier",
)
.note(String::from(
"use `#[graphql_interface(name = ...)]` attribute to specify custom argument's \
name without requiring it being a single identifier",
"use `#[graphql(name = ...)]` attribute to specify custom argument's name without \
requiring it being a single identifier",
))
.emit();
return None;
@ -598,7 +598,7 @@ fn err_disallowed_attr<T, S: Spanned>(span: &S, arg: &str) -> Option<T> {
ERR.custom(
span.span(),
format!(
"attribute argument `#[graphql_interface({} = ...)]` is not allowed here",
"attribute argument `#[graphql({} = ...)]` is not allowed here",
arg,
),
)
@ -663,8 +663,8 @@ fn err_duplicate_downcast(
),
)
.note(String::from(
"use `#[graphql_interface(ignore)]` attribute argument to ignore this trait method for \
interface implementers downcasting",
"use `#[graphql(ignore)]` attribute argument to ignore this trait method for interface \
implementers downcasting",
))
.emit()
}

View file

@ -367,7 +367,7 @@ impl ImplMeta {
}
}
/// Available metadata (arguments) behind `#[graphql_interface]` attribute placed on a trait method
/// Available metadata (arguments) behind `#[graphql]` attribute placed on a trait method
/// definition, when generating code for [GraphQL interface][1] type.
///
/// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
@ -534,8 +534,8 @@ impl MethodMeta {
}
}
/// Available metadata (arguments) behind `#[graphql_interface]` attribute placed on a trait method
/// argument, when generating code for [GraphQL interface][1] type.
/// Available metadata (arguments) behind `#[graphql]` attribute placed on a trait method argument,
/// when generating code for [GraphQL interface][1] type.
///
/// [1]: https://spec.graphql.org/June2018/#sec-Interfaces
#[derive(Debug, Default)]

View file

@ -115,21 +115,21 @@ fn parse_variant_from_trait_method(
// Remove repeated attributes from the method, to omit incorrect expansion.
method.attrs = mem::take(&mut method.attrs)
.into_iter()
.filter(|attr| !path_eq_single(&attr.path, "graphql_union"))
.filter(|attr| !path_eq_single(&attr.path, "graphql"))
.collect();
let meta = UnionVariantMeta::from_attrs("graphql_union", &method_attrs)
let meta = UnionVariantMeta::from_attrs("graphql", &method_attrs)
.map_err(|e| proc_macro_error::emit_error!(e))
.ok()?;
if let Some(rslvr) = meta.external_resolver {
ERR.custom(
rslvr.span_ident(),
"cannot use #[graphql_union(with = ...)] attribute on a trait method",
"cannot use #[graphql(with = ...)] attribute on a trait method",
)
.note(String::from(
"instead use #[graphql_union(ignore)] on the method with \
#[graphql_union(on ... = ...)] on the trait itself",
"instead use #[graphql(ignore)] on the method with #[graphql_union(on ... = ...)] on \
the trait itself",
))
.emit()
}
@ -178,7 +178,7 @@ fn parse_variant_from_trait_method(
),
)
.note(String::from(
"use `#[graphql_union(ignore)]` attribute to ignore this trait method for union \
"use `#[graphql(ignore)]` attribute to ignore this trait method for union \
variants resolution",
))
.emit();

View file

@ -638,12 +638,12 @@ pub fn graphql_subscription(args: TokenStream, input: TokenStream) -> TokenStrea
/// #
/// #[graphql_interface(name = "Character", desc = "Possible episode characters.")]
/// trait Chrctr {
/// #[graphql_interface(name = "id", desc = "ID of the character.")]
/// #[graphql_interface(deprecated = "Don't use it")]
/// #[graphql(name = "id", desc = "ID of the character.")]
/// #[graphql(deprecated = "Don't use it")]
/// fn some_id(
/// &self,
/// #[graphql_interface(name = "number", desc = "Arbitrary number.")]
/// #[graphql_interface(default = 5)]
/// #[graphql(name = "number", desc = "Arbitrary number.")]
/// #[graphql(default = 5)]
/// num: i32,
/// ) -> &str;
/// }
@ -654,7 +654,7 @@ pub fn graphql_subscription(args: TokenStream, input: TokenStream) -> TokenStrea
/// trait CharacterWithDocs {
/// /// ID of the character.
/// #[deprecated]
/// fn id(&self, #[graphql_interface(default)] num: i32) -> &str;
/// fn id(&self, #[graphql(default)] num: i32) -> &str;
/// }
/// ```
///
@ -683,7 +683,7 @@ pub fn graphql_subscription(args: TokenStream, input: TokenStream) -> TokenStrea
/// #[graphql_interface(for = [Human, Droid], Context = Database)]
/// trait Character {
/// fn id<'db>(&self, ctx: &'db Database) -> Option<&'db str>;
/// fn info<'db>(&self, #[graphql_interface(context)] db: &'db Database) -> Option<&'db str>;
/// fn info<'db>(&self, #[graphql(context)] db: &'db Database) -> Option<&'db str>;
/// }
///
/// #[derive(GraphQLObject)]
@ -739,7 +739,7 @@ pub fn graphql_subscription(args: TokenStream, input: TokenStream) -> TokenStrea
///
/// async fn name<'b>(
/// &'b self,
/// #[graphql_interface(executor)] another: &Executor<'_, '_, (), S>,
/// #[graphql(executor)] another: &Executor<'_, '_, (), S>,
/// ) -> &'b str
/// where
/// S: Send + Sync;
@ -825,7 +825,7 @@ pub fn graphql_subscription(args: TokenStream, input: TokenStream) -> TokenStrea
/// trait Character {
/// fn id(&self) -> &str;
///
/// #[graphql_interface(ignore)] // or `#[graphql_interface(skip)]`, your choice
/// #[graphql(ignore)] // or `#[graphql(skip)]`, your choice
/// fn kaboom(&mut self);
/// }
/// ```
@ -856,7 +856,7 @@ pub fn graphql_subscription(args: TokenStream, input: TokenStream) -> TokenStrea
/// trait Character {
/// fn id(&self) -> &str;
///
/// #[graphql_interface(downcast)] // makes method a downcast to `Human`, not a field
/// #[graphql(downcast)] // makes method a downcast to `Human`, not a field
/// // NOTICE: The method signature may optionally contain `&Database` context argument.
/// fn as_human(&self) -> Option<&Human> {
/// None
@ -1423,7 +1423,7 @@ pub fn derive_union(input: TokenStream) -> TokenStream {
/// trait Character {
/// fn as_human(&self) -> Option<&Human> { None }
/// fn as_droid(&self) -> Option<&Droid> { None }
/// #[graphql_union(ignore)] // or `#[graphql_union(skip)]`, your choice
/// #[graphql(ignore)] // or `#[graphql(skip)]`, your choice
/// fn id(&self) -> &str;
/// }
/// #
@ -1471,7 +1471,7 @@ pub fn derive_union(input: TokenStream) -> TokenStream {
/// on Droid = get_droid,
/// )]
/// trait Character {
/// #[graphql_union(ignore)]
/// #[graphql(ignore)]
/// fn id(&self) -> &str;
/// }
///