stash/vendor/github.com/Yamashou/gqlgenc/clientgen/source.go

239 lines
6.4 KiB
Go

package clientgen
import (
"bytes"
"fmt"
"go/types"
"github.com/99designs/gqlgen/codegen/templates"
"github.com/Yamashou/gqlgenc/config"
"github.com/vektah/gqlparser/v2/ast"
"github.com/vektah/gqlparser/v2/formatter"
)
type Source struct {
schema *ast.Schema
queryDocument *ast.QueryDocument
sourceGenerator *SourceGenerator
generateConfig *config.GenerateConfig
}
func NewSource(schema *ast.Schema, queryDocument *ast.QueryDocument, sourceGenerator *SourceGenerator, generateConfig *config.GenerateConfig) *Source {
return &Source{
schema: schema,
queryDocument: queryDocument,
sourceGenerator: sourceGenerator,
generateConfig: generateConfig,
}
}
type Fragment struct {
Name string
Type types.Type
}
func (s *Source) Fragments() ([]*Fragment, error) {
fragments := make([]*Fragment, 0, len(s.queryDocument.Fragments))
for _, fragment := range s.queryDocument.Fragments {
responseFields := s.sourceGenerator.NewResponseFields(fragment.SelectionSet)
if s.sourceGenerator.cfg.Models.Exists(fragment.Name) {
return nil, fmt.Errorf("%s is duplicated", fragment.Name)
}
fragment := &Fragment{
Name: fragment.Name,
Type: responseFields.StructType(),
}
fragments = append(fragments, fragment)
}
for _, fragment := range fragments {
name := fragment.Name
s.sourceGenerator.cfg.Models.Add(
name,
fmt.Sprintf("%s.%s", s.sourceGenerator.client.Pkg(), templates.ToGo(name)),
)
}
return fragments, nil
}
type Operation struct {
Name string
ResponseStructName string
Operation string
Args []*Argument
VariableDefinitions ast.VariableDefinitionList
}
func NewOperation(operation *ast.OperationDefinition, queryDocument *ast.QueryDocument, args []*Argument, generateConfig *config.GenerateConfig) *Operation {
return &Operation{
Name: operation.Name,
ResponseStructName: getResponseStructName(operation, generateConfig),
Operation: queryString(queryDocument),
Args: args,
VariableDefinitions: operation.VariableDefinitions,
}
}
func (s *Source) Operations(queryDocuments []*ast.QueryDocument) ([]*Operation, error) {
operations := make([]*Operation, 0, len(s.queryDocument.Operations))
operationNames := make(map[string]struct{})
queryDocumentsMap := queryDocumentMapByOperationName(queryDocuments)
operationArgsMap := s.operationArgsMapByOperationName()
for _, operation := range s.queryDocument.Operations {
queryDocument := queryDocumentsMap[operation.Name]
_, exist := operationNames[templates.ToGo(operation.Name)]
if exist {
return nil, fmt.Errorf("duplicate operation: %s", operation.Name)
}
operationNames[templates.ToGo(operation.Name)] = struct{}{}
args := operationArgsMap[operation.Name]
operations = append(operations, NewOperation(
operation,
queryDocument,
args,
s.generateConfig,
))
}
return operations, nil
}
func (s *Source) operationArgsMapByOperationName() map[string][]*Argument {
operationArgsMap := make(map[string][]*Argument)
for _, operation := range s.queryDocument.Operations {
operationArgsMap[operation.Name] = s.sourceGenerator.OperationArguments(operation.VariableDefinitions)
}
return operationArgsMap
}
func queryDocumentMapByOperationName(queryDocuments []*ast.QueryDocument) map[string]*ast.QueryDocument {
queryDocumentMap := make(map[string]*ast.QueryDocument)
for _, queryDocument := range queryDocuments {
operation := queryDocument.Operations[0]
queryDocumentMap[operation.Name] = queryDocument
}
return queryDocumentMap
}
func queryString(queryDocument *ast.QueryDocument) string {
var buf bytes.Buffer
astFormatter := formatter.NewFormatter(&buf)
astFormatter.FormatQueryDocument(queryDocument)
return buf.String()
}
type OperationResponse struct {
Name string
Type types.Type
}
func (s *Source) OperationResponses() ([]*OperationResponse, error) {
operationResponse := make([]*OperationResponse, 0, len(s.queryDocument.Operations))
for _, operation := range s.queryDocument.Operations {
responseFields := s.sourceGenerator.NewResponseFields(operation.SelectionSet)
name := getResponseStructName(operation, s.generateConfig)
if s.sourceGenerator.cfg.Models.Exists(name) {
return nil, fmt.Errorf("%s is duplicated", name)
}
operationResponse = append(operationResponse, &OperationResponse{
Name: name,
Type: responseFields.StructType(),
})
}
for _, operationResponse := range operationResponse {
name := operationResponse.Name
s.sourceGenerator.cfg.Models.Add(
name,
fmt.Sprintf("%s.%s", s.sourceGenerator.client.Pkg(), templates.ToGo(name)),
)
}
return operationResponse, nil
}
type Query struct {
Name string
Type types.Type
}
func (s *Source) Query() (*Query, error) {
fields, err := s.sourceGenerator.NewResponseFieldsByDefinition(s.schema.Query)
if err != nil {
return nil, fmt.Errorf("generate failed for query struct type : %w", err)
}
s.sourceGenerator.cfg.Models.Add(
s.schema.Query.Name,
fmt.Sprintf("%s.%s", s.sourceGenerator.client.Pkg(), templates.ToGo(s.schema.Query.Name)),
)
return &Query{
Name: s.schema.Query.Name,
Type: fields.StructType(),
}, nil
}
type Mutation struct {
Name string
Type types.Type
}
func (s *Source) Mutation() (*Mutation, error) {
if s.schema.Mutation == nil {
return nil, nil
}
fields, err := s.sourceGenerator.NewResponseFieldsByDefinition(s.schema.Mutation)
if err != nil {
return nil, fmt.Errorf("generate failed for mutation struct type : %w", err)
}
s.sourceGenerator.cfg.Models.Add(
s.schema.Mutation.Name,
fmt.Sprintf("%s.%s", s.sourceGenerator.client.Pkg(), templates.ToGo(s.schema.Mutation.Name)),
)
return &Mutation{
Name: s.schema.Mutation.Name,
Type: fields.StructType(),
}, nil
}
func getResponseStructName(operation *ast.OperationDefinition, generateConfig *config.GenerateConfig) string {
name := operation.Name
if generateConfig != nil {
if generateConfig.Prefix != nil {
if operation.Operation == ast.Mutation {
name = fmt.Sprintf("%s%s", generateConfig.Prefix.Mutation, name)
}
if operation.Operation == ast.Query {
name = fmt.Sprintf("%s%s", generateConfig.Prefix.Query, name)
}
}
if generateConfig.Suffix != nil {
if operation.Operation == ast.Mutation {
name = fmt.Sprintf("%s%s", name, generateConfig.Suffix.Mutation)
}
if operation.Operation == ast.Query {
name = fmt.Sprintf("%s%s", name, generateConfig.Suffix.Query)
}
}
}
return name
}