-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
enum values binding #2982
enum values binding #2982
Conversation
Thanks! |
Sure, I'll try doing that before the end of the week. |
Here are my thoughts so far:
Also, it feels cumbersome to use to be honest. If I'm already binding an enum to a custom model, I'd rather implement the marshaler/unmarshaler interfaces from gqlgen than having to manually bind each enum value to a go value through the schema/config. For example: enum Day {
MONDAY
TUESDAY
} package model
import (
"errors"
"io"
"github.com/99designs/gqlgen/graphql"
)
type Day int
const (
Monday Day = 0
Tuesday Day = 1
)
func (d Day) MarshalGQL(w io.Writer) {
switch d {
case Monday:
io.WriteString(w, "MONDAY")
case Tuesday:
io.WriteString(w, "TUESDAY")
}
}
func (d *Day) UnmarshalGQL(v any) error {
switch v {
case "MONDAY":
*d = Monday
return nil
case "TUESDAY":
*d = Tuesday
return nil
}
return errors.New("invalid Day")
} In the case where enum types do not implement any marshaler/unmarshaler, I feel like it would be useful to attempt generating default ones based on the standard |
Do you have any specific suggestions? I agree, It doesn't fit perfect. Enum is really special case. I just find it easier to implement with existing directive. I can try to work on new directive
This is expected behaviour. Its not trivial to find source of truth of target enum go type. I believe that attempts to define the type from the value in directives can lead to problems.
Sounds like a limitation. I specifically made sure that this possibility remained. It seems that if the user leave some enum values without a directive, he intentionally wants to leave them without a handler.
If you stick to clean architecture, layered architecture or something that adheres to low coupling principles you should separate api logic and service logic. You will face a problem of mapping api package models to service package models. You cant modify service models with gqlgen code (like in your example) because service models should not even know about gqlgen or any other api existence. This problem always can be resolved manually in gqlgen resolvers (gqlgen creates empty resolver for each type that cant be autobinded). But sometimes models of both layers looks same. That's why we use |
I do think a separate directive for enum values would make more sense as it would only have the relevant option. Also I think it would be nice if it worked the same with package-level constants and variables, provided they're of the correct type.
The non-trivial work is already done by gqlgen so the go type for the enum should already be known by now. You should also be able to verify whether the target value is of the correct type. I wouldn't expect it to matter whether the binding was explicit or implicit.
Sure, it's a limitation but the behaviour right now is that unmarshaling any enum value that has not been annotated results in the zero-value for the enum type and marshaling it produces an empty string which is invalid according to the schema. I don't see any case in which it makes sense. |
Sure! It's not that hard to implement this way.
Thanks for your attention! I will check case with same package enums. Using constants for enums is more standard but I think it is good idea to support variables too.
I guess I'm confused. If we agree that the source of truth for type definition is
I think we should add more restrictions. Directives on enum values without directive on enum should not be allowed.
OK! I understand what you want to protect users from. I will fix it. I also plan to add recipe in web documentation to make it clearer. |
I was under the impression that you meant this was motivated by technical reasons. If this is not the case, I honestly don't understand the reasoning behind it. |
I will check it again later but as long as I remember huge amout of job is done by already existing code (before this pr). This code triggers by placing |
I'm also not a fan of adding restrictions because for aesthetic reasons. |
I suggest this, if there is any misunderstanding, you can write it as you would like in the same format with code examples. This will work: enum Numbers @goModel(model: "./model.Number") {
ONE @goEnum(value: "./model.NumberOne")
TWO @goEnum(value: "./model.NumberTwo")
} This will fail codegen and send user error "unused goEnum directives": enum Numbers {
ONE @goEnum(value: "./model.NumberOne")
TWO @goEnum(value: "./model.NumberTwo")
} This will fail codegen and send user error "not all enum values binded" enum Numbers @goModel(model: "./model.Number") {
ONE @goEnum(value: "./model.NumberOne")
TWO
} This will work as before pr: enum Numbers @goModel(model: "./model.Number") {
ONE
TWO
} |
progress status: I plan to finish it by the end of the week when I return from vacation. |
@StevenACoffman @Desuuuu Hello! I opened pr with fixes and improvements #3014.
I rechecked this moment. I want to add to the thoughts that I wrote above that the situation is complicated by how the modelgen works. I would not want to change the way the plugin works and create an exception for this case. |
I want to improve enum model mapping. I miss the ability to flexible map enum values to go const enums of eny types. My suggestion is to add ability to map each grahpql enum value to specific go const via
@goModel
directive or models config.Now you are able to use
@goModel
directive withENUM_VALUE
. First map enum with specific type then map each enum value with required values. Same result also can be achieved by models config. This implementation contains example server.How to use it:
Complete schema with
@goModel
binding:Or just use
models
config:This is our go model package for binding:
Example of generated type binding implementation for
IntTyped
enum: