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

Generate an enum for @oneOf input #450

Merged
merged 6 commits into from
May 25, 2023
Merged

Conversation

jbourassa
Copy link
Contributor

@jbourassa jbourassa commented May 22, 2023

The RFC for oneOf on input type is currently in at the draft stage. In short, adding the @oneOf directive to an input type means exactly one field of the input's field must be provided.

While the spec still hasn't been accepted, there's a strong need for input unions, the spec is pretty far along and already seeing adoption in the community. It's available in the GraphQL Ruby gem, and we make use of it in Shopify Functions.

With this PR, inputs tagged with @oneOf will generate a Rust enum instead of a struct.

From the test, this type:

input Param @oneOf {
  author: Author
  name: String
  recursiveDirect: Param
  recursiveIndirect: Recursive
  requiredInts: [Int!]
  optionalInts: [Int]
}

generates this Rust enum:

pub enum Param {
    #[serde(rename = "author")]
    Author(Author),
    #[serde(rename = "name")]
    Name(String),
    #[serde(rename = "recursiveDirect")]
    RecursiveDirect(Box<Param>),
    #[serde(rename = "recursiveIndirect")]
    RecursiveIndirect(Box<Recursive>),
    #[serde(rename = "requiredInts")]
    RequiredInts(Vec<Int>),
    #[serde(rename = "optionalInts")]
    OptionalInts(Vec<Option<Int>>),
}

That is, it generates an enum with 1 variant per field, where the variant has 1 required field.


Worth noting that we'll only generate an enum when using IDL-defined schema (.graphql file), but not when using the introspection JSON response. The reason for that is that introspecting oneOf is done through the __Type.isOneOf field, which isn't widely implemented. To make it work, we'd have to dynamically select __Type.isOneOf in the introspection query, based on user opt-in. Since my use case didn't require it, and the introspection query is currently static, I didn't do it.

@jbourassa
Copy link
Contributor Author

@surma this is another stab at addressing the same root problem as Shopify/shopify-function-rust#27, curious to hear your thoughts.

@jbourassa jbourassa changed the title Generate an enum for @oneOf inputs Generate an enum for @oneOf input May 23, 2023
Copy link
Member

@tomhoule tomhoule left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't spent time gathering a lot of context or trying the branch, but with that caveat, lgtm 👍

Copy link
Collaborator

@surma surma left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

I pushed a commit to fix the (new?) clippy warnings. If CI passes, we can ship this.

@surma surma merged commit fcd1f34 into graphql-rust:main May 25, 2023
@jbourassa jbourassa deleted the one-of-input branch May 25, 2023 14:33
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

Successfully merging this pull request may close these issues.

3 participants