Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: Yamashou/gqlgenc
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.30.3
Choose a base ref
...
head repository: Yamashou/gqlgenc
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.31.0
Choose a head ref
  • 8 commits
  • 7 files changed
  • 2 contributors

Commits on Feb 19, 2025

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    96fc0db View commit details
  2. rm isTypNilable

    venkycode committed Feb 19, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    a003277 View commit details
  3. Clarify test cases for slice JSON encoding with omitempty

    venkycode committed Feb 19, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    f7855d6 View commit details

Commits on Feb 20, 2025

  1. feat: Add UserFragment and ProfileFragment

    Added UserFragment and ProfileFragment with related methods.
    Also added new fragments to the GraphQL query.
    Yamashou committed Feb 20, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    8d1472a View commit details
  2. feat: Add test cases

    Added test cases for the mergeFieldsRecursively function. Covers basic merge
    cases and complex queries with fragments.
    Yamashou committed Feb 20, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    dcd63ec View commit details
  3. Merge pull request #266 from Yamashou/fix-inline-gen

    fix: multiple fields
    Yamashou authored Feb 20, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    6371a3a View commit details

Commits on Feb 23, 2025

  1. Merge pull request #265 from venkycode/fix/nil-arrary-converted-to-nu…

    …ll-instead-of-empty-array
    
    [Fix]nil slice converted to empty array instead of "null"
    Yamashou authored Feb 23, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    60aa42c View commit details
  2. chore: update version to 0.31.0

    This commit updates the version from 0.30.3 to 0.31.0. This includes new features
    and fixes.
    Yamashou committed Feb 23, 2025

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    be2281a View commit details
Showing with 377 additions and 16 deletions.
  1. +1 −1 clientgenv2/source_generator.go
  2. +237 −0 clientgenv2/source_generator_test.go
  3. +9 −12 clientv2/client.go
  4. +59 −1 clientv2/client_test.go
  5. +58 −1 example/skipmodel/gen/client.go
  6. +12 −0 example/skipmodel/query/query.graphql
  7. +1 −1 main.go
2 changes: 1 addition & 1 deletion clientgenv2/source_generator.go
Original file line number Diff line number Diff line change
@@ -145,13 +145,13 @@ func mergeFieldsRecursively(targetFields, sourceFields ResponseFieldList, preMer
})

targetField.ResponseFields, newPreMerged, newPostMerged = mergeFieldsRecursively(targetField.ResponseFields, sourceField.ResponseFields, newPreMerged, newPostMerged)

newPostMerged = append(newPostMerged, &StructSource{
Name: targetField.FieldTypeString(),
Type: targetField.ResponseFields.StructType(),
})
} else {
targetFieldsMap[sourceField.Name] = sourceField
responseFieldList = append(responseFieldList, sourceField)
}
}
for _, field := range targetFieldsMap {
237 changes: 237 additions & 0 deletions clientgenv2/source_generator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
package clientgenv2

import (
"go/types"
"testing"
)

func createTestStruct(fields []*types.Var, tags []string) *types.Struct {
return types.NewStruct(fields, tags)
}

func TestMergeFieldsRecursively(t *testing.T) {
tests := []struct {
name string
targetFields ResponseFieldList
sourceFields ResponseFieldList
preMerged []*StructSource
postMerged []*StructSource
expectedFields ResponseFieldList
expectedPreMerged []*StructSource
expectedPostMerged []*StructSource
}{
{
name: "Basic merge case",
targetFields: ResponseFieldList{
{
Name: "field1",
Type: types.Typ[types.String],
Tags: []string{`json:"field1"`},
},
},
sourceFields: ResponseFieldList{
{
Name: "field2",
Type: types.Typ[types.Int],
Tags: []string{`json:"field2"`},
},
},
preMerged: []*StructSource{},
postMerged: []*StructSource{},
expectedFields: ResponseFieldList{
{
Name: "field1",
Type: types.Typ[types.String],
Tags: []string{`json:"field1"`},
},
{
Name: "field2",
Type: types.Typ[types.Int],
Tags: []string{`json:"field2"`},
},
},
expectedPreMerged: []*StructSource{},
expectedPostMerged: []*StructSource{},
},
{
name: "Merge case with complex query including fragments",
targetFields: ResponseFieldList{
{
Name: "id",
Type: types.Typ[types.String],
Tags: []string{`json:"id"`},
},
{
Name: "profile",
Type: types.NewPointer(types.NewNamed(
types.NewTypeName(0, nil, "A_User_Profile", nil),
createTestStruct([]*types.Var{
types.NewVar(0, nil, "id", types.Typ[types.String]),
types.NewVar(0, nil, "name", types.Typ[types.String]),
}, []string{`json:"id"`, `json:"name"`}),
nil,
)),
Tags: []string{`json:"profile"`},
ResponseFields: ResponseFieldList{
{
Name: "id",
Type: types.Typ[types.String],
Tags: []string{`json:"id"`},
},
{
Name: "ProfileFragment",
Type: types.NewPointer(types.NewNamed(
types.NewTypeName(0, nil, "ProfileFragment", nil),
createTestStruct([]*types.Var{
types.NewVar(0, nil, "name", types.Typ[types.String]),
}, []string{`json:"name"`}),
nil,
)),
Tags: []string{`json:"ProfileFragment"`},
IsFragmentSpread: true,
ResponseFields: ResponseFieldList{
{
Name: "name",
Type: types.Typ[types.String],
Tags: []string{`json:"name"`},
},
},
},
},
},
},
sourceFields: ResponseFieldList{
{
Name: "profile",
Type: types.NewPointer(types.NewNamed(
types.NewTypeName(0, nil, "Profile", nil),
createTestStruct([]*types.Var{
types.NewVar(0, nil, "id", types.Typ[types.String]),
types.NewVar(0, nil, "name", types.Typ[types.String]),
}, []string{`json:"id"`, `json:"name"`}),
nil,
)),
Tags: []string{`json:"profile"`},
ResponseFields: ResponseFieldList{
{
Name: "name",
Type: types.Typ[types.String],
Tags: []string{`json:"name"`},
},
},
},
},
preMerged: []*StructSource{},
postMerged: []*StructSource{},
expectedFields: ResponseFieldList{
{
Name: "id",
Type: types.Typ[types.String],
Tags: []string{`json:"id"`},
},
{
Name: "profile",
Type: types.NewPointer(types.NewNamed(
types.NewTypeName(0, nil, "A_User_Profile", nil),
createTestStruct([]*types.Var{
types.NewVar(0, nil, "id", types.Typ[types.String]),
types.NewVar(0, nil, "name", types.Typ[types.String]),
}, []string{`json:"id"`, `json:"name"`}),
nil,
)),
Tags: []string{`json:"profile"`},
ResponseFields: ResponseFieldList{
{
Name: "id",
Type: types.Typ[types.String],
Tags: []string{`json:"id"`},
},
{
Name: "ProfileFragment",
Type: types.NewPointer(types.NewNamed(
types.NewTypeName(0, nil, "ProfileFragment", nil),
createTestStruct([]*types.Var{
types.NewVar(0, nil, "name", types.Typ[types.String]),
}, []string{`json:"name"`}),
nil,
)),
Tags: []string{`json:"ProfileFragment"`},
IsFragmentSpread: true,
ResponseFields: ResponseFieldList{
{
Name: "name",
Type: types.Typ[types.String],
Tags: []string{`json:"name"`},
},
},
},
},
},
},
expectedPreMerged: []*StructSource{
{
Name: "Nested",
Type: createTestStruct([]*types.Var{
types.NewVar(0, nil, "id", types.Typ[types.String]),
}, []string{`json:"id"`}),
},
{
Name: "Nested",
Type: createTestStruct([]*types.Var{
types.NewVar(0, nil, "name", types.Typ[types.String]),
}, []string{`json:"name"`}),
},
},
expectedPostMerged: []*StructSource{
{
Name: "Nested",
Type: createTestStruct([]*types.Var{
types.NewVar(0, nil, "id", types.Typ[types.String]),
types.NewVar(0, nil, "name", types.Typ[types.String]),
}, []string{`json:"id"`, `json:"name"`}),
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
resultFields, resultPreMerged, resultPostMerged := mergeFieldsRecursively(
tt.targetFields,
tt.sourceFields,
tt.preMerged,
tt.postMerged,
)

if len(tt.expectedFields) != len(resultFields) {
t.Errorf("Number of fields does not match: got %v, want %v", len(resultFields), len(tt.expectedFields))
return
}

if len(tt.expectedPreMerged) != len(resultPreMerged) {
t.Errorf("Number of preMerged does not match: got %v, want %v", len(resultPreMerged), len(tt.expectedPreMerged))
}

if len(tt.expectedPostMerged) != len(resultPostMerged) {
t.Errorf("Number of postMerged does not match: got %v, want %v", len(resultPostMerged), len(tt.expectedPostMerged))
}

for i := range tt.expectedFields {
if tt.expectedFields[i].Name != resultFields[i].Name {
t.Errorf("Field name does not match: got %v, want %v", resultFields[i].Name, tt.expectedFields[i].Name)
}
if tt.expectedFields[i].Type.String() != resultFields[i].Type.String() {
t.Errorf("Field type does not match: got %v, want %v", resultFields[i].Type.String(), tt.expectedFields[i].Type.String())
}
if len(tt.expectedFields[i].Tags) != len(resultFields[i].Tags) {
t.Errorf("Number of tags does not match: got %v, want %v", len(resultFields[i].Tags), len(tt.expectedFields[i].Tags))
}
for j, tag := range tt.expectedFields[i].Tags {
if tag != resultFields[i].Tags[j] {
t.Errorf("Tag does not match: got %v, want %v", resultFields[i].Tags[j], tag)
}
}
}
})
}
}
21 changes: 9 additions & 12 deletions clientv2/client.go
Original file line number Diff line number Diff line change
@@ -543,6 +543,7 @@ func (e *Encoder) Encode(v reflect.Value) ([]byte, error) {
}

t := v.Type()

switch t.Kind() {
case reflect.Ptr:
return e.encodePtr(v)
@@ -676,18 +677,6 @@ func (e *Encoder) encodeStruct(v reflect.Value) ([]byte, error) {
continue
}

// omitemptyが無効な場合、nilスライスは空のスライス[]として扱う
if !e.EnableInputJsonOmitemptyTag && fieldValue.Kind() == reflect.Slice && fieldValue.IsNil() {
result[field.jsonName] = []byte("[]")
continue
}

// omitemptyが無効な場合、nilポインタはnullとして扱い、出力に含める
if !e.EnableInputJsonOmitemptyTag && fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() {
result[field.jsonName] = []byte("null")
continue
}

encodedValue, err := e.Encode(fieldValue)
if err != nil {
return nil, err
@@ -699,6 +688,10 @@ func (e *Encoder) encodeStruct(v reflect.Value) ([]byte, error) {

// encodeMap encodes a map value
func (e *Encoder) encodeMap(v reflect.Value) ([]byte, error) {
if v.IsNil() {
return []byte("null"), nil
}

result := make(map[string]json.RawMessage)
for _, key := range v.MapKeys() {
encodedKey, err := e.Encode(key)
@@ -720,6 +713,10 @@ func (e *Encoder) encodeMap(v reflect.Value) ([]byte, error) {

// encodeSlice encodes a slice value
func (e *Encoder) encodeSlice(v reflect.Value) ([]byte, error) {
if v.IsNil() {
return []byte("null"), nil
}

result := make([]json.RawMessage, v.Len())
for i := range v.Len() {
encodedValue, err := e.Encode(v.Index(i))
60 changes: 59 additions & 1 deletion clientv2/client_test.go
Original file line number Diff line number Diff line change
@@ -976,6 +976,7 @@ func TestEncoder_encodeStruct(t *testing.T) {
Nickname string `json:"nickname,omitempty"`
Empty string `json:"-"`
unexposed string
Hobbies []string `json:"hobbies"`
}

zip := "123-4567"
@@ -997,6 +998,7 @@ func TestEncoder_encodeStruct(t *testing.T) {
Address: Address{City: "Tokyo", Country: "Japan", Zip: &zip},
Tags: []string{"tag1", "tag2"},
Nickname: "Johnny",
Hobbies: []string{"reading", "swimming"},
},
enableOmitemptyTag: true,
want: map[string]any{
@@ -1007,6 +1009,7 @@ func TestEncoder_encodeStruct(t *testing.T) {
"address": map[string]any{"city": "Tokyo", "country": "Japan", "zip": "123-4567"},
"tags": []any{"tag1", "tag2"},
"nickname": "Johnny",
"hobbies": []any{"reading", "swimming"},
},
},
{
@@ -1020,6 +1023,7 @@ func TestEncoder_encodeStruct(t *testing.T) {
"name": "John",
"email2": nil,
"address": map[string]any{"city": "Tokyo"},
"hobbies": nil,
},
},
{
@@ -1035,8 +1039,62 @@ func TestEncoder_encodeStruct(t *testing.T) {
"email": nil,
"email2": nil,
"address": map[string]any{"city": "Tokyo", "country": "", "zip": nil},
"tags": []any{},
"tags": nil,
"nickname": "",
"hobbies": nil,
},
},
{
name: "nil slice set to null on omitempty disabled",
input: Person{
Name: "John",
Address: Address{City: "Tokyo"},
},
enableOmitemptyTag: false,
want: map[string]any{
"name": "John",
"age": int64(0),
"email": nil, // omitempty is ignored
"email2": nil,
"tags": nil, // omitempty is ignored
"hobbies": nil,
"address": map[string]any{
"city": "Tokyo",
"country": "", // omitempty is ignored
"zip": nil,
},
"nickname": "", // omitempty is ignored
},
},
{
name: "zero value of slice (i.e. nil slice) dropped on omitempty enabled",
input: Person{
Name: "John",
Address: Address{City: "Tokyo"},
Hobbies: nil,
Tags: nil, // will be dropped as omitempty is enabled
},
enableOmitemptyTag: true,
want: map[string]any{
"name": "John",
"email2": nil,
"hobbies": nil,
"address": map[string]any{"city": "Tokyo"},
},
},
{
name: "nil slice set to null",
input: Person{
Tags: []string{}, // this is not zero value, so omitempty will not be applied
Hobbies: nil, // will continue to be nil
},
enableOmitemptyTag: true,
want: map[string]any{
"name": "",
"email2": nil,
"tags": []any{},
"hobbies": nil,
"address": map[string]any{"city": ""},
},
},
}
59 changes: 58 additions & 1 deletion example/skipmodel/gen/client.go
12 changes: 12 additions & 0 deletions example/skipmodel/query/query.graphql
Original file line number Diff line number Diff line change
@@ -3,6 +3,18 @@ mutation A($input: UserInput!) {
id
profile {
id
...ProfileFragment
}
...UserFragment
}
}

fragment UserFragment on User {
profile {
name
}
}

fragment ProfileFragment on Profile {
name
}
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ import (
"github.com/urfave/cli/v2"
)

const version = "0.30.3"
const version = "0.31.0"

var versionCmd = &cli.Command{
Name: "version",