Describe the bug
A struct using #[graphql_object] (for complexe fields resolvers) and #[graphql_interface] does not generate a valid schema (as_schema_language)
To Reproduce
use juniper::{graphql_interface, graphql_object, graphql_interface};
#[graphql_interface(for = User)]
pub trait Namespace {
fn id(&self) -> Option<uuid::Uuid>;
fn created_at(&self) -> chrono::DateTime<chrono::Utc>;
fn name(&self) -> String;
}
#[derive(Debug, Clone)]
pub struct User {
id: uuid::Uuid,
created_at: chrono::DateTime<chrono::Utc>,
name: String,
other: String,
}
#[graphql_object]
#[graphql(impl = NamespaceValue)]
impl User {
pub fn username() -> String {
panic!("not implemented"); // TODO
}
}
#[graphql_interface]
impl Namespace for User {
fn id(&self) -> Option<uuid::Uuid> {
Some(self.id)
}
fn created_at(&self) -> chrono::DateTime<chrono::Utc> {
self.created_at
}
fn name(&self) -> String {
self.name.clone()
}
}
generates
interface Namespace {
id: Uuid
createdAt: DateTimeUtc!
name: String!
}
type User {
username: String!
}
"DateTime"
scalar DateTimeUtc
"Uuid"
scalar Uuid
Expected behavior
The expected generated schema is as follow
type User implements Namespace {
id: Uuid!
createdAt: DateTimeUtc!
name: String!
username: String!
}
Additional context
branch: master
rev: 4ffd276a5b33ae4423f295675f977ed6cc7fb88a
Also,
When I try as follow:
#[graphql_object(
impl = NamespaceValue,
)]
impl User {
pub fn username() -> String {
panic!("not implemented"); // TODO
}
}
#[graphql_interface]
impl Namespace for User {
fn id(&self) -> Option<uuid::Uuid> {
Some(self.id)
}
fn created_at(&self) -> chrono::DateTime<chrono::Utc> {
self.created_at
}
fn name(&self) -> String {
self.name.clone()
}
}
it generates the following code:
type User implements Namespace {
username: String!
}
while it should have generated:
type User implements Namespace {
id: Uuid!
createdAt: DateTimeUtc!
name: String!
username: String!
}
Thanks for the high-quality report! This does indeed look like a bug. I might be able to look at it over the weekend, but feel free to take a crack at it...the schema generation code is pretty straightforward and contained.
After exploring the tests (https://github.com/graphql-rust/juniper/blob/a4871887bb6b30029bd4671af716c0649a0cc60c/juniper/src/tests/fixtures/starwars/schema.rs / https://github.com/graphql-rust/juniper/blob/a4871887bb6b30029bd4671af716c0649a0cc60c/juniper/src/tests/fixtures/starwars/starwars.graphql) I also noticed that the interface methods are duplicated in both in the impl Human and impl Character for Human so I'm not if it's finally a bug, or if the macro is working as expected, but is just not intuitive to work with.
For example, this code:
#[derive(Debug, Clone)]
pub struct User {
id: uuid::Uuid,
created_at: chrono::DateTime<chrono::Utc>,
name: String,
}
#[graphql_object(
impl = NamespaceInterface,
)]
impl User {
pub fn id(&self) -> Option<ID> {
Some(self.id.into())
}
pub fn created_at(&self) -> Time {
self.created_at.into()
}
pub fn name(&self) -> String {
self.name.clone()
}
pub fn username() -> String {
panic!("not implemented"); // TODO
}
}
#[graphql_interface]
impl Namespace for User {
fn id(&self) -> Option<ID> {
User::id(self)
}
fn created_at(&self) -> Time {
User::created_at(self)
}
fn name(&self) -> String {
User::name(&self)
}
}
generates the good output, but is 'weird'
Not being intuitive is a bug :-)
@LegNeato @skerkour
The problem is that #[graphql_object] macro expansion cannot work with multiple attributes, like #[graphql_interface] does. That's why:
#[graphql_object]
#[graphql(impl = NamespaceValue)]
impl User {
is invalid definition at the moment, where #[graphql(impl = NamespaceValue)] attribute is fully omitted.
Even if #[graphql_object] would have supported that, it should have been defined like that:
#[graphql_object]
#[graphql_object(impl = NamespaceValue)]
impl User {
like the #[graphql_interface]/#[graphql_union] allows at the moment.
This is for the reasons explained here. But I think that point needs re-checking.
Also, need to think about some compile-time check to prevent the situation described above, so it would be complain about User not implementing Namespace in schema.
Most helpful comment
Not being intuitive is a bug :-)