Update go dependencies (#3480)

* Bump golang.org/x/text from 0.3.7 to 0.3.8

Bumps [golang.org/x/text](https://github.com/golang/text) from 0.3.7 to 0.3.8.
- [Release notes](https://github.com/golang/text/releases)
- [Commits](https://github.com/golang/text/compare/v0.3.7...v0.3.8)

---
updated-dependencies:
- dependency-name: golang.org/x/text
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update go dependencies

* Update x/net

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
WithoutPants
2023-02-28 08:26:14 +11:00
committed by GitHub
parent 445e0a7311
commit 30809e16fa
417 changed files with 32289 additions and 17730 deletions

View File

@@ -73,11 +73,15 @@ func (b *builder) buildArg(obj *Object, arg *ast.ArgumentDefinition) (*FieldArgu
return &newArg, nil
}
func (b *builder) bindArgs(field *Field, params *types.Tuple) ([]*FieldArgument, error) {
var newArgs []*FieldArgument
func (b *builder) bindArgs(field *Field, sig *types.Signature, params *types.Tuple) ([]*FieldArgument, error) {
n := params.Len()
newArgs := make([]*FieldArgument, 0, len(field.Args))
// Accept variadic methods (i.e. have optional parameters).
if params.Len() > len(field.Args) && sig.Variadic() {
n = len(field.Args)
}
nextArg:
for j := 0; j < params.Len(); j++ {
for j := 0; j < n; j++ {
param := params.At(j)
for _, oldArg := range field.Args {
if strings.EqualFold(oldArg.Name, param.Name()) {

View File

@@ -183,15 +183,16 @@ func (b *Binder) PointerTo(ref *TypeReference) *TypeReference {
// TypeReference is used by args and field types. The Definition can refer to both input and output types.
type TypeReference struct {
Definition *ast.Definition
GQL *ast.Type
GO types.Type // Type of the field being bound. Could be a pointer or a value type of Target.
Target types.Type // The actual type that we know how to bind to. May require pointer juggling when traversing to fields.
CastType types.Type // Before calling marshalling functions cast from/to this base type
Marshaler *types.Func // When using external marshalling functions this will point to the Marshal function
Unmarshaler *types.Func // When using external marshalling functions this will point to the Unmarshal function
IsMarshaler bool // Does the type implement graphql.Marshaler and graphql.Unmarshaler
IsContext bool // Is the Marshaler/Unmarshaller the context version; applies to either the method or interface variety.
Definition *ast.Definition
GQL *ast.Type
GO types.Type // Type of the field being bound. Could be a pointer or a value type of Target.
Target types.Type // The actual type that we know how to bind to. May require pointer juggling when traversing to fields.
CastType types.Type // Before calling marshalling functions cast from/to this base type
Marshaler *types.Func // When using external marshalling functions this will point to the Marshal function
Unmarshaler *types.Func // When using external marshalling functions this will point to the Unmarshal function
IsMarshaler bool // Does the type implement graphql.Marshaler and graphql.Unmarshaler
IsContext bool // Is the Marshaler/Unmarshaller the context version; applies to either the method or interface variety.
PointersInUmarshalInput bool // Inverse values and pointers in return.
}
func (ref *TypeReference) Elem() *TypeReference {
@@ -216,7 +217,6 @@ func (t *TypeReference) IsPtr() bool {
}
// fix for https://github.com/golang/go/issues/31103 may make it possible to remove this (may still be useful)
//
func (t *TypeReference) IsPtrToPtr() bool {
if p, isPtr := t.GO.(*types.Pointer); isPtr {
_, isPtr := p.Elem().(*types.Pointer)
@@ -252,6 +252,39 @@ func (t *TypeReference) IsStruct() bool {
return isStruct
}
func (t *TypeReference) IsUnderlyingBasic() bool {
_, isUnderlyingBasic := t.GO.Underlying().(*types.Basic)
return isUnderlyingBasic
}
func (t *TypeReference) IsUnusualBasic() bool {
if basic, isBasic := t.GO.(*types.Basic); isBasic {
switch basic.Kind() {
case types.Int8, types.Int16, types.Uint, types.Uint8, types.Uint16, types.Uint32:
return true
default:
return false
}
}
return false
}
func (t *TypeReference) IsUnderlyingUnusualBasic() bool {
if basic, isUnderlyingBasic := t.GO.Underlying().(*types.Basic); isUnderlyingBasic {
switch basic.Kind() {
case types.Int8, types.Int16, types.Uint, types.Uint8, types.Uint16, types.Uint32:
return true
default:
return false
}
}
return false
}
func (t *TypeReference) IsScalarID() bool {
return t.Definition.Kind == ast.Scalar && t.Marshaler.Name() == "MarshalID"
}
func (t *TypeReference) IsScalar() bool {
return t.Definition.Kind == ast.Scalar
}
@@ -413,6 +446,8 @@ func (b *Binder) TypeReference(schemaType *ast.Type, bindTarget types.Type) (ret
ref.GO = bindTarget
}
ref.PointersInUmarshalInput = b.cfg.ReturnPointersInUmarshalInput
return ref, nil
}

View File

@@ -1,8 +1,8 @@
package config
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"regexp"
@@ -12,25 +12,30 @@ import (
"github.com/99designs/gqlgen/internal/code"
"github.com/vektah/gqlparser/v2"
"github.com/vektah/gqlparser/v2/ast"
"gopkg.in/yaml.v2"
"gopkg.in/yaml.v3"
)
type Config struct {
SchemaFilename StringList `yaml:"schema,omitempty"`
Exec ExecConfig `yaml:"exec"`
Model PackageConfig `yaml:"model,omitempty"`
Federation PackageConfig `yaml:"federation,omitempty"`
Resolver ResolverConfig `yaml:"resolver,omitempty"`
AutoBind []string `yaml:"autobind"`
Models TypeMap `yaml:"models,omitempty"`
StructTag string `yaml:"struct_tag,omitempty"`
Directives map[string]DirectiveConfig `yaml:"directives,omitempty"`
OmitSliceElementPointers bool `yaml:"omit_slice_element_pointers,omitempty"`
SkipValidation bool `yaml:"skip_validation,omitempty"`
SkipModTidy bool `yaml:"skip_mod_tidy,omitempty"`
Sources []*ast.Source `yaml:"-"`
Packages *code.Packages `yaml:"-"`
Schema *ast.Schema `yaml:"-"`
SchemaFilename StringList `yaml:"schema,omitempty"`
Exec ExecConfig `yaml:"exec"`
Model PackageConfig `yaml:"model,omitempty"`
Federation PackageConfig `yaml:"federation,omitempty"`
Resolver ResolverConfig `yaml:"resolver,omitempty"`
AutoBind []string `yaml:"autobind"`
Models TypeMap `yaml:"models,omitempty"`
StructTag string `yaml:"struct_tag,omitempty"`
Directives map[string]DirectiveConfig `yaml:"directives,omitempty"`
OmitSliceElementPointers bool `yaml:"omit_slice_element_pointers,omitempty"`
OmitGetters bool `yaml:"omit_getters,omitempty"`
OmitComplexity bool `yaml:"omit_complexity,omitempty"`
StructFieldsAlwaysPointers bool `yaml:"struct_fields_always_pointers,omitempty"`
ReturnPointersInUmarshalInput bool `yaml:"return_pointers_in_unmarshalinput,omitempty"`
ResolversAlwaysReturnPointers bool `yaml:"resolvers_always_return_pointers,omitempty"`
SkipValidation bool `yaml:"skip_validation,omitempty"`
SkipModTidy bool `yaml:"skip_mod_tidy,omitempty"`
Sources []*ast.Source `yaml:"-"`
Packages *code.Packages `yaml:"-"`
Schema *ast.Schema `yaml:"-"`
// Deprecated: use Federation instead. Will be removed next release
Federated bool `yaml:"federated,omitempty"`
@@ -41,11 +46,14 @@ var cfgFilenames = []string{".gqlgen.yml", "gqlgen.yml", "gqlgen.yaml"}
// DefaultConfig creates a copy of the default config
func DefaultConfig() *Config {
return &Config{
SchemaFilename: StringList{"schema.graphql"},
Model: PackageConfig{Filename: "models_gen.go"},
Exec: ExecConfig{Filename: "generated.go"},
Directives: map[string]DirectiveConfig{},
Models: TypeMap{},
SchemaFilename: StringList{"schema.graphql"},
Model: PackageConfig{Filename: "models_gen.go"},
Exec: ExecConfig{Filename: "generated.go"},
Directives: map[string]DirectiveConfig{},
Models: TypeMap{},
StructFieldsAlwaysPointers: true,
ReturnPointersInUmarshalInput: false,
ResolversAlwaysReturnPointers: true,
}
}
@@ -57,7 +65,7 @@ func LoadDefaultConfig() (*Config, error) {
filename = filepath.ToSlash(filename)
var err error
var schemaRaw []byte
schemaRaw, err = ioutil.ReadFile(filename)
schemaRaw, err = os.ReadFile(filename)
if err != nil {
return nil, fmt.Errorf("unable to open schema: %w", err)
}
@@ -94,12 +102,15 @@ var path2regex = strings.NewReplacer(
func LoadConfig(filename string) (*Config, error) {
config := DefaultConfig()
b, err := ioutil.ReadFile(filename)
b, err := os.ReadFile(filename)
if err != nil {
return nil, fmt.Errorf("unable to read config: %w", err)
}
if err := yaml.UnmarshalStrict(b, config); err != nil {
dec := yaml.NewDecoder(bytes.NewReader(b))
dec.KnownFields(true)
if err := dec.Decode(config); err != nil {
return nil, fmt.Errorf("unable to parse config: %w", err)
}
@@ -173,7 +184,7 @@ func CompleteConfig(config *Config) error {
filename = filepath.ToSlash(filename)
var err error
var schemaRaw []byte
schemaRaw, err = ioutil.ReadFile(filename)
schemaRaw, err = os.ReadFile(filename)
if err != nil {
return fmt.Errorf("unable to open schema: %w", err)
}

View File

@@ -12,6 +12,7 @@ import (
type PackageConfig struct {
Filename string `yaml:"filename,omitempty"`
Package string `yaml:"package,omitempty"`
Version int `yaml:"version,omitempty"`
}
func (c *PackageConfig) ImportPath() string {

View File

@@ -2,7 +2,10 @@ package codegen
import (
"fmt"
"os"
"path/filepath"
"sort"
"strings"
"github.com/vektah/gqlparser/v2/ast"
@@ -30,6 +33,26 @@ type Data struct {
QueryRoot *Object
MutationRoot *Object
SubscriptionRoot *Object
AugmentedSources []AugmentedSource
}
func (d *Data) HasEmbeddableSources() bool {
hasEmbeddableSources := false
for _, s := range d.AugmentedSources {
if s.Embeddable {
hasEmbeddableSources = true
}
}
return hasEmbeddableSources
}
// AugmentedSource contains extra information about graphql schema files which is not known directly from the Config.Sources data
type AugmentedSource struct {
// path relative to Config.Exec.Filename
RelativePath string
Embeddable bool
BuiltIn bool
Source string
}
type builder struct {
@@ -147,6 +170,31 @@ func BuildData(cfg *config.Config) (*Data, error) {
// otherwise show a generic error message
return nil, fmt.Errorf("invalid types were encountered while traversing the go source code, this probably means the invalid code generated isnt correct. add try adding -v to debug")
}
aSources := []AugmentedSource{}
for _, s := range cfg.Sources {
wd, err := os.Getwd()
if err != nil {
return nil, fmt.Errorf("failed to get working directory: %w", err)
}
outputDir := cfg.Exec.Dir()
sourcePath := filepath.Join(wd, s.Name)
relative, err := filepath.Rel(outputDir, sourcePath)
if err != nil {
return nil, fmt.Errorf("failed to compute path of %s relative to %s: %w", sourcePath, outputDir, err)
}
relative = filepath.ToSlash(relative)
embeddable := true
if strings.HasPrefix(relative, "..") || s.BuiltIn {
embeddable = false
}
aSources = append(aSources, AugmentedSource{
RelativePath: relative,
Embeddable: embeddable,
BuiltIn: s.BuiltIn,
Source: s.Input,
})
}
s.AugmentedSources = aSources
return &s, nil
}

View File

@@ -70,7 +70,7 @@ func (ec *executionContext) _mutationMiddleware(ctx context.Context, obj *ast.Op
{{ end }}
{{ if .Directives.LocationDirectives "SUBSCRIPTION" }}
func (ec *executionContext) _subscriptionMiddleware(ctx context.Context, obj *ast.OperationDefinition, next func(ctx context.Context) (interface{}, error)) func() graphql.Marshaler {
func (ec *executionContext) _subscriptionMiddleware(ctx context.Context, obj *ast.OperationDefinition, next func(ctx context.Context) (interface{}, error)) func(ctx context.Context) graphql.Marshaler {
for _, d := range obj.Directives {
switch d.Name {
{{- range $directive := .Directives.LocationDirectives "SUBSCRIPTION" }}
@@ -80,7 +80,7 @@ func (ec *executionContext) _subscriptionMiddleware(ctx context.Context, obj *as
args, err := ec.{{ $directive.ArgsFunc }}(ctx,rawArgs)
if err != nil {
ec.Error(ctx, err)
return func() graphql.Marshaler {
return func(ctx context.Context) graphql.Marshaler {
return graphql.Null
}
}
@@ -98,15 +98,15 @@ func (ec *executionContext) _subscriptionMiddleware(ctx context.Context, obj *as
tmp, err := next(ctx)
if err != nil {
ec.Error(ctx, err)
return func() graphql.Marshaler {
return func(ctx context.Context) graphql.Marshaler {
return graphql.Null
}
}
if data, ok := tmp.(func() graphql.Marshaler); ok {
if data, ok := tmp.(func(ctx context.Context) graphql.Marshaler); ok {
return data
}
ec.Errorf(ctx, `unexpected type %T from directive, should be graphql.Marshaler`, tmp)
return func() graphql.Marshaler {
return func(ctx context.Context) graphql.Marshaler {
return graphql.Null
}
}

View File

@@ -3,6 +3,7 @@ package codegen
import (
"errors"
"fmt"
goast "go/ast"
"go/types"
"log"
"reflect"
@@ -12,6 +13,8 @@ import (
"github.com/99designs/gqlgen/codegen/config"
"github.com/99designs/gqlgen/codegen/templates"
"github.com/vektah/gqlparser/v2/ast"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)
type Field struct {
@@ -71,7 +74,7 @@ func (b *builder) buildField(obj *Object, field *ast.FieldDefinition) (*Field, e
log.Println(err.Error())
}
if f.IsResolver && !f.TypeReference.IsPtr() && f.TypeReference.IsStruct() {
if f.IsResolver && b.Config.ResolversAlwaysReturnPointers && !f.TypeReference.IsPtr() && f.TypeReference.IsStruct() {
f.TypeReference = b.Binder.PointerTo(f.TypeReference)
}
@@ -179,8 +182,8 @@ func (b *builder) bindField(obj *Object, f *Field) (errret error) {
params = types.NewTuple(vars...)
}
// Try to match target function's arguments with GraphQL field arguments
newArgs, err := b.bindArgs(f, params)
// Try to match target function's arguments with GraphQL field arguments.
newArgs, err := b.bindArgs(f, sig, params)
if err != nil {
return fmt.Errorf("%s:%d: %w", pos.Filename, pos.Line, err)
}
@@ -469,10 +472,11 @@ func (f *Field) GoNameUnexported() string {
}
func (f *Field) ShortInvocation() string {
caser := cases.Title(language.English, cases.NoLower)
if f.Object.Kind == ast.InputObject {
return fmt.Sprintf("%s().%s(ctx, &it, data)", strings.Title(f.Object.Definition.Name), f.GoFieldName)
return fmt.Sprintf("%s().%s(ctx, &it, data)", caser.String(f.Object.Definition.Name), f.GoFieldName)
}
return fmt.Sprintf("%s().%s(%s)", strings.Title(f.Object.Definition.Name), f.GoFieldName, f.CallArgs())
return fmt.Sprintf("%s().%s(%s)", caser.String(f.Object.Definition.Name), f.GoFieldName, f.CallArgs())
}
func (f *Field) ArgsFunc() string {
@@ -483,6 +487,14 @@ func (f *Field) ArgsFunc() string {
return "field_" + f.Object.Definition.Name + "_" + f.Name + "_args"
}
func (f *Field) FieldContextFunc() string {
return "fieldContext_" + f.Object.Definition.Name + "_" + f.Name
}
func (f *Field) ChildFieldContextFunc(name string) string {
return "fieldContext_" + f.TypeReference.Definition.Name + "_" + name
}
func (f *Field) ResolverType() string {
if !f.IsResolver {
return ""
@@ -492,6 +504,12 @@ func (f *Field) ResolverType() string {
}
func (f *Field) ShortResolverDeclaration() string {
return f.ShortResolverSignature(nil)
}
// ShortResolverSignature is identical to ShortResolverDeclaration,
// but respects previous naming (return) conventions, if any.
func (f *Field) ShortResolverSignature(ft *goast.FuncType) string {
if f.Object.Kind == ast.InputObject {
return fmt.Sprintf("(ctx context.Context, obj %s, data %s) error",
templates.CurrentImports.LookupType(f.Object.Reference()),
@@ -512,8 +530,17 @@ func (f *Field) ShortResolverDeclaration() string {
if f.Object.Stream {
result = "<-chan " + result
}
res += fmt.Sprintf(") (%s, error)", result)
// Named return.
var namedV, namedE string
if ft != nil {
if ft.Results != nil && len(ft.Results.List) > 0 && len(ft.Results.List[0].Names) > 0 {
namedV = ft.Results.List[0].Names[0].Name
}
if ft.Results != nil && len(ft.Results.List) > 1 && len(ft.Results.List[1].Names) > 0 {
namedE = ft.Results.List[1].Names[0].Name
}
}
res += fmt.Sprintf(") (%s %s, %s error)", namedV, result, namedE)
return res
}
@@ -549,7 +576,20 @@ func (f *Field) CallArgs() string {
}
for _, arg := range f.Args {
args = append(args, "args["+strconv.Quote(arg.Name)+"].("+templates.CurrentImports.LookupType(arg.TypeReference.GO)+")")
tmp := "fc.Args[" + strconv.Quote(arg.Name) + "].(" + templates.CurrentImports.LookupType(arg.TypeReference.GO) + ")"
if iface, ok := arg.TypeReference.GO.(*types.Interface); ok && iface.Empty() {
tmp = fmt.Sprintf(`
func () interface{} {
if fc.Args["%s"] == nil {
return nil
}
return fc.Args["%s"].(interface{})
}()`, arg.Name, arg.Name,
)
}
args = append(args, tmp)
}
return strings.Join(args, ", ")

View File

@@ -1,34 +1,21 @@
{{- range $object := .Objects }}{{- range $field := $object.Fields }}
func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Context, field graphql.CollectedField{{ if not $object.Root }}, obj {{$object.Reference | ref}}{{end}}) (ret {{ if $object.Stream }}func(){{ end }}graphql.Marshaler) {
func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Context, field graphql.CollectedField{{ if not $object.Root }}, obj {{$object.Reference | ref}}{{end}}) (ret {{ if $object.Stream }}func(ctx context.Context){{ end }}graphql.Marshaler) {
{{- $null := "graphql.Null" }}
{{- if $object.Stream }}
{{- $null = "nil" }}
{{- end }}
fc, err := ec.{{ $field.FieldContextFunc }}(ctx, field)
if err != nil {
return {{ $null }}
}
ctx = graphql.WithFieldContext(ctx, fc)
defer func () {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = {{ $null }}
}
}()
fc := &graphql.FieldContext{
Object: {{$object.Name|quote}},
Field: field,
Args: nil,
IsMethod: {{or $field.IsMethod $field.IsResolver}},
IsResolver: {{ $field.IsResolver }},
}
ctx = graphql.WithFieldContext(ctx, fc)
{{- if $field.Args }}
rawArgs := field.ArgumentMap(ec.Variables)
args, err := ec.{{ $field.ArgsFunc }}(ctx,rawArgs)
if err != nil {
ec.Error(ctx, err)
return {{ $null }}
}
fc.Args = args
{{- end }}
{{- if $.AllDirectives.LocationDirectives "FIELD" }}
resTmp := ec._fieldMiddleware(ctx, {{if $object.Root}}nil{{else}}obj{{end}}, func(rctx context.Context) (interface{}, error) {
{{ template "field" $field }}
@@ -39,7 +26,9 @@ func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Contex
})
if err != nil {
ec.Error(ctx, err)
return {{ $null }}
{{- if not $object.Root }}
return {{ $null }}
{{- end }}
}
{{- end }}
if resTmp == nil {
@@ -51,18 +40,22 @@ func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Contex
return {{ $null }}
}
{{- if $object.Stream }}
return func() graphql.Marshaler {
res, ok := <-resTmp.(<-chan {{$field.TypeReference.GO | ref}})
if !ok {
return func(ctx context.Context) graphql.Marshaler {
select {
case res, ok := <-resTmp.(<-chan {{$field.TypeReference.GO | ref}}):
if !ok {
return nil
}
return graphql.WriterFunc(func(w io.Writer) {
w.Write([]byte{'{'})
graphql.MarshalString(field.Alias).MarshalGQL(w)
w.Write([]byte{':'})
ec.{{ $field.TypeReference.MarshalFunc }}(ctx, field.Selections, res).MarshalGQL(w)
w.Write([]byte{'}'})
})
case <-ctx.Done():
return nil
}
return graphql.WriterFunc(func(w io.Writer) {
w.Write([]byte{'{'})
graphql.MarshalString(field.Alias).MarshalGQL(w)
w.Write([]byte{':'})
ec.{{ $field.TypeReference.MarshalFunc }}(ctx, field.Selections, res).MarshalGQL(w)
w.Write([]byte{'}'})
})
}
{{- else }}
res := resTmp.({{$field.TypeReference.GO | ref}})
@@ -71,6 +64,44 @@ func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Contex
{{- end }}
}
func (ec *executionContext) {{ $field.FieldContextFunc }}(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
fc = &graphql.FieldContext{
Object: {{quote $field.Object.Name}},
Field: field,
IsMethod: {{or $field.IsMethod $field.IsResolver}},
IsResolver: {{ $field.IsResolver }},
Child: func (ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
{{- if not $field.TypeReference.Definition.Fields }}
return nil, errors.New("field of type {{ $field.TypeReference.Definition.Name }} does not have child fields")
{{- else if ne $field.TypeReference.Definition.Kind "OBJECT" }}
return nil, errors.New("FieldContext.Child cannot be called on type {{ $field.TypeReference.Definition.Kind }}")
{{- else }}
switch field.Name {
{{- range $f := $field.TypeReference.Definition.Fields }}
case "{{ $f.Name }}":
return ec.{{ $field.ChildFieldContextFunc $f.Name }}(ctx, field)
{{- end }}
}
return nil, fmt.Errorf("no field named %q was found under type {{ $field.TypeReference.Definition.Name }}", field.Name)
{{- end }}
},
}
{{- if $field.Args }}
defer func () {
if r := recover(); r != nil {
err = ec.Recover(ctx, r)
ec.Error(ctx, err)
}
}()
ctx = graphql.WithFieldContext(ctx, fc)
if fc.Args, err = ec.{{ $field.ArgsFunc }}(ctx, field.ArgumentMap(ec.Variables)); err != nil {
ec.Error(ctx, err)
return
}
{{- end }}
return fc, nil
}
{{- end }}{{- end}}
{{ define "field" }}

View File

@@ -1,9 +1,10 @@
package codegen
import (
"embed"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strings"
@@ -13,6 +14,9 @@ import (
"github.com/vektah/gqlparser/v2/ast"
)
//go:embed *.gotpl
var codegenTemplates embed.FS
func GenerateCode(data *Data) error {
if !data.Config.Exec.IsDefined() {
return fmt.Errorf("missing exec config")
@@ -36,6 +40,7 @@ func generateSingleFile(data *Data) error {
RegionTags: true,
GeneratedHeader: true,
Packages: data.Config.Packages,
TemplateFS: codegenTemplates,
})
}
@@ -82,6 +87,7 @@ func generatePerSchema(data *Data) error {
RegionTags: true,
GeneratedHeader: true,
Packages: data.Config.Packages,
TemplateFS: codegenTemplates,
})
if err != nil {
return err
@@ -131,7 +137,7 @@ func generateRootFile(data *Data) error {
_, thisFile, _, _ := runtime.Caller(0)
rootDir := filepath.Dir(thisFile)
templatePath := filepath.Join(rootDir, "root_.gotpl")
templateBytes, err := ioutil.ReadFile(templatePath)
templateBytes, err := os.ReadFile(templatePath)
if err != nil {
return err
}
@@ -145,6 +151,7 @@ func generateRootFile(data *Data) error {
RegionTags: false,
GeneratedHeader: true,
Packages: data.Config.Packages,
TemplateFS: codegenTemplates,
})
}

View File

@@ -7,6 +7,7 @@
{{ reserveImport "sync/atomic" }}
{{ reserveImport "errors" }}
{{ reserveImport "bytes" }}
{{ reserveImport "embed" }}
{{ reserveImport "github.com/vektah/gqlparser/v2" "gqlparser" }}
{{ reserveImport "github.com/vektah/gqlparser/v2/ast" }}
@@ -50,6 +51,7 @@
}
type ComplexityRoot struct {
{{- if not .Config.OmitComplexity }}
{{ range $object := .Objects }}
{{ if not $object.IsReserved -}}
{{ ucFirst $object.Name }} struct {
@@ -62,6 +64,7 @@
}
{{- end }}
{{ end }}
{{- end }}
}
{{ end }}
@@ -103,6 +106,7 @@
func (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) {
ec := executionContext{nil, e}
_ = ec
{{ if not .Config.OmitComplexity -}}
switch typeName + "." + field {
{{ range $object := .Objects }}
{{ if not $object.IsReserved }}
@@ -129,12 +133,20 @@
{{ end }}
{{ end }}
}
{{- end }}
return 0, false
}
func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
rc := graphql.GetOperationContext(ctx)
ec := executionContext{rc, e}
inputUnmarshalMap := graphql.BuildUnmarshalerMap(
{{- range $input := .Inputs -}}
{{ if not $input.HasUnmarshal }}
ec.unmarshalInput{{ $input.Name }},
{{- end }}
{{- end }}
)
first := true
switch rc.Operation.Operation {
@@ -142,6 +154,7 @@
return func(ctx context.Context) *graphql.Response {
if !first { return nil }
first = false
ctx = graphql.WithUnmarshalerMap(ctx, inputUnmarshalMap)
{{ if .Directives.LocationDirectives "QUERY" -}}
data := ec._queryMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error){
return ec._{{.QueryRoot.Name}}(ctx, rc.Operation.SelectionSet), nil
@@ -162,6 +175,7 @@
return func(ctx context.Context) *graphql.Response {
if !first { return nil }
first = false
ctx = graphql.WithUnmarshalerMap(ctx, inputUnmarshalMap)
{{ if .Directives.LocationDirectives "MUTATION" -}}
data := ec._mutationMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error){
return ec._{{.MutationRoot.Name}}(ctx, rc.Operation.SelectionSet), nil
@@ -190,7 +204,7 @@
var buf bytes.Buffer
return func(ctx context.Context) *graphql.Response {
buf.Reset()
data := next()
data := next(ctx)
if data == nil {
return nil
@@ -226,9 +240,22 @@
return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
}
{{if .HasEmbeddableSources }}
//go:embed{{- range $source := .AugmentedSources }}{{if $source.Embeddable}} {{$source.RelativePath|quote}}{{end}}{{- end }}
var sourcesFS embed.FS
func sourceData(filename string) string {
data, err := sourcesFS.ReadFile(filename)
if err != nil {
panic(fmt.Sprintf("codegen problem: %s not available", filename))
}
return string(data)
}
{{- end }}
var sources = []*ast.Source{
{{- range $source := .Config.Sources }}
{Name: {{$source.Name|quote}}, Input: {{$source.Input|rawQuote}}, BuiltIn: {{$source.BuiltIn}}},
{{- range $source := .AugmentedSources }}
{Name: {{$source.RelativePath|quote}}, Input: {{if (not $source.Embeddable)}}{{$source.Source|rawQuote}}{{else}}sourceData({{$source.RelativePath|quote}}){{end}}, BuiltIn: {{$source.BuiltIn}}},
{{- end }}
}
var parsedSchema = gqlparser.MustLoadSchema(sources...)

View File

@@ -1,6 +1,10 @@
{{- range $input := .Inputs }}
{{- if not .HasUnmarshal }}
func (ec *executionContext) unmarshalInput{{ .Name }}(ctx context.Context, obj interface{}) ({{.Type | ref}}, error) {
{{- $it := "it" }}
{{- if .PointersInUmarshalInput }}
{{- $it = "&it" }}
{{- end }}
func (ec *executionContext) unmarshalInput{{ .Name }}(ctx context.Context, obj interface{}) ({{ if .PointersInUmarshalInput }}*{{ end }}{{.Type | ref}}, error) {
var it {{.Type | ref}}
asMap := map[string]interface{}{}
for k, v := range obj.(map[string]interface{}) {
@@ -14,7 +18,12 @@
{{- end}}
{{- end }}
for k, v := range asMap {
fieldsInOrder := [...]string{ {{ range .Fields }}{{ quote .Name }},{{ end }} }
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
continue
}
switch k {
{{- range $field := .Fields }}
case {{$field.Name|quote}}:
@@ -26,12 +35,12 @@
{{ template "implDirectives" $field }}
tmp, err := directive{{$field.ImplDirectives|len}}(ctx)
if err != nil {
return it, graphql.ErrorOnPath(ctx, err)
return {{$it}}, graphql.ErrorOnPath(ctx, err)
}
if data, ok := tmp.({{ $field.TypeReference.GO | ref }}) ; ok {
{{- if $field.IsResolver }}
if err = ec.resolvers.{{ $field.ShortInvocation }}; err != nil {
return it, err
return {{$it}}, err
}
{{- else }}
it.{{$field.GoFieldName}} = data
@@ -44,21 +53,21 @@
{{- end }}
} else {
err := fmt.Errorf(`unexpected type %T from directive, should be {{ $field.TypeReference.GO }}`, tmp)
return it, graphql.ErrorOnPath(ctx, err)
return {{$it}}, graphql.ErrorOnPath(ctx, err)
}
{{- else }}
{{- if $field.IsResolver }}
data, err := ec.{{ $field.TypeReference.UnmarshalFunc }}(ctx, v)
if err != nil {
return it, err
return {{$it}}, err
}
if err = ec.resolvers.{{ $field.ShortInvocation }}; err != nil {
return it, err
return {{$it}}, err
}
{{- else }}
it.{{$field.GoFieldName}}, err = ec.{{ $field.TypeReference.UnmarshalFunc }}(ctx, v)
if err != nil {
return it, err
return {{$it}}, err
}
{{- end }}
{{- end }}
@@ -66,7 +75,7 @@
}
}
return it, nil
return {{$it}}, nil
}
{{- end }}
{{ end }}

View File

@@ -9,6 +9,8 @@ import (
"github.com/99designs/gqlgen/codegen/config"
"github.com/vektah/gqlparser/v2/ast"
"golang.org/x/text/cases"
"golang.org/x/text/language"
)
type GoFieldType int
@@ -23,14 +25,15 @@ const (
type Object struct {
*ast.Definition
Type types.Type
ResolverInterface types.Type
Root bool
Fields []*Field
Implements []*ast.Definition
DisableConcurrency bool
Stream bool
Directives []*Directive
Type types.Type
ResolverInterface types.Type
Root bool
Fields []*Field
Implements []*ast.Definition
DisableConcurrency bool
Stream bool
Directives []*Directive
PointersInUmarshalInput bool
}
func (b *builder) buildObject(typ *ast.Definition) (*Object, error) {
@@ -38,15 +41,16 @@ func (b *builder) buildObject(typ *ast.Definition) (*Object, error) {
if err != nil {
return nil, fmt.Errorf("%s: %w", typ.Name, err)
}
caser := cases.Title(language.English, cases.NoLower)
obj := &Object{
Definition: typ,
Root: b.Schema.Query == typ || b.Schema.Mutation == typ || b.Schema.Subscription == typ,
DisableConcurrency: typ == b.Schema.Mutation,
Stream: typ == b.Schema.Subscription,
Directives: dirs,
Definition: typ,
Root: b.Schema.Query == typ || b.Schema.Mutation == typ || b.Schema.Subscription == typ,
DisableConcurrency: typ == b.Schema.Mutation,
Stream: typ == b.Schema.Subscription,
Directives: dirs,
PointersInUmarshalInput: b.Config.ReturnPointersInUmarshalInput,
ResolverInterface: types.NewNamed(
types.NewTypeName(0, b.Config.Exec.Pkg(), strings.Title(typ.Name)+"Resolver", nil),
types.NewTypeName(0, b.Config.Exec.Pkg(), caser.String(typ.Name)+"Resolver", nil),
nil,
nil,
),

View File

@@ -3,7 +3,7 @@
var {{ $object.Name|lcFirst}}Implementors = {{$object.Implementors}}
{{- if .Stream }}
func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.SelectionSet) func() graphql.Marshaler {
func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.SelectionSet) func(ctx context.Context) graphql.Marshaler {
fields := graphql.CollectFields(ec.OperationContext, sel, {{$object.Name|lcFirst}}Implementors)
ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{
Object: {{$object.Name|quote}},
@@ -31,7 +31,9 @@ func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.Selec
})
{{end}}
out := graphql.NewFieldSet(fields)
var invalids uint32
{{- if not $object.Root }}
var invalids uint32
{{- end }}
for i, field := range fields {
{{- if $object.Root }}
innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{
@@ -54,14 +56,16 @@ func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.Selec
}
}()
res = ec._{{$object.Name}}_{{$field.Name}}(ctx, field{{if not $object.Root}}, obj{{end}})
{{- if $field.TypeReference.GQL.NonNull }}
if res == graphql.Null {
{{- if $object.IsConcurrent }}
atomic.AddUint32(&invalids, 1)
{{- else }}
invalids++
{{- end }}
}
{{- if not $object.Root }}
{{- if $field.TypeReference.GQL.NonNull }}
if res == graphql.Null {
{{- if $object.IsConcurrent }}
atomic.AddUint32(&invalids, 1)
{{- else }}
invalids++
{{- end }}
}
{{- end }}
{{- end }}
return res
}
@@ -80,23 +84,24 @@ func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.Selec
{{end}}
})
{{- else }}
innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
return ec._{{$object.Name}}_{{$field.Name}}(ctx, field{{if not $object.Root}}, obj{{end}})
}
{{if $object.Root}}
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc)
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
return ec._{{$object.Name}}_{{$field.Name}}(ctx, field)
})
{{else}}
out.Values[i] = innerFunc(ctx)
out.Values[i] = ec._{{$object.Name}}_{{$field.Name}}(ctx, field, obj)
{{end}}
{{- if $field.TypeReference.GQL.NonNull }}
if out.Values[i] == graphql.Null {
{{- if $object.IsConcurrent }}
atomic.AddUint32(&invalids, 1)
{{- else }}
invalids++
{{- end }}
}
{{- if not $object.Root }}
{{- if $field.TypeReference.GQL.NonNull }}
if out.Values[i] == graphql.Null {
{{- if $object.IsConcurrent }}
atomic.AddUint32(&invalids, 1)
{{- else }}
invalids++
{{- end }}
}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
@@ -105,7 +110,9 @@ func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.Selec
}
}
out.Dispatch()
if invalids > 0 { return graphql.Null }
{{- if not $object.Root }}
if invalids > 0 { return graphql.Null }
{{- end }}
return out
}
{{- end }}

View File

@@ -7,6 +7,7 @@
{{ reserveImport "sync/atomic" }}
{{ reserveImport "errors" }}
{{ reserveImport "bytes" }}
{{ reserveImport "embed" }}
{{ reserveImport "github.com/vektah/gqlparser/v2" "gqlparser" }}
{{ reserveImport "github.com/vektah/gqlparser/v2/ast" }}
@@ -34,6 +35,11 @@ type ResolverRoot interface {
{{ucFirst $object.Name}}() {{ucFirst $object.Name}}Resolver
{{ end }}
{{- end }}
{{- range $object := .Inputs -}}
{{ if $object.HasResolvers -}}
{{ucFirst $object.Name}}() {{ucFirst $object.Name}}Resolver
{{ end }}
{{- end }}
}
type DirectiveRoot struct {
@@ -43,6 +49,7 @@ type DirectiveRoot struct {
}
type ComplexityRoot struct {
{{- if not .Config.OmitComplexity }}
{{ range $object := .Objects }}
{{ if not $object.IsReserved -}}
{{ ucFirst $object.Name }} struct {
@@ -55,6 +62,7 @@ type ComplexityRoot struct {
}
{{- end }}
{{ end }}
{{- end }}
}
type executableSchema struct {
@@ -70,6 +78,7 @@ func (e *executableSchema) Schema() *ast.Schema {
func (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) {
ec := executionContext{nil, e}
_ = ec
{{- if not .Config.OmitComplexity }}
switch typeName + "." + field {
{{ range $object := .Objects }}
{{ if not $object.IsReserved }}
@@ -96,12 +105,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
{{ end }}
{{ end }}
}
{{- end }}
return 0, false
}
func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
rc := graphql.GetOperationContext(ctx)
ec := executionContext{rc, e}
inputUnmarshalMap := graphql.BuildUnmarshalerMap(
{{- range $input := .Inputs -}}
{{ if not $input.HasUnmarshal }}
ec.unmarshalInput{{ $input.Name }},
{{- end }}
{{- end }}
)
first := true
switch rc.Operation.Operation {
@@ -109,6 +126,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
return func(ctx context.Context) *graphql.Response {
if !first { return nil }
first = false
ctx = graphql.WithUnmarshalerMap(ctx, inputUnmarshalMap)
{{ if .Directives.LocationDirectives "QUERY" -}}
data := ec._queryMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error){
return ec._{{.QueryRoot.Name}}(ctx, rc.Operation.SelectionSet), nil
@@ -129,6 +147,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
return func(ctx context.Context) *graphql.Response {
if !first { return nil }
first = false
ctx = graphql.WithUnmarshalerMap(ctx, inputUnmarshalMap)
{{ if .Directives.LocationDirectives "MUTATION" -}}
data := ec._mutationMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error){
return ec._{{.MutationRoot.Name}}(ctx, rc.Operation.SelectionSet), nil
@@ -157,7 +176,7 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
var buf bytes.Buffer
return func(ctx context.Context) *graphql.Response {
buf.Reset()
data := next()
data := next(ctx)
if data == nil {
return nil
@@ -193,9 +212,23 @@ func (ec *executionContext) introspectType(name string) (*introspection.Type, er
return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
}
{{if .HasEmbeddableSources }}
//go:embed{{- range $source := .AugmentedSources }}{{if $source.Embeddable}} {{$source.RelativePath|quote}}{{end}}{{- end }}
var sourcesFS embed.FS
func sourceData(filename string) string {
data, err := sourcesFS.ReadFile(filename)
if err != nil {
panic(fmt.Sprintf("codegen problem: %s not available", filename))
}
return string(data)
}
{{- end}}
var sources = []*ast.Source{
{{- range $source := .Config.Sources }}
{Name: {{$source.Name|quote}}, Input: {{$source.Input|rawQuote}}, BuiltIn: {{$source.BuiltIn}}},
{{- range $source := .AugmentedSources }}
{Name: {{$source.RelativePath|quote}}, Input: {{if (not $source.Embeddable)}}{{$source.Source|rawQuote}}{{else}}sourceData({{$source.RelativePath|quote}}){{end}}, BuiltIn: {{$source.BuiltIn}}},
{{- end }}
}
var parsedSchema = gqlparser.MustLoadSchema(sources...)

View File

@@ -45,7 +45,7 @@ func (s *Imports) Reserve(path string, aliases ...string) (string, error) {
panic("empty ambient import")
}
// if we are referencing our own package we dont need an import
// if we are referencing our own package we don't need an import
if code.ImportPathForDir(s.destDir) == path {
return "", nil
}
@@ -85,7 +85,7 @@ func (s *Imports) Lookup(path string) string {
path = code.NormalizeVendor(path)
// if we are referencing our own package we dont need an import
// if we are referencing our own package we don't need an import
if code.ImportPathForDir(s.destDir) == path {
return ""
}

View File

@@ -4,14 +4,16 @@ import (
"bytes"
"fmt"
"go/types"
"io/ioutil"
"io/fs"
"os"
"path/filepath"
"reflect"
"regexp"
"runtime"
"sort"
"strconv"
"strings"
"sync"
"text/template"
"unicode"
@@ -36,6 +38,11 @@ type Options struct {
// the plugin processor will look for .gotpl files
// in the same directory of where you wrote the plugin.
Template string
// Use the go:embed API to collect all the template files you want to pass into Render
// this is an alternative to passing the Template option
TemplateFS fs.FS
// Filename is the name of the file that will be
// written to the system disk once the template is rendered.
Filename string
@@ -53,6 +60,12 @@ type Options struct {
Packages *code.Packages
}
var (
modelNamesMu sync.Mutex
modelNames = make(map[string]string, 0)
goNameRe = regexp.MustCompile("[^a-zA-Z0-9_]")
)
// Render renders a gql plugin template from the given Options. Render is an
// abstraction of the text/template package that makes it easier to write gqlgen
// plugins. If Options.Template is empty, the Render function will look for `.gotpl`
@@ -63,55 +76,27 @@ func Render(cfg Options) error {
}
CurrentImports = &Imports{packages: cfg.Packages, destDir: filepath.Dir(cfg.Filename)}
// load path relative to calling source file
_, callerFile, _, _ := runtime.Caller(1)
rootDir := filepath.Dir(callerFile)
funcs := Funcs()
for n, f := range cfg.Funcs {
funcs[n] = f
}
t := template.New("").Funcs(funcs)
t, err := parseTemplates(cfg, t)
if err != nil {
return err
}
var roots []string
if cfg.Template != "" {
var err error
t, err = t.New("template.gotpl").Parse(cfg.Template)
if err != nil {
return fmt.Errorf("error with provided template: %w", err)
roots := make([]string, 0, len(t.Templates()))
for _, template := range t.Templates() {
// templates that end with _.gotpl are special files we don't want to include
if strings.HasSuffix(template.Name(), "_.gotpl") ||
// filter out templates added with {{ template xxx }} syntax inside the template file
!strings.HasSuffix(template.Name(), ".gotpl") {
continue
}
roots = append(roots, "template.gotpl")
} else {
// load all the templates in the directory
err := filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
name := filepath.ToSlash(strings.TrimPrefix(path, rootDir+string(os.PathSeparator)))
if !strings.HasSuffix(info.Name(), ".gotpl") {
return nil
}
// omit any templates with "_" at the end of their name, which are meant for specific contexts only
if strings.HasSuffix(info.Name(), "_.gotpl") {
return nil
}
b, err := ioutil.ReadFile(path)
if err != nil {
return err
}
t, err = t.New(name).Parse(string(b))
if err != nil {
return fmt.Errorf("%s: %w", cfg.Filename, err)
}
roots = append(roots, name)
return nil
})
if err != nil {
return fmt.Errorf("locating templates: %w", err)
}
roots = append(roots, template.Name())
}
// then execute all the important looking ones in order, adding them to the same file
@@ -125,6 +110,7 @@ func Render(cfg Options) error {
}
return roots[i] < roots[j]
})
var buf bytes.Buffer
for _, root := range roots {
if cfg.RegionTags {
@@ -156,7 +142,7 @@ func Render(cfg Options) error {
result.WriteString("import (\n")
result.WriteString(CurrentImports.String())
result.WriteString(")\n")
_, err := buf.WriteTo(&result)
_, err = buf.WriteTo(&result)
if err != nil {
return err
}
@@ -171,6 +157,34 @@ func Render(cfg Options) error {
return nil
}
func parseTemplates(cfg Options, t *template.Template) (*template.Template, error) {
if cfg.Template != "" {
var err error
t, err = t.New("template.gotpl").Parse(cfg.Template)
if err != nil {
return nil, fmt.Errorf("error with provided template: %w", err)
}
return t, nil
}
var fileSystem fs.FS
if cfg.TemplateFS != nil {
fileSystem = cfg.TemplateFS
} else {
// load path relative to calling source file
_, callerFile, _, _ := runtime.Caller(1)
rootDir := filepath.Dir(callerFile)
fileSystem = os.DirFS(rootDir)
}
t, err := t.ParseFS(fileSystem, "*.gotpl")
if err != nil {
return nil, fmt.Errorf("locating templates: %w", err)
}
return t, nil
}
func center(width int, pad string, s string) string {
if len(s)+2 > width {
return s
@@ -182,20 +196,22 @@ func center(width int, pad string, s string) string {
func Funcs() template.FuncMap {
return template.FuncMap{
"ucFirst": UcFirst,
"lcFirst": LcFirst,
"quote": strconv.Quote,
"rawQuote": rawQuote,
"dump": Dump,
"ref": ref,
"ts": TypeIdentifier,
"call": Call,
"prefixLines": prefixLines,
"notNil": notNil,
"reserveImport": CurrentImports.Reserve,
"lookupImport": CurrentImports.Lookup,
"go": ToGo,
"goPrivate": ToGoPrivate,
"ucFirst": UcFirst,
"lcFirst": LcFirst,
"quote": strconv.Quote,
"rawQuote": rawQuote,
"dump": Dump,
"ref": ref,
"ts": TypeIdentifier,
"call": Call,
"prefixLines": prefixLines,
"notNil": notNil,
"reserveImport": CurrentImports.Reserve,
"lookupImport": CurrentImports.Lookup,
"go": ToGo,
"goPrivate": ToGoPrivate,
"goModelName": ToGoModelName,
"goPrivateModelName": ToGoPrivateModelName,
"add": func(a, b int) int {
return a + b
},
@@ -285,25 +301,154 @@ func Call(p *types.Func) string {
return pkg + p.Name()
}
func resetModelNames() {
modelNamesMu.Lock()
defer modelNamesMu.Unlock()
modelNames = make(map[string]string, 0)
}
func buildGoModelNameKey(parts []string) string {
const sep = ":"
return strings.Join(parts, sep)
}
func goModelName(primaryToGoFunc func(string) string, parts []string) string {
modelNamesMu.Lock()
defer modelNamesMu.Unlock()
var (
goNameKey string
partLen int
nameExists = func(n string) bool {
for _, v := range modelNames {
if n == v {
return true
}
}
return false
}
applyToGoFunc = func(parts []string) string {
var out string
switch len(parts) {
case 0:
return ""
case 1:
return primaryToGoFunc(parts[0])
default:
out = primaryToGoFunc(parts[0])
}
for _, p := range parts[1:] {
out = fmt.Sprintf("%s%s", out, ToGo(p))
}
return out
}
applyValidGoName = func(parts []string) string {
var out string
for _, p := range parts {
out = fmt.Sprintf("%s%s", out, replaceInvalidCharacters(p))
}
return out
}
)
// build key for this entity
goNameKey = buildGoModelNameKey(parts)
// determine if we've seen this entity before, and reuse if so
if goName, ok := modelNames[goNameKey]; ok {
return goName
}
// attempt first pass
if goName := applyToGoFunc(parts); !nameExists(goName) {
modelNames[goNameKey] = goName
return goName
}
// determine number of parts
partLen = len(parts)
// if there is only 1 part, append incrementing number until no conflict
if partLen == 1 {
base := applyToGoFunc(parts)
for i := 0; ; i++ {
tmp := fmt.Sprintf("%s%d", base, i)
if !nameExists(tmp) {
modelNames[goNameKey] = tmp
return tmp
}
}
}
// best effort "pretty" name
for i := partLen - 1; i >= 1; i-- {
tmp := fmt.Sprintf("%s%s", applyToGoFunc(parts[0:i]), applyValidGoName(parts[i:]))
if !nameExists(tmp) {
modelNames[goNameKey] = tmp
return tmp
}
}
// finally, fallback to just adding an incrementing number
base := applyToGoFunc(parts)
for i := 0; ; i++ {
tmp := fmt.Sprintf("%s%d", base, i)
if !nameExists(tmp) {
modelNames[goNameKey] = tmp
return tmp
}
}
}
func ToGoModelName(parts ...string) string {
return goModelName(ToGo, parts)
}
func ToGoPrivateModelName(parts ...string) string {
return goModelName(ToGoPrivate, parts)
}
func replaceInvalidCharacters(in string) string {
return goNameRe.ReplaceAllLiteralString(in, "_")
}
func wordWalkerFunc(private bool, nameRunes *[]rune) func(*wordInfo) {
return func(info *wordInfo) {
word := info.Word
switch {
case private && info.WordOffset == 0:
if strings.ToUpper(word) == word || strings.ToLower(word) == word {
// ID → id, CAMEL → camel
word = strings.ToLower(info.Word)
} else {
// ITicket → iTicket
word = LcFirst(info.Word)
}
case info.MatchCommonInitial:
word = strings.ToUpper(word)
case !info.HasCommonInitial && (strings.ToUpper(word) == word || strings.ToLower(word) == word):
// FOO or foo → Foo
// FOo → FOo
word = UcFirst(strings.ToLower(word))
}
*nameRunes = append(*nameRunes, []rune(word)...)
}
}
func ToGo(name string) string {
if name == "_" {
return "_"
}
runes := make([]rune, 0, len(name))
wordWalker(name, func(info *wordInfo) {
word := info.Word
if info.MatchCommonInitial {
word = strings.ToUpper(word)
} else if !info.HasCommonInitial {
if strings.ToUpper(word) == word || strings.ToLower(word) == word {
// FOO or foo → Foo
// FOo → FOo
word = UcFirst(strings.ToLower(word))
}
}
runes = append(runes, []rune(word)...)
})
wordWalker(name, wordWalkerFunc(false, &runes))
return string(runes)
}
@@ -314,31 +459,13 @@ func ToGoPrivate(name string) string {
}
runes := make([]rune, 0, len(name))
first := true
wordWalker(name, func(info *wordInfo) {
word := info.Word
switch {
case first:
if strings.ToUpper(word) == word || strings.ToLower(word) == word {
// ID → id, CAMEL → camel
word = strings.ToLower(info.Word)
} else {
// ITicket → iTicket
word = LcFirst(info.Word)
}
first = false
case info.MatchCommonInitial:
word = strings.ToUpper(word)
case !info.HasCommonInitial:
word = UcFirst(strings.ToLower(word))
}
runes = append(runes, []rune(word)...)
})
wordWalker(name, wordWalkerFunc(true, &runes))
return sanitizeKeywords(string(runes))
}
type wordInfo struct {
WordOffset int
Word string
MatchCommonInitial bool
HasCommonInitial bool
@@ -348,7 +475,7 @@ type wordInfo struct {
// https://github.com/golang/lint/blob/06c8688daad7faa9da5a0c2f163a3d14aac986ca/lint.go#L679
func wordWalker(str string, f func(*wordInfo)) {
runes := []rune(strings.TrimFunc(str, isDelimiter))
w, i := 0, 0 // index of start of word, scan
w, i, wo := 0, 0, 0 // index of start of word, scan, word offset
hasCommonInitial := false
for i+1 <= len(runes) {
eow := false // whether we hit the end of a word
@@ -396,12 +523,14 @@ func wordWalker(str string, f func(*wordInfo)) {
}
f(&wordInfo{
WordOffset: wo,
Word: word,
MatchCommonInitial: matchCommonInitial,
HasCommonInitial: hasCommonInitial,
})
hasCommonInitial = false
w = i
wo++
}
}
@@ -576,7 +705,7 @@ func resolveName(name string, skip int) string {
func render(filename string, tpldata interface{}) (*bytes.Buffer, error) {
t := template.New("").Funcs(Funcs())
b, err := ioutil.ReadFile(filename)
b, err := os.ReadFile(filename)
if err != nil {
return nil, err
}
@@ -602,7 +731,7 @@ func write(filename string, b []byte, packages *code.Packages) error {
formatted = b
}
err = ioutil.WriteFile(filename, formatted, 0o644)
err = os.WriteFile(filename, formatted, 0o644)
if err != nil {
return fmt.Errorf("failed to write %s: %w", filename, err)
}

View File

@@ -0,0 +1 @@
this is my test package

View File

@@ -0,0 +1 @@
this will not be included

View File

@@ -56,6 +56,10 @@
return *res, graphql.ErrorOnPath(ctx, err)
{{- else if and (not $type.IsTargetNilable) $type.IsNilable }}
return &res, graphql.ErrorOnPath(ctx, err)
{{- else if or $type.IsUnusualBasic $type.IsUnderlyingUnusualBasic }}
return {{ $type.GO | ref }}(res), graphql.ErrorOnPath(ctx, err)
{{- else if and $type.IsNamed $type.Definition.BuiltIn (not $type.IsScalarID) }}
return {{ $type.GO | ref }}(res), graphql.ErrorOnPath(ctx, err)
{{- else}}
return res, graphql.ErrorOnPath(ctx, err)
{{- end }}
@@ -75,9 +79,11 @@
return res, graphql.ErrorOnPath(ctx, err)
{{- else }}
res, err := ec.unmarshalInput{{ $type.GQL.Name }}(ctx, v)
{{- if $type.IsNilable }}
{{- if and $type.IsNilable (not $type.PointersInUmarshalInput) }}
return &res, graphql.ErrorOnPath(ctx, err)
{{- else}}
{{- else if and (not $type.IsNilable) $type.PointersInUmarshalInput }}
return *res, graphql.ErrorOnPath(ctx, err)
{{- else }}
return res, graphql.ErrorOnPath(ctx, err)
{{- end }}
{{- end }}
@@ -151,7 +157,7 @@
if v == nil {
{{- if $type.GQL.NonNull }}
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "must not be null")
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
}
{{- end }}
return graphql.Null
@@ -170,11 +176,17 @@
{{- else if and (not $type.IsTargetNilable) $type.IsNilable }}
{{- $v = "*v" }}
{{- end }}
res := {{ $type.Marshaler | call }}({{- if $type.CastType }}{{ $type.CastType | ref }}({{ $v }}){{else}}{{ $v }}{{- end }})
{{- if or $type.IsUnusualBasic $type.IsUnderlyingUnusualBasic }}
res := {{ $type.Marshaler | call }}({{ $type.Target | ref }}({{ $v }}))
{{- else if and $type.IsNamed $type.Definition.BuiltIn (not $type.IsScalarID) }}
res := {{ $type.Marshaler | call }}({{- if and $type.GO.Underlying $type.IsUnderlyingBasic }}{{ $type.GO.Underlying | ref }}({{ $v }}){{else}}{{ $v }}{{- end }})
{{- else }}
res := {{ $type.Marshaler | call }}({{- if $type.CastType }}{{ $type.CastType | ref }}({{ $v }}){{else}}{{ $v }}{{- end }})
{{- end }}
{{- if $type.GQL.NonNull }}
if res == graphql.Null {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "must not be null")
ec.Errorf(ctx, "the requested element is null which the schema does not allow")
}
}
{{- end }}

View File

@@ -41,6 +41,7 @@ func findGoInterface(def types.Type) (*types.Interface, error) {
func equalFieldName(source, target string) bool {
source = strings.ReplaceAll(source, "_", "")
source = strings.ReplaceAll(source, ",omitempty", "")
target = strings.ReplaceAll(target, "_", "")
return strings.EqualFold(source, target)
}