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

Fix MarsahlJson #218

Merged
merged 1 commit into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 25 additions & 10 deletions clientv2/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,8 +409,8 @@ func MarshalJSON(v interface{}) ([]byte, error) {
}

// getTypeEncoder returns an appropriate encoder function for the provided type.
func getTypeEncoder(t reflect.Type) func(a any) ([]byte, error) {
if t.Implements(reflect.TypeOf((*graphql.Marshaler)(nil)).Elem()) {
func getTypeEncoder(t reflect.Type) func(any2 any) ([]byte, error) {
if t.Implements(reflect.TypeOf((*graphql.Marshaler)(nil)).Elem()) || (t.Kind() == reflect.Ptr && reflect.PtrTo(t).Implements(reflect.TypeOf((*graphql.Marshaler)(nil)).Elem())) {
return gqlMarshalerEncoder
}

Expand Down Expand Up @@ -444,7 +444,7 @@ func getTypeEncoder(t reflect.Type) func(a any) ([]byte, error) {
}
}

func gqlMarshalerEncoder(v interface{}) ([]byte, error) {
func gqlMarshalerEncoder(v any) ([]byte, error) {
var buf bytes.Buffer
if val, ok := v.(graphql.Marshaler); ok {
val.MarshalGQL(&buf)
Expand Down Expand Up @@ -546,19 +546,34 @@ func checkMarshalerFields(t reflect.Type) bool {
if checkMarshalerFields(f.Type) {
return true
}

// If the value type is interface{}, we need to handle it at runtime
if f.Type.Kind() == reflect.Interface {
return true // Assume it could implement Marshaler at runtime
}
}

case reflect.Map:
// Check both key and value types for Marshaler implementation; usually, value type is what matters
keyType, valueType := t.Key(), t.Elem()
if isMarshalerType(valueType) || isMarshalerType(keyType) {
// Check key type for Marshaler implementation (usually not needed unless custom types used as keys)
keyType := t.Key()
if isMarshalerType(keyType) {
return true
}
// Recursively check the map value type
if checkMarshalerFields(valueType) {

// Check value type for Marshaler implementation
valueType := t.Elem()
if isMarshalerType(valueType) {
return true
}

// If the value type is interface{}, we need to handle it at runtime
if valueType.Kind() == reflect.Interface {
return true // Assume it could implement Marshaler at runtime
}

// Recursively check the map value type
return checkMarshalerFields(valueType)

case reflect.Slice, reflect.Array:
// Recursively check the element type
return checkMarshalerFields(t.Elem())
Expand All @@ -581,7 +596,7 @@ func isMarshalerType(t reflect.Type) bool {
return false
}

func newStructEncoder(t reflect.Type) func(interface{}) ([]byte, error) {
func newStructEncoder(t reflect.Type) func(any2 any) ([]byte, error) {
fields := prepareFields(t)
marshalerFieldExists := checkMarshalerFields(t)

Expand Down Expand Up @@ -619,7 +634,6 @@ func trimQuotes(s string) string {

func newMapEncoder(t reflect.Type) func(interface{}) ([]byte, error) {
keyEncoder := getTypeEncoder(t.Key())
valueEncoder := getTypeEncoder(t.Elem())

return func(v interface{}) ([]byte, error) {
val := reflect.ValueOf(v)
Expand All @@ -633,6 +647,7 @@ func newMapEncoder(t reflect.Type) func(interface{}) ([]byte, error) {
keyStr = trimQuotes(keyStr)

value := val.MapIndex(key)
valueEncoder := getTypeEncoder(value.Type())
encodedValue, err := valueEncoder(value.Interface())
if err != nil {
return nil, err
Expand Down
20 changes: 20 additions & 0 deletions clientv2/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,26 @@ func TestMarshalJSON(t *testing.T) {
want []byte
wantErr bool
}{
{
name: "marshal NumberOne",
args: args{
v: map[string]interface{}{"input": NumberOne},
},
want: []byte(`{"input":"ONE"}`),
},
{
name: "marshal NumberTwo",
args: args{
v: Request{
OperationName: "query",
Query: `query ($input: Number!) { input }`,
Variables: map[string]any{
"input": NumberTwo,
},
},
},
want: []byte(`{"operationName":"query", "query":"query ($input: Number!) { input }","variables":{"input":"TWO"}}`),
},
{
name: "marshal a struct with custom marshaler",
args: args{
Expand Down