Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into 1645-context-marshal
Browse files Browse the repository at this point in the history
  • Loading branch information
duckbrain committed Oct 14, 2021
2 parents 7b8b47a + 7435403 commit 6004ffc
Show file tree
Hide file tree
Showing 75 changed files with 7,680 additions and 1,173 deletions.
7 changes: 5 additions & 2 deletions api/generate.go
Expand Up @@ -77,8 +77,11 @@ func Generate(cfg *config.Config, option ...Option) error {
if err = codegen.GenerateCode(data); err != nil {
return fmt.Errorf("generating core failed: %w", err)
}
if err = cfg.Packages.ModTidy(); err != nil {
return fmt.Errorf("tidy failed: %w", err)

if !cfg.SkipModTidy {
if err = cfg.Packages.ModTidy(); err != nil {
return fmt.Errorf("tidy failed: %w", err)
}
}

for _, p := range plugins {
Expand Down
20 changes: 20 additions & 0 deletions api/option.go
Expand Up @@ -18,3 +18,23 @@ func AddPlugin(p plugin.Plugin) Option {
*plugins = append(*plugins, p)
}
}

// ReplacePlugin replaces any existing plugin with a matching plugin name
func ReplacePlugin(p plugin.Plugin) Option {
return func(cfg *config.Config, plugins *[]plugin.Plugin) {
if plugins != nil {
found := false
ps := *plugins
for i, o := range ps {
if p.Name() == o.Name() {
ps[i] = p
found = true
}
}
if !found {
ps = append(ps, p)
}
*plugins = ps
}
}
}
58 changes: 58 additions & 0 deletions api/option_test.go
@@ -0,0 +1,58 @@
package api

import (
"testing"

"github.com/99designs/gqlgen/codegen/config"
"github.com/99designs/gqlgen/plugin"
"github.com/99designs/gqlgen/plugin/federation"
"github.com/99designs/gqlgen/plugin/modelgen"
"github.com/99designs/gqlgen/plugin/resolvergen"
"github.com/stretchr/testify/require"
)

type testPlugin struct {
}

// Name returns the plugin name
func (t *testPlugin) Name() string {
return "modelgen"
}

// MutateConfig mutates the configuration
func (t *testPlugin) MutateConfig(_ *config.Config) error {
return nil
}

func TestReplacePlugin(t *testing.T) {

t.Run("replace plugin if exists", func(t *testing.T) {
pg := []plugin.Plugin{
federation.New(),
modelgen.New(),
resolvergen.New(),
}

expectedPlugin := &testPlugin{}
ReplacePlugin(expectedPlugin)(config.DefaultConfig(), &pg)

require.EqualValues(t, federation.New(), pg[0])
require.EqualValues(t, expectedPlugin, pg[1])
require.EqualValues(t, resolvergen.New(), pg[2])
})

t.Run("add plugin if doesn't exist", func(t *testing.T) {
pg := []plugin.Plugin{
federation.New(),
resolvergen.New(),
}

expectedPlugin := &testPlugin{}
ReplacePlugin(expectedPlugin)(config.DefaultConfig(), &pg)

require.EqualValues(t, federation.New(), pg[0])
require.EqualValues(t, resolvergen.New(), pg[1])
require.EqualValues(t, expectedPlugin, pg[2])
})

}
1 change: 1 addition & 0 deletions client/client.go
Expand Up @@ -30,6 +30,7 @@ type (
Query string `json:"query"`
Variables map[string]interface{} `json:"variables,omitempty"`
OperationName string `json:"operationName,omitempty"`
Extensions map[string]interface{} `json:"extensions,omitempty"`
HTTP *http.Request `json:"-"`
}

Expand Down
27 changes: 27 additions & 0 deletions client/client_test.go
Expand Up @@ -101,3 +101,30 @@ func TestAddCookie(t *testing.T) {
client.AddCookie(&http.Cookie{Name: "foo", Value: "value"}),
)
}

func TestAddExtensions(t *testing.T) {
h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
b, err := ioutil.ReadAll(r.Body)
if err != nil {
panic(err)
}
require.Equal(t, `{"query":"user(id:1){name}","extensions":{"persistedQuery":{"sha256Hash":"ceec2897e2da519612279e63f24658c3e91194cbb2974744fa9007a7e1e9f9e7","version":1}}}`, string(b))
err = json.NewEncoder(w).Encode(map[string]interface{}{
"data": map[string]interface{}{
"Name": "Bob",
},
})
if err != nil {
panic(err)
}
})

c := client.New(h)

var resp struct {
Name string
}
c.MustPost("user(id:1){name}", &resp,
client.Extensions(map[string]interface{}{"persistedQuery": map[string]interface{}{"version": 1, "sha256Hash": "ceec2897e2da519612279e63f24658c3e91194cbb2974744fa9007a7e1e9f9e7"}}),
)
}
7 changes: 7 additions & 0 deletions client/options.go
Expand Up @@ -20,6 +20,13 @@ func Operation(name string) Option {
}
}

// Extensions sets the extensions to be sent with the outgoing request
func Extensions(extensions map[string]interface{}) Option {
return func(bd *Request) {
bd.Extensions = extensions
}
}

// Path sets the url that this request will be made against, useful if you are mounting your entire router
// and need to specify the url to the graphql endpoint.
func Path(url string) Option {
Expand Down
10 changes: 10 additions & 0 deletions codegen/config/binder.go
Expand Up @@ -192,6 +192,16 @@ func (t *TypeReference) IsPtr() bool {
return isPtr
}

// 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)
return isPtr
}
return false
}

func (t *TypeReference) IsNilable() bool {
return IsNilable(t.GO)
}
Expand Down
60 changes: 45 additions & 15 deletions codegen/config/config.go
Expand Up @@ -27,6 +27,7 @@ type Config struct {
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:"-"`
Expand Down Expand Up @@ -203,15 +204,8 @@ func (c *Config) Init() error {
}

c.injectBuiltins()

// prefetch all packages in one big packages.Load call
pkgs := []string{
"github.com/99designs/gqlgen/graphql",
"github.com/99designs/gqlgen/graphql/introspection",
}
pkgs = append(pkgs, c.Models.ReferencedPackages()...)
pkgs = append(pkgs, c.AutoBind...)
c.Packages.LoadAll(pkgs...)
c.Packages.LoadAll(c.packageList()...)

// check everything is valid on the way out
err = c.check()
Expand All @@ -222,6 +216,20 @@ func (c *Config) Init() error {
return nil
}

func (c *Config) packageList() []string {
pkgs := []string{
"github.com/99designs/gqlgen/graphql",
"github.com/99designs/gqlgen/graphql/introspection",
}
pkgs = append(pkgs, c.Models.ReferencedPackages()...)
pkgs = append(pkgs, c.AutoBind...)
return pkgs
}

func (c *Config) ReloadAllPackages() {
c.Packages.ReloadAll(c.packageList()...)
}

func (c *Config) injectTypesFromSchema() error {
c.Directives["goModel"] = DirectiveConfig{
SkipRuntime: true,
Expand All @@ -231,6 +239,10 @@ func (c *Config) injectTypesFromSchema() error {
SkipRuntime: true,
}

c.Directives["extraTag"] = DirectiveConfig{
SkipRuntime: true,
}

for _, schemaType := range c.Schema.Types {
if schemaType == c.Schema.Query || schemaType == c.Schema.Mutation || schemaType == c.Schema.Subscription {
continue
Expand All @@ -253,9 +265,15 @@ func (c *Config) injectTypesFromSchema() error {

if schemaType.Kind == ast.Object || schemaType.Kind == ast.InputObject {
for _, field := range schemaType.Fields {
typeMapField := TypeMapField{
ExtraTag: c.Models[schemaType.Name].Fields[field.Name].ExtraTag,
FieldName: c.Models[schemaType.Name].Fields[field.Name].FieldName,
Resolver: c.Models[schemaType.Name].Fields[field.Name].Resolver,
}
directive := false
if fd := field.Directives.ForName("goField"); fd != nil {
forceResolver := c.Models[schemaType.Name].Fields[field.Name].Resolver
fieldName := c.Models[schemaType.Name].Fields[field.Name].FieldName
forceResolver := typeMapField.Resolver
fieldName := typeMapField.FieldName

if ra := fd.Arguments.ForName("forceResolver"); ra != nil {
if fr, err := ra.Value.Value(nil); err == nil {
Expand All @@ -269,17 +287,28 @@ func (c *Config) injectTypesFromSchema() error {
}
}

typeMapField.FieldName = fieldName
typeMapField.Resolver = forceResolver
directive = true
}

if ex := field.Directives.ForName("extraTag"); ex != nil {
args := []string{}
for _, arg := range ex.Arguments {
args = append(args, arg.Name+`:"`+arg.Value.Raw+`"`)
}
typeMapField.ExtraTag = strings.Join(args, " ")
directive = true
}

if directive {
if c.Models[schemaType.Name].Fields == nil {
c.Models[schemaType.Name] = TypeMapEntry{
Model: c.Models[schemaType.Name].Model,
Fields: map[string]TypeMapField{},
}
}

c.Models[schemaType.Name].Fields[field.Name] = TypeMapField{
FieldName: fieldName,
Resolver: forceResolver,
}
c.Models[schemaType.Name].Fields[field.Name] = typeMapField
}
}
}
Expand All @@ -296,6 +325,7 @@ type TypeMapEntry struct {
type TypeMapField struct {
Resolver bool `yaml:"resolver"`
FieldName string `yaml:"fieldName"`
ExtraTag string `yaml:"extraTag"`
GeneratedMethod string `yaml:"-"`
}

Expand Down
2 changes: 1 addition & 1 deletion codegen/field.go
Expand Up @@ -461,7 +461,7 @@ func (f *Field) GoNameUnexported() string {
}

func (f *Field) ShortInvocation() string {
return fmt.Sprintf("%s().%s(%s)", f.Object.Definition.Name, f.GoFieldName, f.CallArgs())
return fmt.Sprintf("%s().%s(%s)", strings.Title(f.Object.Definition.Name), f.GoFieldName, f.CallArgs())
}

func (f *Field) ArgsFunc() string {
Expand Down
10 changes: 5 additions & 5 deletions codegen/generated!.gotpl
Expand Up @@ -32,7 +32,7 @@ type Config struct {
type ResolverRoot interface {
{{- range $object := .Objects -}}
{{ if $object.HasResolvers -}}
{{$object.Name}}() {{$object.Name}}Resolver
{{ucFirst $object.Name}}() {{ucFirst $object.Name}}Resolver
{{ end }}
{{- end }}
}
Expand All @@ -46,7 +46,7 @@ type DirectiveRoot struct {
type ComplexityRoot struct {
{{ range $object := .Objects }}
{{ if not $object.IsReserved -}}
{{ $object.Name|go }} struct {
{{ ucFirst $object.Name }} struct {
{{ range $_, $fields := $object.UniqueFields }}
{{- $field := index $fields 0 -}}
{{ if not $field.IsReserved -}}
Expand All @@ -60,7 +60,7 @@ type ComplexityRoot struct {

{{ range $object := .Objects -}}
{{ if $object.HasResolvers }}
type {{$object.Name}}Resolver interface {
type {{ucFirst $object.Name}}Resolver interface {
{{ range $field := $object.Fields -}}
{{- if $field.IsResolver }}
{{- $field.GoFieldName}}{{ $field.ShortResolverDeclaration }}
Expand Down Expand Up @@ -92,7 +92,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
{{- $last := eq (add $i 1) $len }}
{{- if not $field.IsReserved }}
{{- if eq $i 0 }}case {{ end }}"{{$object.Name}}.{{$field.Name}}"{{ if not $last }},{{ else }}:
if e.complexity.{{$object.Name|go}}.{{$field.GoFieldName}} == nil {
if e.complexity.{{ucFirst $object.Name}}.{{$field.GoFieldName}} == nil {
break
}
{{ if $field.Args }}
Expand All @@ -101,7 +101,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return 0, false
}
{{ end }}
return e.complexity.{{$object.Name|go}}.{{$field.GoFieldName}}(childComplexity{{if $field.Args}}, {{$field.ComplexityArgs}} {{ end }}), true
return e.complexity.{{ucFirst $object.Name}}.{{$field.GoFieldName}}(childComplexity{{if $field.Args}}, {{$field.ComplexityArgs}} {{ end }}), true
{{ end }}
{{- end }}
{{- end }}
Expand Down
2 changes: 1 addition & 1 deletion codegen/input.gotpl
Expand Up @@ -7,7 +7,7 @@
asMap[k] = v
}
{{ range $field := .Fields}}
{{- if $field.Default}}
{{- if notNil "Default" $field }}
if _, present := asMap[{{$field.Name|quote}}] ; !present {
asMap[{{$field.Name|quote}}] = {{ $field.Default | dump }}
}
Expand Down
2 changes: 1 addition & 1 deletion codegen/object.go
Expand Up @@ -46,7 +46,7 @@ func (b *builder) buildObject(typ *ast.Definition) (*Object, error) {
Stream: typ == b.Schema.Subscription,
Directives: dirs,
ResolverInterface: types.NewNamed(
types.NewTypeName(0, b.Config.Exec.Pkg(), typ.Name+"Resolver", nil),
types.NewTypeName(0, b.Config.Exec.Pkg(), strings.Title(typ.Name)+"Resolver", nil),
nil,
nil,
),
Expand Down

0 comments on commit 6004ffc

Please sign in to comment.