Yamashou / gqlgenc

This is Go library for building GraphQL client with gqlgen
MIT License
370 stars 66 forks source link

Is `MarshalGQL` not referenced? #196

Closed zaneli closed 1 month ago

zaneli commented 9 months ago

It seems like gqlgenc doesn't take MarshalGQL method into account.

type Query {
  enumToNum(numer: Number!): Int!
}

enum Number @goModel(model: "github.com/zaneli/gql-test/enums.Number") {
    ONE
    TWO
}
package enums

import (
    "fmt"
    "io"
    "strconv"
)

type Number int64

const (
    NumberOne Number = 1
    NumberTwo Number = 2
)

func (n *Number) UnmarshalGQL(v interface{}) error {
    str, ok := v.(string)
    if !ok {
        return fmt.Errorf("enums must be strings")
    }

    switch str {
    case "ONE":
        *n = NumberOne
    case "TWO":
        *n = NumberTwo
    default:
        return fmt.Errorf("Number not found Type: %d", n)
    }
    return nil
}

func (n Number) MarshalGQL(w io.Writer) {
    var str string
    switch n {
    case NumberOne:
        str = "ONE"
    case NumberTwo:
        str = "TWO"
    }
    fmt.Fprint(w, strconv.Quote(str))
}
func (r *queryResolver) EnumToNum(ctx context.Context, numer enums.Number) (int, error) {
    return int(numer), nil
}

It works fine.

スクリーンショット 2024-01-09 17 10 13

However, gqlgenc generated codes seem to not use MarshalGQL method.

func TestEnumToNum(t *testing.T) {
    httpCli := &http.Client{
        Transport:     nil,
        CheckRedirect: nil,
        Jar:           nil,
        Timeout:       30 * time.Second,
    }
    c := client.NewClient(httpCli, "http://localhost:8080/graphql", nil)

    ctx := context.Background()
    res, err := c.EnumToNum(ctx, enums.NumberOne)
    if err != nil {
        t.Fatal(err)
    }
    if res.EnumToNum != 1 {
        t.Fatalf("want 1, got %v", res.EnumToNum)
    }
}
--- FAIL: TestEnumToNum (0.00s)
    /Users/zaneli/go/src/github.com/zaneli/gql-test/tests/enum_to_num_test.go:25: {"networkErrors":{"code":422,"message":"Response body {\"errors\":[{\"message\":\"1 is not a valid Number\",\"path\":[\"variable\",\"numer\"],\"extensions\":{\"code\":\"GRAPHQL_VALIDATION_FAILED\"}}],\"data\":null}"},"graphqlErrors":[{"message":"1 is not a valid Number","path":["variable","numer"],"extensions":{"code":"GRAPHQL_VALIDATION_FAILED"}}]}

https://github.com/Yamashou/gqlgenc/blob/484c08b959ce132e110b0e74b7eb44eb396f6e36/clientv2/client.go#L185

{"query":"query EnumToNum ($numer: Number!) {\n\tenumToNum(numer: $numer)\n}\n","variables":{"numer":1},"operationName":"EnumToNum"}

I realized that there is a workaround to implement MarshalJSON method as well.

func (n Number) MarshalJSON() ([]byte, error) {
    b := new(bytes.Buffer)
    n.MarshalGQL(b)
    return b.Bytes(), nil
}

After implement MarshalJSON, TestEnumToNum succeeded.

Yamashou commented 9 months ago

@zaneli Thanks ! I'm glad to know about this issue. Currently, there are other issues with the parser, and I will try to fix them together with those issues.

zaneli commented 6 months ago

I tried to use v0.21.1 and the problem does not appear to be fixed. The following test fail.

{
    name: "marshal Request",
    args: args{
        v: &Request{
            Query:         `{ query(input: $input) }`,
            Variables:     map[string]interface{}{"input": NumberOne},
            OperationName: "Test",
        },
    },
    want: []byte(`{"query":"{ query(input: $input) }","variables":{"input":"ONE"},"operationName":"Test"}`),
},
--- FAIL: TestMarshalJSON (0.00s)
    --- FAIL: TestMarshalJSON/marshal_Request (0.00s)
        gqlgenc/clientv2/client_test.go:675: MarshalJSON() got = map[operationName:Test query:{ query(input: $input) } variables:map[input:1]], want map[operationName:Test query:{ query(input: $input) } variables:map[input:ONE]]

I also think there is a similar problem with unmarshalling. I hope this test will be successful.

func TestUnmarshalGQL(t *testing.T) {
    c := &Client{}
    type Example struct {
        Name   string `json:"name"`
        Number Number `json:"number"`
    }
    var got Example
    if err := c.unmarshal([]byte(`{"data": {"name": "test", "number": "ONE"}}`), &got); err != nil {
        t.Fatalf("Failed to unmarshal: %v", err)
    }

    want := Example{
        Name:   "test",
        Number: NumberOne,
    }
    if !cmp.Equal(got, want) {
        t.Fatalf("c.unmarshal() got = %v, want %v", got, want)
    }
}
--- FAIL: TestUnmarshalGQL (0.00s)
    gqlgenc/clientv2/client_test.go:689: Failed to unmarshal: failed to decode data into response {"data": {"name": "test", "number": "ONE"}}: : : : : json: cannot unmarshal string into Go value of type clientv2.Number
kyoh86 commented 4 months ago

@Yamashou not yet?

Yamashou commented 4 months ago

@kyoh86 sorry. I have not been able to finish my day job and have not gotten around to it. I have about 20% to complete.

Yamashou commented 4 months ago

@zaneli @kyoh86 Implemented support for arguments! https://github.com/Yamashou/gqlgenc/releases/tag/v0.23.2

zaneli commented 3 months ago

I have verified that this problem has been fixed. Thank you for fixing it!