-
Notifications
You must be signed in to change notification settings - Fork 138
Description
Describe the bug
Generated MarshalJSON and UnmarshalJSON functions for type union-based fragments are invalid and need manual intervention.
The documentation about the optional_generic_type gives a possibility to specify the type, but doesn't require and specific contract so the generator doesn't know anything about the internal structure. When UnmarshalJSON and __premarshalJSON functions are generated, the code does't count, with the fact, that the value is wrapped inside of struct.
MarshalJSON
genqlient/generate/marshal.go.tmpl
Line 57 in 7c070dd
| src := v.{{$field.Selector}} |
The code needs to be aware how to get value from
src := v.Source => src := v.Source.Value()
UnmarshalJSON
Similar issue, but with an extra step, the wrapper usually has an internal bool attribute that needs to be set to true to signal that the value was set.
golang var v Source err = __unmarshalSource( src, &v) // unmarchal to variable if err != nil { return fmt.Errorf( "unable to unmarshal PersonalizedSnippetPreviewFragment.Source: %w", err) } dst.SetValue(v) // set to omittable
genqlient/generate/unmarshal.go.tmpl
Line 139 in 7c070dd
| src, {{if $field.GoType.IsPointer}}*{{end}}dst) |
To Reproduce
Steps to reproduce the behavior. Please include whether the problem happens at code-generation time or at runtime.
We are using our own generic type for optional types
optional_generic_type: "our package /model.Omittable"
Then we have a following union type using type union in graphql schema and fragments
Source =
SourceA
| SourceB
| SourceN
type Message {
source: Source
}
fragment FragmentMessage on Message {
source {
...FragmentSource
}
}
fragment FragmentSource on Source {
... on SourceA {
... some fields
}
... on SourceB {
... some fields
}
... on SourceN {
... some fields
}
}Expected behavior
The union type based fragments should be working without manual intervention in generated code.
genqlient version
github.com/Khan/genqlient v0.7.0 but i haven't found any trace that latest would work
Additional context
I guess that some contract on optional wrappers is required or some extra settings that would allow to specify functions that would return or set values for example:
yaml optional_generic_type_methods: getter: Value setter: SetValue
where functions signatures are:
``golang
type Omittable[T any] struct {
value T
set bool
}
func (o Omittable[T]) Value() T {
if !o.set {
var zero T
return zero
}
return o.value
}
func (o *Omittable[T]) SetValue(v T) {
o.set = true
o.value = v
}
``