-
Notifications
You must be signed in to change notification settings - Fork 534
Hydrate enum values dynamically #859
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
Hydrate enum values dynamically #859
Conversation
@benwilson512 Last few issues blocking next 1.5 rc... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems good, but does it let us actually add values to the enum or merely adjust the values that are there?
Yeah good point, this just lets you edit an existing What do you think of a hydration like this: {:values, [Blueprint.Schema.EnumValueDefinition.t()]} It seems like constructing the full I could split this up and get the explicit exception raised first then tackle dynamic enum values in another PR |
@benwilson512 do you have any thoughts on this? It seems like most other hydration takes pretty basic data types (strings, functions, etc), whereas setting the full |
That's a good point. I think it's fair to say that if you want to mess with the actual type structs then you should use a pipeline modifier to add a new schema phase. We definitely could add some docs around that to make sure it feels intuitive. I think we can merge what is here as in this case, and promote general schema manipulation strategies as the way to add whole values. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def hydrate(%Absinthe.Blueprint.Schema.EnumValueDefinition{identifier: identifier}, []) | ||
when identifier in [:red, :blue, :green] do | ||
{:as, color_map(identifier)} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it correct to use the :identifier
key here, or should we instead be using :value
? For example, I have this enum definition:
enum :purchase_payment_status do
value(:paid, as: :purchase_payment_status_paid)
end
In that example, :paid
corresponds to the external value of the enum, "PAID"
. With my chosen value as: :purchase_payment_status_paid
, I assumed I was supposed to provide something totally unique that I could reference during hydration. However, when hydrate
gets called, it gets called with:
[2] %Elixir.Absinthe.Blueprint.Schema.EnumValueDefinition{
__reference__: %{
location: %{
file: "/MyApp/web/graphql/schema_types/purchase.ex"
line: 12
}
module: :Elixir.MyApp.GraphQL.Schema.Types.Purchase
}
deprecation: nil
description: "The purchase has not yet been paid"
directives: []
errors: []
flags: %{}
identifier: :not_paid
module: :Elixir.MyApp.GraphQL.Schema.Types.Purchase
name: "NOT_PAID"
source_location: nil
value: :purchase_payment_status_not_paid
}
In that example it is :value
that I actually want to match against in order to convert to its true internal value, "Not Paid"
, which I pull in from a function in another module during hydrate
:
def hydrate(%Absinthe.Blueprint.Schema.EnumValueDefinition{value: value} = enum, [])
when value in [:purchase_payment_status_not_paid] do
{:as, MyApp.GraphQL.Schema.Types.Purchase.payment_status(value)}
end
Asking here for a few reasons:
- In case we might want to alter the test to reflect different recommended usage
- In case we want to alter any docs to reflect this
- In case somebody else runs into a similar issue and this example is helpful to them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's just an example, people could do it whatever way works best for them...
Though the whole point is to assign the :as
value, so already having one set will just overwrite it (ie: why set that at all in the schema?)
Seems like you have 3 "layers" of enum values going on here, which I don't think would be so common?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I can see how it might be less common. In this case, the external value :paid
/"PAID"
is not something that I would be confident would be unique across all of our enums, so I don't feel confident matching on that in hydrate
because it might conflict with another value (say the same value on Order status, or Invoice status).
I haven't seen any GraphQL convention that advocates making all of your enums have globally unique values, so this seems like what's necessary to avoid a potential collision 🤷♂ Anyway, will assume this is a rarer use case and leave it at that, thanks @binaryseed ✌️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't seen any GraphQL convention that advocates making all of your enums have globally unique values, so this seems like what's necessary to avoid a potential collision
The normal solution here is that the hydrate
function should be passed a list as the second arg of the parent values indicating where in the schema "tree" we are. This would allow you to pattern match for a particular enum value definition found under a specific enum definition. However @binaryseed I'm noticing that the second arg in your test case is an empty list. Am if misremembering how hydrate works or are we losing context for some reason?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah I noticed that too - it works currently, but i'm making a PR that matches on the ancestors since thats what we should be doing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:as
@benwilson512 open to feedback on the approach for this one...
closes #843