From 8711dd195d7b39ff16145105f67c03fade3ab49f Mon Sep 17 00:00:00 2001 From: Yamashou <1230124fw@gmail.com> Date: Tue, 3 Dec 2024 18:42:56 +0900 Subject: [PATCH 1/2] Fix sycle input --- example/skipmodel/.gqlgenc.yml | 14 +++++ example/skipmodel/gen/client.go | 68 +++++++++++++++++++++++++ example/skipmodel/model/models_gen.go | 13 +++++ example/skipmodel/query/query.graphql | 5 ++ example/skipmodel/schema/schema.graphql | 32 ++++++++++++ querydocument/query_document.go | 36 ++++++------- 6 files changed, 151 insertions(+), 17 deletions(-) create mode 100644 example/skipmodel/.gqlgenc.yml create mode 100644 example/skipmodel/gen/client.go create mode 100644 example/skipmodel/model/models_gen.go create mode 100644 example/skipmodel/query/query.graphql create mode 100644 example/skipmodel/schema/schema.graphql diff --git a/example/skipmodel/.gqlgenc.yml b/example/skipmodel/.gqlgenc.yml new file mode 100644 index 0000000..17fabfd --- /dev/null +++ b/example/skipmodel/.gqlgenc.yml @@ -0,0 +1,14 @@ +schema: + - ./schema/schema.graphql +model: + filename: ./model/models_gen.go +client: + filename: ./gen/client.go +models: + DateTime: + model: github.com/99designs/gqlgen/graphql.Time +query: + - "./query/*.graphql" +generate: + clientV2: true + onlyUsedModels: true diff --git a/example/skipmodel/gen/client.go b/example/skipmodel/gen/client.go new file mode 100644 index 0000000..f11a0c6 --- /dev/null +++ b/example/skipmodel/gen/client.go @@ -0,0 +1,68 @@ +// Code generated by github.com/Yamashou/gqlgenc, DO NOT EDIT. + +package gen + +import ( + "context" + + "github.com/Yamashou/gqlgenc/clientv2" + "github.com/Yamashou/gqlgenc/example/skipmodel/model" +) + +type Client struct { + Client *clientv2.Client +} + +func NewClient(cli clientv2.HttpClient, baseURL string, options *clientv2.Options, interceptors ...clientv2.RequestInterceptor) *Client { + return &Client{Client: clientv2.NewClient(cli, baseURL, options, interceptors...)} +} + +type A_User struct { + ID string "json:\"id\" graphql:\"id\"" +} + +func (t *A_User) GetID() string { + if t == nil { + t = &A_User{} + } + return t.ID +} + +type A struct { + User A_User "json:\"user\" graphql:\"user\"" +} + +func (t *A) GetUser() *A_User { + if t == nil { + t = &A{} + } + return &t.User +} + +const ADocument = `mutation A ($input: UserInput!) { + user(input: $input) { + id + } +} +` + +func (c *Client) A(ctx context.Context, input model.UserInput, interceptors ...clientv2.RequestInterceptor) (*A, error) { + vars := map[string]any{ + "input": input, + } + + var res A + if err := c.Client.Post(ctx, "A", ADocument, &res, vars, interceptors...); err != nil { + if c.Client.ParseDataWhenErrors { + return &res, err + } + + return nil, err + } + + return &res, nil +} + +var DocumentOperationNames = map[string]string{ + ADocument: "A", +} diff --git a/example/skipmodel/model/models_gen.go b/example/skipmodel/model/models_gen.go new file mode 100644 index 0000000..998620d --- /dev/null +++ b/example/skipmodel/model/models_gen.go @@ -0,0 +1,13 @@ +// Code generated by github.com/99designs/gqlgen, DO NOT EDIT. + +package model + +type ProfileInput struct { + Name string `json:"name"` +} + +type UserInput struct { + ID string `json:"id"` + Profile *ProfileInput `json:"profile"` + Friends []*UserInput `json:"friends"` +} diff --git a/example/skipmodel/query/query.graphql b/example/skipmodel/query/query.graphql new file mode 100644 index 0000000..3721aa5 --- /dev/null +++ b/example/skipmodel/query/query.graphql @@ -0,0 +1,5 @@ +mutation A($input: UserInput!) { + user(input: $input) { + id + } +} diff --git a/example/skipmodel/schema/schema.graphql b/example/skipmodel/schema/schema.graphql new file mode 100644 index 0000000..e71e83b --- /dev/null +++ b/example/skipmodel/schema/schema.graphql @@ -0,0 +1,32 @@ +schema { + query: Query + mutation: Mutation +} + +type Query { + user: User! +} + +type Mutation { + user(input: UserInput!): User! +} + +input UserInput { + id: ID! + profile: ProfileInput! + friends: [UserInput!]! +} + +input ProfileInput { + name: String! +} + +type User { + id: ID! + profile: Profile! +} + +type Profile { + id: ID! + name: String! +} diff --git a/querydocument/query_document.go b/querydocument/query_document.go index 943186a..f2ac85b 100644 --- a/querydocument/query_document.go +++ b/querydocument/query_document.go @@ -72,6 +72,7 @@ func fragmentsInOperationWalker(selectionSet ast.SelectionSet) ast.FragmentDefin // CollectTypesFromQueryDocuments returns a map of type names used in query document arguments func CollectTypesFromQueryDocuments(schema *ast.Schema, queryDocuments []*ast.QueryDocument) map[string]bool { usedTypes := make(map[string]bool) + processedTypes := make(map[string]bool) // 完全に処理済みの型を追跡 for _, doc := range queryDocuments { for _, op := range doc.Operations { @@ -79,8 +80,10 @@ func CollectTypesFromQueryDocuments(schema *ast.Schema, queryDocuments []*ast.Qu for _, v := range op.VariableDefinitions { collectTypeFromTypeReference(v.Type, usedTypes) // Recursively collect input object fields - if def, ok := schema.Types[v.Type.Name()]; ok && def.IsInputType() { - collectInputObjectFields(def, schema, usedTypes) + if typeName := v.Type.Name(); typeName != "" { + if def, ok := schema.Types[typeName]; ok && def.IsInputType() { + collectInputObjectFieldsWithCycle(def, schema, usedTypes, processedTypes) + } } } } @@ -89,32 +92,31 @@ func CollectTypesFromQueryDocuments(schema *ast.Schema, queryDocuments []*ast.Qu return usedTypes } -// collectInputObjectFields recursively collects types from input object fields -func collectInputObjectFields(def *ast.Definition, schema *ast.Schema, usedTypes map[string]bool) { - // Skip if type has already been processed - if _, ok := usedTypes[def.Name]; ok { - return +func collectInputObjectFieldsWithCycle(def *ast.Definition, schema *ast.Schema, usedTypes map[string]bool, processedTypes map[string]bool) { + if processedTypes[def.Name] { + return // この型は既に完全に処理済み } - usedTypes[def.Name] = true + + usedTypes[def.Name] = true // この型を使用済みとしてマーク for _, field := range def.Fields { - // Get the actual type name - typeName := field.Type.NamedType - if typeName == "" { - // For list types, get the element type name - if field.Type.Elem != nil { - typeName = field.Type.Elem.NamedType - } + var typeName string + // リスト型の要素型まで辿る + for field.Type != nil && field.Type.NamedType != "" { + typeName = field.Type.NamedType + break } if typeName != "" { usedTypes[typeName] = true - // If field is an input object type, collect recursively + // 入力型のフィールドを再帰的に収集 if fieldDef, ok := schema.Types[typeName]; ok && fieldDef.IsInputType() { - collectInputObjectFields(fieldDef, schema, usedTypes) + collectInputObjectFieldsWithCycle(fieldDef, schema, usedTypes, processedTypes) } } } + + processedTypes[def.Name] = true // この型の処理が完了したことをマーク } // collectTypeFromTypeReference is a helper function to collect type names from type references From 098b26c80ad90a7f98235316bbba5710855da585 Mon Sep 17 00:00:00 2001 From: Yamashou <1230124fw@gmail.com> Date: Wed, 4 Dec 2024 00:40:27 +0900 Subject: [PATCH 2/2] update version --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index a3849c9..4c62caf 100644 --- a/main.go +++ b/main.go @@ -9,7 +9,7 @@ import ( "github.com/urfave/cli/v2" ) -const version = "0.27.2" +const version = "0.27.3" var versionCmd = &cli.Command{ Name: "version",