Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

GraphQL Union types on generic Rust enums #1262

Open
murtlatif opened this issue Jun 5, 2024 · 0 comments
Open

GraphQL Union types on generic Rust enums #1262

murtlatif opened this issue Jun 5, 2024 · 0 comments

Comments

@murtlatif
Copy link

I've been struggling to figure out the best way to implement a generic rust enum as a GraphQL union.

Objective

My goal is to have a generic enum type in rust enum Thing<T> and be able to export concrete types of this generic type to my GraphQL schema.

For example, having:

#[derive(GraphQLUnion)]
pub enum Thing<T> {
  A(ThingA<T>),
  B(ThingB<T>),
  C(ThingC<T>),
}

where I can explicitly export types like

union IntThing = IntThingA | IntThingB | IntThingC

for Thing<i32>.

My current solution is to create the entire enum and enum variant structs in a macro for each type, but it would be a significant improvement for me to be able to define a generic struct and just have some sort of implementation for each type I want to export. This will allow me to define more implementations like methods on the generic type without leaning so much into the macro (I would prefer not having to write all function methods in the macro definition).

We can export generic structs as GraphQL objects using the #[juniper::graphql_object] on a concrete implementation like so:

struct Thing<T> {
  something: T,
}

#[juniper::graphql_object(name = "IntThing")]
impl Thing<i32> {
  fn something(&self) -> i32 {
    self.something
  }
}

But it's unclear to me how to do a similar thing for union types.

Attempt

My current best attempt looks similar to what I would do for enums with generic lifetimes:

#[derive(GraphQLUnion)]
#[graphql(
  on ThingA<T> = Thing::resolve_a,
  on ThingB<T> = Thing::resolve_b,
  on ThingC<T> = Thing::resolve_c,
)]
enum Thing<T> {
  #[graphql(skip)]
  A(ThingA<T>),
  #[grapqhl(skip)]
  B(ThingB<T>),
  #[graphql(skip)]
  C(ThingC<T>),
}

This fails with:

error[E0401]: can't use generic parameters from outer item
   |
13 |     on ThingA<T> = Thing::resolve_a,           
   |               ^ use of generic parameter from outer item             
...                                                                                
18 | enum Thing<T> {                                                      
   |            - type parameter from outer item                          
   |                                                                               
   = note: a `const` is a separate item from the item that contains it   

I can only implement #[graphql_union] on traits, so that is not an option, and #[graphql_object] isn't appropriate here either.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant