aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/99designs/gqlgen
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/99designs/gqlgen')
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/complexity.go6
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/config/binder.go27
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/config/config.go8
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl33
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/object.gotpl20
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/templates/templates.go77
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/type.gotpl17
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/any.go19
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/context.go4
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/exec.go19
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/introspection/type.go4
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/time.go4
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/upload.go26
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/version.go2
-rw-r--r--vendor/github.com/99designs/gqlgen/handler/graphql.go220
-rw-r--r--vendor/github.com/99designs/gqlgen/handler/mock.go57
-rw-r--r--vendor/github.com/99designs/gqlgen/internal/code/imports.go90
-rw-r--r--vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go33
-rw-r--r--vendor/github.com/99designs/gqlgen/plugin/modelgen/models.gotpl2
19 files changed, 551 insertions, 117 deletions
diff --git a/vendor/github.com/99designs/gqlgen/codegen/complexity.go b/vendor/github.com/99designs/gqlgen/codegen/complexity.go
index 66d21a84..e9c6a20e 100644
--- a/vendor/github.com/99designs/gqlgen/codegen/complexity.go
+++ b/vendor/github.com/99designs/gqlgen/codegen/complexity.go
@@ -1,10 +1,10 @@
package codegen
-func (o *Object) UniqueFields() map[string]*Field {
- m := map[string]*Field{}
+func (o *Object) UniqueFields() map[string][]*Field {
+ m := map[string][]*Field{}
for _, f := range o.Fields {
- m[f.GoFieldName] = f
+ m[f.GoFieldName] = append(m[f.GoFieldName], f)
}
return m
diff --git a/vendor/github.com/99designs/gqlgen/codegen/config/binder.go b/vendor/github.com/99designs/gqlgen/codegen/config/binder.go
index f3956387..cea904ad 100644
--- a/vendor/github.com/99designs/gqlgen/codegen/config/binder.go
+++ b/vendor/github.com/99designs/gqlgen/codegen/config/binder.go
@@ -238,25 +238,6 @@ func (t *TypeReference) IsScalar() bool {
return t.Definition.Kind == ast.Scalar
}
-func (t *TypeReference) HasIsZero() bool {
- it := t.GO
- if ptr, isPtr := it.(*types.Pointer); isPtr {
- it = ptr.Elem()
- }
- namedType, ok := it.(*types.Named)
- if !ok {
- return false
- }
-
- for i := 0; i < namedType.NumMethods(); i++ {
- switch namedType.Method(i).Name() {
- case "IsZero":
- return true
- }
- }
- return false
-}
-
func (t *TypeReference) UniquenessKey() string {
var nullability = "O"
if t.GQL.NonNull {
@@ -368,7 +349,7 @@ func (b *Binder) TypeReference(schemaType *ast.Type, bindTarget types.Type) (ret
} else if hasMethod(obj.Type(), "MarshalGQL") && hasMethod(obj.Type(), "UnmarshalGQL") {
ref.GO = obj.Type()
ref.IsMarshaler = true
- } else if underlying := basicUnderlying(obj.Type()); underlying != nil && underlying.Kind() == types.String {
+ } else if underlying := basicUnderlying(obj.Type()); def.IsLeafType() && underlying != nil && underlying.Kind() == types.String {
// Special case for named types wrapping strings. Used by default enum implementations.
ref.GO = obj.Type()
@@ -402,7 +383,11 @@ func (b *Binder) TypeReference(schemaType *ast.Type, bindTarget types.Type) (ret
func (b *Binder) CopyModifiersFromAst(t *ast.Type, base types.Type) types.Type {
if t.Elem != nil {
- return types.NewSlice(b.CopyModifiersFromAst(t.Elem, base))
+ child := b.CopyModifiersFromAst(t.Elem, base)
+ if _, isStruct := child.Underlying().(*types.Struct); isStruct {
+ child = types.NewPointer(child)
+ }
+ return types.NewSlice(child)
}
var isInterface bool
diff --git a/vendor/github.com/99designs/gqlgen/codegen/config/config.go b/vendor/github.com/99designs/gqlgen/codegen/config/config.go
index 0c72420e..1725adab 100644
--- a/vendor/github.com/99designs/gqlgen/codegen/config/config.go
+++ b/vendor/github.com/99designs/gqlgen/codegen/config/config.go
@@ -136,7 +136,7 @@ func (c *PackageConfig) normalize() error {
// If Package is not set, first attempt to load the package at the output dir. If that fails
// fallback to just the base dir name of the output filename.
if c.Package == "" {
- c.Package = code.NameForPackage(c.ImportPath())
+ c.Package = code.NameForDir(c.Dir())
}
return nil
@@ -363,8 +363,10 @@ func (c *Config) InjectBuiltins(s *ast.Schema) {
// These are additional types that are injected if defined in the schema as scalars.
extraBuiltins := TypeMap{
- "Time": {Model: StringList{"github.com/99designs/gqlgen/graphql.Time"}},
- "Map": {Model: StringList{"github.com/99designs/gqlgen/graphql.Map"}},
+ "Time": {Model: StringList{"github.com/99designs/gqlgen/graphql.Time"}},
+ "Map": {Model: StringList{"github.com/99designs/gqlgen/graphql.Map"}},
+ "Upload": {Model: StringList{"github.com/99designs/gqlgen/graphql.Upload"}},
+ "Any": {Model: StringList{"github.com/99designs/gqlgen/graphql.Any"}},
}
for typeName, entry := range extraBuiltins {
diff --git a/vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl b/vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl
index dce8ce97..5753f1d1 100644
--- a/vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl
+++ b/vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl
@@ -4,6 +4,7 @@
{{ reserveImport "strconv" }}
{{ reserveImport "time" }}
{{ reserveImport "sync" }}
+{{ reserveImport "sync/atomic" }}
{{ reserveImport "errors" }}
{{ reserveImport "bytes" }}
@@ -46,7 +47,8 @@ type ComplexityRoot struct {
{{ range $object := .Objects }}
{{ if not $object.IsReserved -}}
{{ $object.Name|go }} struct {
- {{ range $field := $object.UniqueFields -}}
+ {{ range $_, $fields := $object.UniqueFields }}
+ {{- $field := index $fields 0 -}}
{{ if not $field.IsReserved -}}
{{ $field.GoFieldName }} {{ $field.ComplexitySignature }}
{{ end }}
@@ -84,20 +86,25 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
switch typeName + "." + field {
{{ range $object := .Objects }}
{{ if not $object.IsReserved }}
- {{ range $field := $object.UniqueFields }}
- {{ if not $field.IsReserved }}
- case "{{$object.Name}}.{{$field.GoFieldName}}":
- if e.complexity.{{$object.Name|go}}.{{$field.GoFieldName}} == nil {
- break
- }
- {{ if $field.Args }}
- args, err := ec.{{ $field.ArgsFunc }}(context.TODO(),rawArgs)
- if err != nil {
- return 0, false
+ {{ range $_, $fields := $object.UniqueFields }}
+ {{- $len := len $fields }}
+ {{- range $i, $field := $fields }}
+ {{- $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 {
+ break
}
+ {{ if $field.Args }}
+ args, err := ec.{{ $field.ArgsFunc }}(context.TODO(),rawArgs)
+ if err != nil {
+ return 0, false
+ }
+ {{ end }}
+ return e.complexity.{{$object.Name|go}}.{{$field.GoFieldName}}(childComplexity{{if $field.Args}}, {{$field.ComplexityArgs}} {{ end }}), true
{{ end }}
- return e.complexity.{{$object.Name|go}}.{{$field.GoFieldName}}(childComplexity{{if $field.Args}}, {{$field.ComplexityArgs}} {{end}}), true
- {{ end }}
+ {{- end }}
+ {{- end }}
{{ end }}
{{ end }}
{{ end }}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/object.gotpl b/vendor/github.com/99designs/gqlgen/codegen/object.gotpl
index 19da1b19..98a75740 100644
--- a/vendor/github.com/99designs/gqlgen/codegen/object.gotpl
+++ b/vendor/github.com/99designs/gqlgen/codegen/object.gotpl
@@ -4,7 +4,7 @@ var {{ $object.Name|lcFirst}}Implementors = {{$object.Implementors}}
{{- if .Stream }}
func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.SelectionSet) func() graphql.Marshaler {
- fields := graphql.CollectFields(ctx, sel, {{$object.Name|lcFirst}}Implementors)
+ fields := graphql.CollectFields(ec.RequestContext, sel, {{$object.Name|lcFirst}}Implementors)
ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{
Object: {{$object.Name|quote}},
})
@@ -24,7 +24,7 @@ func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.Selec
}
{{- else }}
func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.SelectionSet{{ if not $object.Root }},obj {{$object.Reference | ref }}{{ end }}) graphql.Marshaler {
- fields := graphql.CollectFields(ctx, sel, {{$object.Name|lcFirst}}Implementors)
+ fields := graphql.CollectFields(ec.RequestContext, sel, {{$object.Name|lcFirst}}Implementors)
{{if $object.Root}}
ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{
Object: {{$object.Name|quote}},
@@ -32,7 +32,7 @@ func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.Selec
{{end}}
out := graphql.NewFieldSet(fields)
- invalid := false
+ var invalids uint32
for i, field := range fields {
switch field.Name {
case "__typename":
@@ -50,7 +50,11 @@ 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 {
- invalid = true
+ {{- if $object.IsConcurrent }}
+ atomic.AddUint32(&invalids, 1)
+ {{- else }}
+ invalids++
+ {{- end }}
}
{{- end }}
return res
@@ -59,7 +63,11 @@ func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.Selec
out.Values[i] = ec._{{$object.Name}}_{{$field.Name}}(ctx, field{{if not $object.Root}}, obj{{end}})
{{- if $field.TypeReference.GQL.NonNull }}
if out.Values[i] == graphql.Null {
- invalid = true
+ {{- if $object.IsConcurrent }}
+ atomic.AddUint32(&invalids, 1)
+ {{- else }}
+ invalids++
+ {{- end }}
}
{{- end }}
{{- end }}
@@ -69,7 +77,7 @@ func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.Selec
}
}
out.Dispatch()
- if invalid { return graphql.Null }
+ if invalids > 0 { return graphql.Null }
return out
}
{{- end }}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/templates/templates.go b/vendor/github.com/99designs/gqlgen/codegen/templates/templates.go
index 4c292732..f2fcb568 100644
--- a/vendor/github.com/99designs/gqlgen/codegen/templates/templates.go
+++ b/vendor/github.com/99designs/gqlgen/codegen/templates/templates.go
@@ -19,18 +19,36 @@ import (
"github.com/pkg/errors"
)
+// CurrentImports keeps track of all the import declarations that are needed during the execution of a plugin.
// this is done with a global because subtemplates currently get called in functions. Lets aim to remove this eventually.
var CurrentImports *Imports
+// Options specify various parameters to rendering a template.
type Options struct {
- PackageName string
+ // PackageName is a helper that specifies the package header declaration.
+ // In other words, when you write the template you don't need to specify `package X`
+ // at the top of the file. By providing PackageName in the Options, the Render
+ // function will do that for you.
+ PackageName string
+ // Template is a string of the entire template that
+ // will be parsed and rendered. If it's empty,
+ // the plugin processor will look for .gotpl files
+ // in the same directory of where you wrote the plugin.
+ Template string
+ // Filename is the name of the file that will be
+ // written to the system disk once the template is rendered.
Filename string
RegionTags bool
GeneratedHeader bool
- Data interface{}
- Funcs template.FuncMap
+ // Data will be passed to the template execution.
+ Data interface{}
+ Funcs template.FuncMap
}
+// 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`
+// files inside the directory where you wrote the plugin.
func Render(cfg Options) error {
if CurrentImports != nil {
panic(fmt.Errorf("recursive or concurrent call to RenderToFile detected"))
@@ -48,31 +66,40 @@ func Render(cfg Options) error {
t := template.New("").Funcs(funcs)
var roots []string
- // load all the templates in the directory
- err := filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error {
+ if cfg.Template != "" {
+ var err error
+ t, err = t.New("template.gotpl").Parse(cfg.Template)
if err != nil {
- return err
- }
- name := filepath.ToSlash(strings.TrimPrefix(path, rootDir+string(os.PathSeparator)))
- if !strings.HasSuffix(info.Name(), ".gotpl") {
- return nil
- }
- b, err := ioutil.ReadFile(path)
- if err != nil {
- return err
+ return errors.Wrap(err, "error with provided template")
}
+ 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
+ }
+ b, err := ioutil.ReadFile(path)
+ if err != nil {
+ return err
+ }
- t, err = t.New(name).Parse(string(b))
- if err != nil {
- return errors.Wrap(err, cfg.Filename)
- }
+ t, err = t.New(name).Parse(string(b))
+ if err != nil {
+ return errors.Wrap(err, cfg.Filename)
+ }
- roots = append(roots, name)
+ roots = append(roots, name)
- return nil
- })
- if err != nil {
- return errors.Wrap(err, "locating templates")
+ return nil
+ })
+ if err != nil {
+ return errors.Wrap(err, "locating templates")
+ }
}
// then execute all the important looking ones in order, adding them to the same file
@@ -91,7 +118,7 @@ func Render(cfg Options) error {
if cfg.RegionTags {
buf.WriteString("\n// region " + center(70, "*", " "+root+" ") + "\n")
}
- err = t.Lookup(root).Execute(&buf, cfg.Data)
+ err := t.Lookup(root).Execute(&buf, cfg.Data)
if err != nil {
return errors.Wrap(err, root)
}
@@ -110,7 +137,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
}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/type.gotpl b/vendor/github.com/99designs/gqlgen/codegen/type.gotpl
index f727baac..cb2782c3 100644
--- a/vendor/github.com/99designs/gqlgen/codegen/type.gotpl
+++ b/vendor/github.com/99designs/gqlgen/codegen/type.gotpl
@@ -56,15 +56,6 @@
{{- end }}
return graphql.Null
}
- {{- else if $type.HasIsZero }}
- if v.IsZero() {
- {{- if $type.GQL.NonNull }}
- if !ec.HasError(graphql.GetResolverContext(ctx)) {
- ec.Errorf(ctx, "must not be null")
- }
- {{- end }}
- return graphql.Null
- }
{{- end }}
{{- if $type.IsSlice }}
@@ -119,6 +110,14 @@
{{- else if $type.Marshaler }}
{{- if $type.IsPtr }}
return ec.{{ $type.Elem.MarshalFunc }}(ctx, sel, *v)
+ {{- else if $type.GQL.NonNull }}
+ res := {{ $type.Marshaler | call }}({{- if $type.CastType }}{{ $type.CastType | ref }}(v){{else}}v{{- end }})
+ if res == graphql.Null {
+ if !ec.HasError(graphql.GetResolverContext(ctx)) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ }
+ return res
{{- else }}
return {{ $type.Marshaler | call }}({{- if $type.CastType }}{{ $type.CastType | ref }}(v){{else}}v{{- end }})
{{- end }}
diff --git a/vendor/github.com/99designs/gqlgen/graphql/any.go b/vendor/github.com/99designs/gqlgen/graphql/any.go
new file mode 100644
index 00000000..6ea8bf2e
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/graphql/any.go
@@ -0,0 +1,19 @@
+package graphql
+
+import (
+ "encoding/json"
+ "io"
+)
+
+func MarshalAny(v interface{}) Marshaler {
+ return WriterFunc(func(w io.Writer) {
+ err := json.NewEncoder(w).Encode(v)
+ if err != nil {
+ panic(err)
+ }
+ })
+}
+
+func UnmarshalAny(v interface{}) (interface{}, error) {
+ return v, nil
+}
diff --git a/vendor/github.com/99designs/gqlgen/graphql/context.go b/vendor/github.com/99designs/gqlgen/graphql/context.go
index 58d3c741..356f5175 100644
--- a/vendor/github.com/99designs/gqlgen/graphql/context.go
+++ b/vendor/github.com/99designs/gqlgen/graphql/context.go
@@ -132,14 +132,14 @@ func WithResolverContext(ctx context.Context, rc *ResolverContext) context.Conte
// This is just a convenient wrapper method for CollectFields
func CollectFieldsCtx(ctx context.Context, satisfies []string) []CollectedField {
resctx := GetResolverContext(ctx)
- return CollectFields(ctx, resctx.Field.Selections, satisfies)
+ return CollectFields(GetRequestContext(ctx), resctx.Field.Selections, satisfies)
}
// CollectAllFields returns a slice of all GraphQL field names that were selected for the current resolver context.
// The slice will contain the unique set of all field names requested regardless of fragment type conditions.
func CollectAllFields(ctx context.Context) []string {
resctx := GetResolverContext(ctx)
- collected := CollectFields(ctx, resctx.Field.Selections, nil)
+ collected := CollectFields(GetRequestContext(ctx), resctx.Field.Selections, nil)
uniq := make([]string, 0, len(collected))
Next:
for _, f := range collected {
diff --git a/vendor/github.com/99designs/gqlgen/graphql/exec.go b/vendor/github.com/99designs/gqlgen/graphql/exec.go
index 17c57bf6..3e00a4d5 100644
--- a/vendor/github.com/99designs/gqlgen/graphql/exec.go
+++ b/vendor/github.com/99designs/gqlgen/graphql/exec.go
@@ -19,12 +19,12 @@ type ExecutableSchema interface {
// CollectFields returns the set of fields from an ast.SelectionSet where all collected fields satisfy at least one of the GraphQL types
// passed through satisfies. Providing an empty or nil slice for satisfies will return collect all fields regardless of fragment
// type conditions.
-func CollectFields(ctx context.Context, selSet ast.SelectionSet, satisfies []string) []CollectedField {
- return collectFields(GetRequestContext(ctx), selSet, satisfies, map[string]bool{})
+func CollectFields(reqCtx *RequestContext, selSet ast.SelectionSet, satisfies []string) []CollectedField {
+ return collectFields(reqCtx, selSet, satisfies, map[string]bool{})
}
func collectFields(reqCtx *RequestContext, selSet ast.SelectionSet, satisfies []string, visited map[string]bool) []CollectedField {
- var groupedFields []CollectedField
+ groupedFields := make([]CollectedField, 0, len(selSet))
for _, sel := range selSet {
switch sel := sel.(type) {
@@ -32,7 +32,7 @@ func collectFields(reqCtx *RequestContext, selSet ast.SelectionSet, satisfies []
if !shouldIncludeNode(sel.Directives, reqCtx.Variables) {
continue
}
- f := getOrCreateField(&groupedFields, sel.Alias, func() CollectedField {
+ f := getOrCreateAndAppendField(&groupedFields, sel.Alias, func() CollectedField {
return CollectedField{Field: sel}
})
@@ -45,7 +45,7 @@ func collectFields(reqCtx *RequestContext, selSet ast.SelectionSet, satisfies []
continue
}
for _, childField := range collectFields(reqCtx, sel.SelectionSet, satisfies, visited) {
- f := getOrCreateField(&groupedFields, childField.Name, func() CollectedField { return childField })
+ f := getOrCreateAndAppendField(&groupedFields, childField.Name, func() CollectedField { return childField })
f.Selections = append(f.Selections, childField.Selections...)
}
@@ -70,10 +70,9 @@ func collectFields(reqCtx *RequestContext, selSet ast.SelectionSet, satisfies []
}
for _, childField := range collectFields(reqCtx, fragment.SelectionSet, satisfies, visited) {
- f := getOrCreateField(&groupedFields, childField.Name, func() CollectedField { return childField })
+ f := getOrCreateAndAppendField(&groupedFields, childField.Name, func() CollectedField { return childField })
f.Selections = append(f.Selections, childField.Selections...)
}
-
default:
panic(fmt.Errorf("unsupported %T", sel))
}
@@ -97,7 +96,7 @@ func instanceOf(val string, satisfies []string) bool {
return false
}
-func getOrCreateField(c *[]CollectedField, name string, creator func() CollectedField) *CollectedField {
+func getOrCreateAndAppendField(c *[]CollectedField, name string, creator func() CollectedField) *CollectedField {
for i, cf := range *c {
if cf.Alias == name {
return &(*c)[i]
@@ -111,6 +110,10 @@ func getOrCreateField(c *[]CollectedField, name string, creator func() Collected
}
func shouldIncludeNode(directives ast.DirectiveList, variables map[string]interface{}) bool {
+ if len(directives) == 0 {
+ return true
+ }
+
skip, include := false, true
if d := directives.ForName("skip"); d != nil {
diff --git a/vendor/github.com/99designs/gqlgen/graphql/introspection/type.go b/vendor/github.com/99designs/gqlgen/graphql/introspection/type.go
index f1228edf..9aceebdc 100644
--- a/vendor/github.com/99designs/gqlgen/graphql/introspection/type.go
+++ b/vendor/github.com/99designs/gqlgen/graphql/introspection/type.go
@@ -70,6 +70,10 @@ func (t *Type) Fields(includeDeprecated bool) []Field {
continue
}
+ if !includeDeprecated && f.Directives.ForName("deprecated") != nil {
+ continue
+ }
+
var args []InputValue
for _, arg := range f.Arguments {
args = append(args, InputValue{
diff --git a/vendor/github.com/99designs/gqlgen/graphql/time.go b/vendor/github.com/99designs/gqlgen/graphql/time.go
index 4f448560..9945f3fb 100644
--- a/vendor/github.com/99designs/gqlgen/graphql/time.go
+++ b/vendor/github.com/99designs/gqlgen/graphql/time.go
@@ -8,6 +8,10 @@ import (
)
func MarshalTime(t time.Time) Marshaler {
+ if t.IsZero() {
+ return Null
+ }
+
return WriterFunc(func(w io.Writer) {
io.WriteString(w, strconv.Quote(t.Format(time.RFC3339)))
})
diff --git a/vendor/github.com/99designs/gqlgen/graphql/upload.go b/vendor/github.com/99designs/gqlgen/graphql/upload.go
new file mode 100644
index 00000000..22d61031
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/graphql/upload.go
@@ -0,0 +1,26 @@
+package graphql
+
+import (
+ "fmt"
+ "io"
+)
+
+type Upload struct {
+ File io.Reader
+ Filename string
+ Size int64
+}
+
+func MarshalUpload(f Upload) Marshaler {
+ return WriterFunc(func(w io.Writer) {
+ io.Copy(w, f.File)
+ })
+}
+
+func UnmarshalUpload(v interface{}) (Upload, error) {
+ upload, ok := v.(Upload)
+ if !ok {
+ return Upload{}, fmt.Errorf("%T is not an Upload", v)
+ }
+ return upload, nil
+}
diff --git a/vendor/github.com/99designs/gqlgen/graphql/version.go b/vendor/github.com/99designs/gqlgen/graphql/version.go
index 88014abf..11dc6b01 100644
--- a/vendor/github.com/99designs/gqlgen/graphql/version.go
+++ b/vendor/github.com/99designs/gqlgen/graphql/version.go
@@ -1,3 +1,3 @@
package graphql
-const Version = "v0.8.3"
+const Version = "v0.9.0"
diff --git a/vendor/github.com/99designs/gqlgen/handler/graphql.go b/vendor/github.com/99designs/gqlgen/handler/graphql.go
index 92a0471c..a2254222 100644
--- a/vendor/github.com/99designs/gqlgen/handler/graphql.go
+++ b/vendor/github.com/99designs/gqlgen/handler/graphql.go
@@ -3,16 +3,21 @@ package handler
import (
"context"
"encoding/json"
+ "errors"
"fmt"
"io"
+ "io/ioutil"
+ "mime"
"net/http"
+ "os"
+ "strconv"
"strings"
"time"
"github.com/99designs/gqlgen/complexity"
"github.com/99designs/gqlgen/graphql"
"github.com/gorilla/websocket"
- "github.com/hashicorp/golang-lru"
+ lru "github.com/hashicorp/golang-lru"
"github.com/vektah/gqlparser/ast"
"github.com/vektah/gqlparser/gqlerror"
"github.com/vektah/gqlparser/parser"
@@ -37,6 +42,8 @@ type Config struct {
complexityLimitFunc graphql.ComplexityLimitFunc
disableIntrospection bool
connectionKeepAlivePingInterval time.Duration
+ uploadMaxMemory int64
+ uploadMaxSize int64
}
func (c *Config) newRequestContext(es graphql.ExecutableSchema, doc *ast.QueryDocument, op *ast.OperationDefinition, query string, variables map[string]interface{}) *graphql.RequestContext {
@@ -251,6 +258,23 @@ func CacheSize(size int) Option {
}
}
+// UploadMaxSize sets the maximum number of bytes used to parse a request body
+// as multipart/form-data.
+func UploadMaxSize(size int64) Option {
+ return func(cfg *Config) {
+ cfg.uploadMaxSize = size
+ }
+}
+
+// UploadMaxMemory sets the maximum number of bytes used to parse a request body
+// as multipart/form-data in memory, with the remainder stored on disk in
+// temporary files.
+func UploadMaxMemory(size int64) Option {
+ return func(cfg *Config) {
+ cfg.uploadMaxMemory = size
+ }
+}
+
// WebsocketKeepAliveDuration allows you to reconfigure the keepalive behavior.
// By default, keepalive is enabled with a DefaultConnectionKeepAlivePingInterval
// duration. Set handler.connectionKeepAlivePingInterval = 0 to disable keepalive
@@ -264,9 +288,20 @@ func WebsocketKeepAliveDuration(duration time.Duration) Option {
const DefaultCacheSize = 1000
const DefaultConnectionKeepAlivePingInterval = 25 * time.Second
+// DefaultUploadMaxMemory is the maximum number of bytes used to parse a request body
+// as multipart/form-data in memory, with the remainder stored on disk in
+// temporary files.
+const DefaultUploadMaxMemory = 32 << 20
+
+// DefaultUploadMaxSize is maximum number of bytes used to parse a request body
+// as multipart/form-data.
+const DefaultUploadMaxSize = 32 << 20
+
func GraphQL(exec graphql.ExecutableSchema, options ...Option) http.HandlerFunc {
cfg := &Config{
cacheSize: DefaultCacheSize,
+ uploadMaxMemory: DefaultUploadMaxMemory,
+ uploadMaxSize: DefaultUploadMaxSize,
connectionKeepAlivePingInterval: DefaultConnectionKeepAlivePingInterval,
upgrader: websocket.Upgrader{
ReadBufferSize: 1024,
@@ -335,8 +370,36 @@ func (gh *graphqlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
}
case http.MethodPost:
- if err := jsonDecode(r.Body, &reqParams); err != nil {
- sendErrorf(w, http.StatusBadRequest, "json body could not be decoded: "+err.Error())
+ mediaType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
+ if err != nil {
+ sendErrorf(w, http.StatusBadRequest, "error parsing request Content-Type")
+ return
+ }
+
+ switch mediaType {
+ case "application/json":
+ if err := jsonDecode(r.Body, &reqParams); err != nil {
+ sendErrorf(w, http.StatusBadRequest, "json body could not be decoded: "+err.Error())
+ return
+ }
+
+ case "multipart/form-data":
+ var closers []io.Closer
+ var tmpFiles []string
+ defer func() {
+ for i := len(closers) - 1; 0 <= i; i-- {
+ _ = closers[i].Close()
+ }
+ for _, tmpFile := range tmpFiles {
+ _ = os.Remove(tmpFile)
+ }
+ }()
+ if err := processMultipart(w, r, &reqParams, &closers, &tmpFiles, gh.cfg.uploadMaxSize, gh.cfg.uploadMaxMemory); err != nil {
+ sendErrorf(w, http.StatusBadRequest, "multipart body could not be decoded: "+err.Error())
+ return
+ }
+ default:
+ sendErrorf(w, http.StatusBadRequest, "unsupported Content-Type: "+mediaType)
return
}
default:
@@ -493,3 +556,154 @@ func sendError(w http.ResponseWriter, code int, errors ...*gqlerror.Error) {
func sendErrorf(w http.ResponseWriter, code int, format string, args ...interface{}) {
sendError(w, code, &gqlerror.Error{Message: fmt.Sprintf(format, args...)})
}
+
+type bytesReader struct {
+ s *[]byte
+ i int64 // current reading index
+ prevRune int // index of previous rune; or < 0
+}
+
+func (r *bytesReader) Read(b []byte) (n int, err error) {
+ if r.s == nil {
+ return 0, errors.New("byte slice pointer is nil")
+ }
+ if r.i >= int64(len(*r.s)) {
+ return 0, io.EOF
+ }
+ r.prevRune = -1
+ n = copy(b, (*r.s)[r.i:])
+ r.i += int64(n)
+ return
+}
+
+func processMultipart(w http.ResponseWriter, r *http.Request, request *params, closers *[]io.Closer, tmpFiles *[]string, uploadMaxSize, uploadMaxMemory int64) error {
+ var err error
+ if r.ContentLength > uploadMaxSize {
+ return errors.New("failed to parse multipart form, request body too large")
+ }
+ r.Body = http.MaxBytesReader(w, r.Body, uploadMaxSize)
+ if err = r.ParseMultipartForm(uploadMaxMemory); err != nil {
+ if strings.Contains(err.Error(), "request body too large") {
+ return errors.New("failed to parse multipart form, request body too large")
+ }
+ return errors.New("failed to parse multipart form")
+ }
+ *closers = append(*closers, r.Body)
+
+ if err = jsonDecode(strings.NewReader(r.Form.Get("operations")), &request); err != nil {
+ return errors.New("operations form field could not be decoded")
+ }
+
+ var uploadsMap = map[string][]string{}
+ if err = json.Unmarshal([]byte(r.Form.Get("map")), &uploadsMap); err != nil {
+ return errors.New("map form field could not be decoded")
+ }
+
+ var upload graphql.Upload
+ for key, paths := range uploadsMap {
+ if len(paths) == 0 {
+ return fmt.Errorf("invalid empty operations paths list for key %s", key)
+ }
+ file, header, err := r.FormFile(key)
+ if err != nil {
+ return fmt.Errorf("failed to get key %s from form", key)
+ }
+ *closers = append(*closers, file)
+
+ if len(paths) == 1 {
+ upload = graphql.Upload{
+ File: file,
+ Size: header.Size,
+ Filename: header.Filename,
+ }
+ err = addUploadToOperations(request, upload, key, paths[0])
+ if err != nil {
+ return err
+ }
+ } else {
+ if r.ContentLength < uploadMaxMemory {
+ fileBytes, err := ioutil.ReadAll(file)
+ if err != nil {
+ return fmt.Errorf("failed to read file for key %s", key)
+ }
+ for _, path := range paths {
+ upload = graphql.Upload{
+ File: &bytesReader{s: &fileBytes, i: 0, prevRune: -1},
+ Size: header.Size,
+ Filename: header.Filename,
+ }
+ err = addUploadToOperations(request, upload, key, path)
+ if err != nil {
+ return err
+ }
+ }
+ } else {
+ tmpFile, err := ioutil.TempFile(os.TempDir(), "gqlgen-")
+ if err != nil {
+ return fmt.Errorf("failed to create temp file for key %s", key)
+ }
+ tmpName := tmpFile.Name()
+ *tmpFiles = append(*tmpFiles, tmpName)
+ _, err = io.Copy(tmpFile, file)
+ if err != nil {
+ if err := tmpFile.Close(); err != nil {
+ return fmt.Errorf("failed to copy to temp file and close temp file for key %s", key)
+ }
+ return fmt.Errorf("failed to copy to temp file for key %s", key)
+ }
+ if err := tmpFile.Close(); err != nil {
+ return fmt.Errorf("failed to close temp file for key %s", key)
+ }
+ for _, path := range paths {
+ pathTmpFile, err := os.Open(tmpName)
+ if err != nil {
+ return fmt.Errorf("failed to open temp file for key %s", key)
+ }
+ *closers = append(*closers, pathTmpFile)
+ upload = graphql.Upload{
+ File: pathTmpFile,
+ Size: header.Size,
+ Filename: header.Filename,
+ }
+ err = addUploadToOperations(request, upload, key, path)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ }
+ }
+ return nil
+}
+
+func addUploadToOperations(request *params, upload graphql.Upload, key, path string) error {
+ if !strings.HasPrefix(path, "variables.") {
+ return fmt.Errorf("invalid operations paths for key %s", key)
+ }
+
+ var ptr interface{} = request.Variables
+ parts := strings.Split(path, ".")
+
+ // skip the first part (variables) because we started there
+ for i, p := range parts[1:] {
+ last := i == len(parts)-2
+ if ptr == nil {
+ return fmt.Errorf("path is missing \"variables.\" prefix, key: %s, path: %s", key, path)
+ }
+ if index, parseNbrErr := strconv.Atoi(p); parseNbrErr == nil {
+ if last {
+ ptr.([]interface{})[index] = upload
+ } else {
+ ptr = ptr.([]interface{})[index]
+ }
+ } else {
+ if last {
+ ptr.(map[string]interface{})[p] = upload
+ } else {
+ ptr = ptr.(map[string]interface{})[p]
+ }
+ }
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/99designs/gqlgen/handler/mock.go b/vendor/github.com/99designs/gqlgen/handler/mock.go
new file mode 100644
index 00000000..3e70cf03
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/handler/mock.go
@@ -0,0 +1,57 @@
+package handler
+
+import (
+ "context"
+
+ "github.com/99designs/gqlgen/graphql"
+ "github.com/vektah/gqlparser"
+ "github.com/vektah/gqlparser/ast"
+)
+
+type executableSchemaMock struct {
+ MutationFunc func(ctx context.Context, op *ast.OperationDefinition) *graphql.Response
+}
+
+var _ graphql.ExecutableSchema = &executableSchemaMock{}
+
+func (e *executableSchemaMock) Schema() *ast.Schema {
+ return gqlparser.MustLoadSchema(&ast.Source{Input: `
+ schema { query: Query, mutation: Mutation }
+ type Query {
+ empty: String!
+ }
+ scalar Upload
+ type File {
+ id: Int!
+ }
+ input UploadFile {
+ id: Int!
+ file: Upload!
+ }
+ type Mutation {
+ singleUpload(file: Upload!): File!
+ singleUploadWithPayload(req: UploadFile!): File!
+ multipleUpload(files: [Upload!]!): [File!]!
+ multipleUploadWithPayload(req: [UploadFile!]!): [File!]!
+ }
+ `})
+}
+
+func (e *executableSchemaMock) Complexity(typeName, field string, childComplexity int, args map[string]interface{}) (int, bool) {
+ return 0, false
+}
+
+func (e *executableSchemaMock) Query(ctx context.Context, op *ast.OperationDefinition) *graphql.Response {
+ return graphql.ErrorResponse(ctx, "queries are not supported")
+}
+
+func (e *executableSchemaMock) Mutation(ctx context.Context, op *ast.OperationDefinition) *graphql.Response {
+ return e.MutationFunc(ctx, op)
+}
+
+func (e *executableSchemaMock) Subscription(ctx context.Context, op *ast.OperationDefinition) func() *graphql.Response {
+ return func() *graphql.Response {
+ <-ctx.Done()
+ return nil
+ }
+}
diff --git a/vendor/github.com/99designs/gqlgen/internal/code/imports.go b/vendor/github.com/99designs/gqlgen/internal/code/imports.go
index 2384e87d..75c30fe1 100644
--- a/vendor/github.com/99designs/gqlgen/internal/code/imports.go
+++ b/vendor/github.com/99designs/gqlgen/internal/code/imports.go
@@ -2,44 +2,96 @@ package code
import (
"errors"
+ "go/build"
+ "go/parser"
+ "go/token"
+ "io/ioutil"
"path/filepath"
+ "regexp"
+ "strings"
"sync"
"golang.org/x/tools/go/packages"
)
-var pathForDirCache = sync.Map{}
+var nameForPackageCache = sync.Map{}
-// ImportPathFromDir takes an *absolute* path and returns a golang import path for the package, and returns an error if it isn't on the gopath
-func ImportPathForDir(dir string) string {
- if v, ok := pathForDirCache.Load(dir); ok {
- return v.(string)
+var gopaths []string
+
+func init() {
+ gopaths = filepath.SplitList(build.Default.GOPATH)
+ for i, p := range gopaths {
+ gopaths[i] = filepath.ToSlash(filepath.Join(p, "src"))
}
+}
- p, _ := packages.Load(&packages.Config{
- Dir: dir,
- }, ".")
+// NameForDir manually looks for package stanzas in files located in the given directory. This can be
+// much faster than having to consult go list, because we already know exactly where to look.
+func NameForDir(dir string) string {
+ dir, err := filepath.Abs(dir)
+ if err != nil {
+ return SanitizePackageName(filepath.Base(dir))
+ }
+ files, err := ioutil.ReadDir(dir)
+ if err != nil {
+ return SanitizePackageName(filepath.Base(dir))
+ }
+ fset := token.NewFileSet()
+ for _, file := range files {
+ if !strings.HasSuffix(strings.ToLower(file.Name()), ".go") {
+ continue
+ }
+
+ filename := filepath.Join(dir, file.Name())
+ if src, err := parser.ParseFile(fset, filename, nil, parser.PackageClauseOnly); err == nil {
+ return src.Name.Name
+ }
+ }
- // If the dir dosent exist yet, keep walking up the directory tree trying to find a match
- if len(p) != 1 {
- parent, err := filepath.Abs(filepath.Join(dir, ".."))
+ return SanitizePackageName(filepath.Base(dir))
+}
+
+// ImportPathForDir takes a path and returns a golang import path for the package
+func ImportPathForDir(dir string) (res string) {
+ dir, err := filepath.Abs(dir)
+ if err != nil {
+ panic(err)
+ }
+ dir = filepath.ToSlash(dir)
+
+ modDir := dir
+ assumedPart := ""
+ for {
+ f, err := ioutil.ReadFile(filepath.Join(modDir, "/", "go.mod"))
+ if err == nil {
+ // found it, stop searching
+ return string(modregex.FindSubmatch(f)[1]) + assumedPart
+ }
+
+ assumedPart = "/" + filepath.Base(modDir) + assumedPart
+ modDir, err = filepath.Abs(filepath.Join(modDir, ".."))
if err != nil {
panic(err)
}
+
// Walked all the way to the root and didnt find anything :'(
- if parent == dir {
- return ""
+ if modDir == "/" {
+ break
}
- return ImportPathForDir(parent) + "/" + filepath.Base(dir)
}
- pathForDirCache.Store(dir, p[0].PkgPath)
+ for _, gopath := range gopaths {
+ if len(gopath) < len(dir) && strings.EqualFold(gopath, dir[0:len(gopath)]) {
+ return dir[len(gopath)+1:]
+ }
+ }
- return p[0].PkgPath
+ return ""
}
-var nameForPackageCache = sync.Map{}
+var modregex = regexp.MustCompile("module (.*)\n")
+// NameForPackage returns the package name for a given import path. This can be really slow.
func NameForPackage(importPath string) string {
if importPath == "" {
panic(errors.New("import path can not be empty"))
@@ -48,7 +100,9 @@ func NameForPackage(importPath string) string {
return v.(string)
}
importPath = QualifyPackagePath(importPath)
- p, _ := packages.Load(nil, importPath)
+ p, _ := packages.Load(&packages.Config{
+ Mode: packages.NeedName,
+ }, importPath)
if len(p) != 1 || p[0].Name == "" {
return SanitizePackageName(filepath.Base(importPath))
diff --git a/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go b/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go
index 508cc14d..bb400f1b 100644
--- a/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go
+++ b/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go
@@ -1,6 +1,7 @@
package modelgen
import (
+ "fmt"
"go/types"
"sort"
@@ -110,6 +111,7 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error {
for _, field := range schemaType.Fields {
var typ types.Type
+ fieldDef := schema.Types[field.Type.Name()]
if cfg.Models.UserDefined(field.Type.Name()) {
pkg, typeName := code.PkgAndType(cfg.Models[field.Type.Name()].Model[0])
@@ -118,7 +120,6 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error {
return err
}
} else {
- fieldDef := schema.Types[field.Type.Name()]
switch fieldDef.Kind {
case ast.Scalar:
// no user defined model, referencing a default scalar
@@ -127,6 +128,7 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error {
nil,
nil,
)
+
case ast.Interface, ast.Union:
// no user defined model, referencing a generated interface type
typ = types.NewNamed(
@@ -134,13 +136,25 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error {
types.NewInterfaceType([]*types.Func{}, []types.Type{}),
nil,
)
- default:
- // no user defined model, must reference another generated model
+
+ case ast.Enum:
+ // no user defined model, must reference a generated enum
typ = types.NewNamed(
types.NewTypeName(0, cfg.Model.Pkg(), templates.ToGo(field.Type.Name()), nil),
nil,
nil,
)
+
+ case ast.Object, ast.InputObject:
+ // no user defined model, must reference a generated struct
+ typ = types.NewNamed(
+ types.NewTypeName(0, cfg.Model.Pkg(), templates.ToGo(field.Type.Name()), nil),
+ types.NewStruct(nil, nil),
+ nil,
+ )
+
+ default:
+ panic(fmt.Errorf("unknown ast type %s", fieldDef.Kind))
}
}
@@ -149,9 +163,15 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error {
name = nameOveride
}
+ typ = binder.CopyModifiersFromAst(field.Type, typ)
+
+ if isStruct(typ) && (fieldDef.Kind == ast.Object || fieldDef.Kind == ast.InputObject) {
+ typ = types.NewPointer(typ)
+ }
+
it.Fields = append(it.Fields, &Field{
Name: name,
- Type: binder.CopyModifiersFromAst(field.Type, typ),
+ Type: typ,
Description: field.Description,
Tag: `json:"` + field.Name + `"`,
})
@@ -205,3 +225,8 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error {
GeneratedHeader: true,
})
}
+
+func isStruct(t types.Type) bool {
+ _, is := t.Underlying().(*types.Struct)
+ return is
+}
diff --git a/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.gotpl b/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.gotpl
index d06cf050..6df200ee 100644
--- a/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.gotpl
+++ b/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.gotpl
@@ -31,7 +31,7 @@
}
{{- range $iface := .Implements }}
- func ({{ $model.Name|go }}) Is{{ $iface }}() {}
+ func ({{ $model.Name|go }}) Is{{ $iface|go }}() {}
{{- end }}
{{- end}}