From e381d5554a1b2b6e3a750206a853e090ec8183ab Mon Sep 17 00:00:00 2001 From: Amine Hilaly Date: Sun, 7 Jul 2019 13:37:03 +0200 Subject: [PATCH] Update gqlgen vendors --- .../99designs/gqlgen/api/generate.go | 2 + .../99designs/gqlgen/codegen/args.go | 16 ++ .../99designs/gqlgen/codegen/args.gotpl | 20 +-- .../99designs/gqlgen/codegen/config/binder.go | 24 ++- .../99designs/gqlgen/codegen/config/config.go | 96 ++++++++++-- .../99designs/gqlgen/codegen/data.go | 7 +- .../99designs/gqlgen/codegen/directive.go | 63 +++++--- .../99designs/gqlgen/codegen/directives.gotpl | 137 ++++++++++++++++++ .../99designs/gqlgen/codegen/field.go | 23 ++- .../99designs/gqlgen/codegen/field.gotpl | 94 ++++++++---- .../99designs/gqlgen/codegen/generated!.gotpl | 59 +++----- .../99designs/gqlgen/codegen/input.gotpl | 24 +-- .../99designs/gqlgen/graphql/version.go | 2 +- .../99designs/gqlgen/handler/graphql.go | 93 ++++++++++++ .../99designs/gqlgen/handler/websocket.go | 10 +- .../gqlgen/plugin/modelgen/models.go | 5 + .../gqlgen/plugin/resolvergen/resolver.go | 1 + .../gqlgen/plugin/resolvergen/resolver.gotpl | 6 +- .../plugin/schemaconfig/schemaconfig.go | 93 ++++++++++++ 19 files changed, 632 insertions(+), 143 deletions(-) create mode 100644 vendor/github.com/99designs/gqlgen/codegen/directives.gotpl create mode 100644 vendor/github.com/99designs/gqlgen/plugin/schemaconfig/schemaconfig.go diff --git a/vendor/github.com/99designs/gqlgen/api/generate.go b/vendor/github.com/99designs/gqlgen/api/generate.go index 3dd083f5..3256bdc3 100644 --- a/vendor/github.com/99designs/gqlgen/api/generate.go +++ b/vendor/github.com/99designs/gqlgen/api/generate.go @@ -8,6 +8,7 @@ import ( "github.com/99designs/gqlgen/plugin" "github.com/99designs/gqlgen/plugin/modelgen" "github.com/99designs/gqlgen/plugin/resolvergen" + "github.com/99designs/gqlgen/plugin/schemaconfig" "github.com/pkg/errors" "golang.org/x/tools/go/packages" ) @@ -17,6 +18,7 @@ func Generate(cfg *config.Config, option ...Option) error { _ = syscall.Unlink(cfg.Model.Filename) plugins := []plugin.Plugin{ + schemaconfig.New(), modelgen.New(), resolvergen.New(), } diff --git a/vendor/github.com/99designs/gqlgen/codegen/args.go b/vendor/github.com/99designs/gqlgen/codegen/args.go index d1498bdd..1d3e51aa 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/args.go +++ b/vendor/github.com/99designs/gqlgen/codegen/args.go @@ -26,6 +26,22 @@ type FieldArgument struct { Value interface{} // value set in Data } +//ImplDirectives get not Builtin and location ARGUMENT_DEFINITION directive +func (f *FieldArgument) ImplDirectives() []*Directive { + d := make([]*Directive, 0) + for i := range f.Directives { + if !f.Directives[i].Builtin && f.Directives[i].IsLocation(ast.LocationArgumentDefinition) { + d = append(d, f.Directives[i]) + } + } + + return d +} + +func (f *FieldArgument) DirectiveObjName() string { + return "rawArgs" +} + func (f *FieldArgument) Stream() bool { return f.Object != nil && f.Object.Stream } diff --git a/vendor/github.com/99designs/gqlgen/codegen/args.gotpl b/vendor/github.com/99designs/gqlgen/codegen/args.gotpl index 4c721218..c76bf0f7 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/args.gotpl +++ b/vendor/github.com/99designs/gqlgen/codegen/args.gotpl @@ -5,22 +5,10 @@ func (ec *executionContext) {{ $name }}(ctx context.Context, rawArgs map[string] {{- range $i, $arg := . }} var arg{{$i}} {{ $arg.TypeReference.GO | ref}} if tmp, ok := rawArgs[{{$arg.Name|quote}}]; ok { - {{- if $arg.Directives }} - getArg0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, tmp) } - - {{- range $i, $directive := $arg.Directives }} - getArg{{add $i 1}} := func(ctx context.Context) (res interface{}, err error) { - {{- range $dArg := $directive.Args }} - {{- if and $dArg.TypeReference.IsPtr ( notNil "Value" $dArg ) }} - {{ $dArg.VarName }} := {{ $dArg.Value | dump }} - {{- end }} - {{- end }} - n := getArg{{$i}} - return ec.directives.{{$directive.Name|ucFirst}}({{$directive.ResolveArgs "tmp" "n" }}) - } - {{- end }} - - tmp, err = getArg{{$arg.Directives|len}}(ctx) + {{- if $arg.ImplDirectives }} + directive0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, tmp) } + {{ template "implDirectives" $arg }} + tmp, err = directive{{$arg.ImplDirectives|len}}(ctx) if err != nil { return nil, err } diff --git a/vendor/github.com/99designs/gqlgen/codegen/config/binder.go b/vendor/github.com/99designs/gqlgen/codegen/config/binder.go index cea904ad..72956de4 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/config/binder.go +++ b/vendor/github.com/99designs/gqlgen/codegen/config/binder.go @@ -14,7 +14,7 @@ import ( // Binder connects graphql types to golang types using static analysis type Binder struct { - pkgs []*packages.Package + pkgs map[string]*packages.Package schema *ast.Schema cfg *Config References []*TypeReference @@ -26,7 +26,9 @@ func (c *Config) NewBinder(s *ast.Schema) (*Binder, error) { return nil, err } + mp := map[string]*packages.Package{} for _, p := range pkgs { + populatePkg(mp, p) for _, e := range p.Errors { if e.Kind == packages.ListError { return nil, p.Errors[0] @@ -35,12 +37,23 @@ func (c *Config) NewBinder(s *ast.Schema) (*Binder, error) { } return &Binder{ - pkgs: pkgs, + pkgs: mp, schema: s, cfg: c, }, nil } +func populatePkg(mp map[string]*packages.Package, p *packages.Package) { + imp := code.NormalizeVendor(p.PkgPath) + if _, ok := mp[imp]; ok { + return + } + mp[imp] = p + for _, p := range p.Imports { + populatePkg(mp, p) + } +} + func (b *Binder) TypePosition(typ types.Type) token.Position { named, isNamed := typ.(*types.Named) if !isNamed { @@ -75,10 +88,9 @@ func (b *Binder) FindType(pkgName string, typeName string) (types.Type, error) { } func (b *Binder) getPkg(find string) *packages.Package { - for _, p := range b.pkgs { - if code.NormalizeVendor(find) == code.NormalizeVendor(p.PkgPath) { - return p - } + imp := code.NormalizeVendor(find) + if p, ok := b.pkgs[imp]; ok { + return p } return nil } diff --git a/vendor/github.com/99designs/gqlgen/codegen/config/config.go b/vendor/github.com/99designs/gqlgen/codegen/config/config.go index 1725adab..c7a7d4d8 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/config/config.go +++ b/vendor/github.com/99designs/gqlgen/codegen/config/config.go @@ -6,9 +6,12 @@ import ( "io/ioutil" "os" "path/filepath" + "regexp" "sort" "strings" + "golang.org/x/tools/go/packages" + "github.com/99designs/gqlgen/internal/code" "github.com/pkg/errors" "github.com/vektah/gqlparser" @@ -17,12 +20,14 @@ import ( ) type Config struct { - SchemaFilename StringList `yaml:"schema,omitempty"` - Exec PackageConfig `yaml:"exec"` - Model PackageConfig `yaml:"model"` - Resolver PackageConfig `yaml:"resolver,omitempty"` - Models TypeMap `yaml:"models,omitempty"` - StructTag string `yaml:"struct_tag,omitempty"` + SchemaFilename StringList `yaml:"schema,omitempty"` + Exec PackageConfig `yaml:"exec"` + Model PackageConfig `yaml:"model"` + Resolver PackageConfig `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"` } var cfgFilenames = []string{".gqlgen.yml", "gqlgen.yml", "gqlgen.yaml"} @@ -33,6 +38,17 @@ func DefaultConfig() *Config { SchemaFilename: StringList{"schema.graphql"}, Model: PackageConfig{Filename: "models_gen.go"}, Exec: PackageConfig{Filename: "generated.go"}, + Directives: map[string]DirectiveConfig{ + "skip": { + SkipRuntime: true, + }, + "include": { + SkipRuntime: true, + }, + "deprecated": { + SkipRuntime: true, + }, + }, } } @@ -51,6 +67,13 @@ func LoadConfigFromDefaultLocations() (*Config, error) { return LoadConfig(cfgFile) } +var path2regex = strings.NewReplacer( + `.`, `\.`, + `*`, `.+`, + `\`, `[\\/]`, + `/`, `[\\/]`, +) + // LoadConfig reads the gqlgen.yml config file func LoadConfig(filename string) (*Config, error) { config := DefaultConfig() @@ -67,9 +90,35 @@ func LoadConfig(filename string) (*Config, error) { preGlobbing := config.SchemaFilename config.SchemaFilename = StringList{} for _, f := range preGlobbing { - matches, err := filepath.Glob(f) - if err != nil { - return nil, errors.Wrapf(err, "failed to glob schema filename %s", f) + var matches []string + + // for ** we want to override default globbing patterns and walk all + // subdirectories to match schema files. + if strings.Contains(f, "**") { + pathParts := strings.SplitN(f, "**", 2) + rest := strings.TrimPrefix(strings.TrimPrefix(pathParts[1], `\`), `/`) + // turn the rest of the glob into a regex, anchored only at the end because ** allows + // for any number of dirs in between and walk will let us match against the full path name + globRe := regexp.MustCompile(path2regex.Replace(rest) + `$`) + + if err := filepath.Walk(pathParts[0], func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if globRe.MatchString(strings.TrimPrefix(path, pathParts[0])) { + matches = append(matches, path) + } + + return nil + }); err != nil { + return nil, errors.Wrapf(err, "failed to walk schema at root %s", pathParts[0]) + } + } else { + matches, err = filepath.Glob(f) + if err != nil { + return nil, errors.Wrapf(err, "failed to glob schema filename %s", f) + } } for _, m := range matches { @@ -265,6 +314,10 @@ func (tm TypeMap) Add(Name string, goType string) { tm[Name] = modelCfg } +type DirectiveConfig struct { + SkipRuntime bool `yaml:"skip_runtime"` +} + func inStrSlice(haystack []string, needle string) bool { for _, v := range haystack { if needle == v { @@ -329,6 +382,31 @@ func (c *Config) normalize() error { return nil } +func (c *Config) Autobind(s *ast.Schema) error { + if len(c.AutoBind) == 0 { + return nil + } + ps, err := packages.Load(&packages.Config{Mode: packages.LoadTypes}, c.AutoBind...) + if err != nil { + return err + } + + for _, t := range s.Types { + if c.Models.UserDefined(t.Name) { + continue + } + + for _, p := range ps { + if t := p.Types.Scope().Lookup(t.Name); t != nil { + c.Models.Add(t.Name(), t.Pkg().Path()+"."+t.Name()) + break + } + } + } + + return nil +} + func (c *Config) InjectBuiltins(s *ast.Schema) { builtins := TypeMap{ "__Directive": {Model: StringList{"github.com/99designs/gqlgen/graphql/introspection.Directive"}}, diff --git a/vendor/github.com/99designs/gqlgen/codegen/data.go b/vendor/github.com/99designs/gqlgen/codegen/data.go index f2ea70b4..98d2ec88 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/data.go +++ b/vendor/github.com/99designs/gqlgen/codegen/data.go @@ -15,7 +15,7 @@ type Data struct { Config *config.Config Schema *ast.Schema SchemaStr map[string]string - Directives map[string]*Directive + Directives DirectiveList Objects Objects Inputs Objects Interfaces map[string]*Interface @@ -51,6 +51,11 @@ func BuildData(cfg *config.Config) (*Data, error) { return nil, err } + err = cfg.Autobind(b.Schema) + if err != nil { + return nil, err + } + cfg.InjectBuiltins(b.Schema) b.Binder, err = b.Config.NewBinder(b.Schema) diff --git a/vendor/github.com/99designs/gqlgen/codegen/directive.go b/vendor/github.com/99designs/gqlgen/codegen/directive.go index 5a27e8ac..491f92f4 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/directive.go +++ b/vendor/github.com/99designs/gqlgen/codegen/directive.go @@ -10,12 +10,43 @@ import ( "github.com/vektah/gqlparser/ast" ) +type DirectiveList map[string]*Directive + +//LocationDirectives filter directives by location +func (dl DirectiveList) LocationDirectives(location string) DirectiveList { + return locationDirectives(dl, ast.DirectiveLocation(location)) +} + type Directive struct { + *ast.DirectiveDefinition Name string Args []*FieldArgument Builtin bool } +//IsLocation check location directive +func (d *Directive) IsLocation(location ...ast.DirectiveLocation) bool { + for _, l := range d.Locations { + for _, a := range location { + if l == a { + return true + } + } + } + + return false +} + +func locationDirectives(directives DirectiveList, location ...ast.DirectiveLocation) map[string]*Directive { + mDirectives := make(map[string]*Directive) + for name, d := range directives { + if d.IsLocation(location...) { + mDirectives[name] = d + } + } + return mDirectives +} + func (b *builder) buildDirectives() (map[string]*Directive, error) { directives := make(map[string]*Directive, len(b.Schema.Directives)) @@ -24,11 +55,6 @@ func (b *builder) buildDirectives() (map[string]*Directive, error) { return nil, errors.Errorf("directive with name %s already exists", name) } - var builtin bool - if name == "skip" || name == "include" || name == "deprecated" { - builtin = true - } - var args []*FieldArgument for _, arg := range dir.Arguments { tr, err := b.Binder.TypeReference(arg.Type, nil) @@ -53,9 +79,10 @@ func (b *builder) buildDirectives() (map[string]*Directive, error) { } directives[name] = &Directive{ - Name: name, - Args: args, - Builtin: builtin, + DirectiveDefinition: dir, + Name: name, + Args: args, + Builtin: b.Config.Directives[name].SkipRuntime, } } @@ -92,8 +119,10 @@ func (b *builder) getDirectives(list ast.DirectiveList) ([]*Directive, error) { }) } dirs[i] = &Directive{ - Name: d.Name, - Args: args, + Name: d.Name, + Args: args, + DirectiveDefinition: list[i].Definition, + Builtin: b.Config.Directives[d.Name].SkipRuntime, } } @@ -119,18 +148,12 @@ func (d *Directive) CallArgs() string { return strings.Join(args, ", ") } -func (d *Directive) ResolveArgs(obj string, next string) string { - args := []string{"ctx", obj, next} +func (d *Directive) ResolveArgs(obj string, next int) string { + args := []string{"ctx", obj, fmt.Sprintf("directive%d", next)} for _, arg := range d.Args { - dArg := "&" + arg.VarName - if !arg.TypeReference.IsPtr() { - if arg.Value != nil { - dArg = templates.Dump(arg.Value) - } else { - dArg = templates.Dump(arg.Default) - } - } else if arg.Value == nil && arg.Default == nil { + dArg := arg.VarName + if arg.Value == nil && arg.Default == nil { dArg = "nil" } diff --git a/vendor/github.com/99designs/gqlgen/codegen/directives.gotpl b/vendor/github.com/99designs/gqlgen/codegen/directives.gotpl new file mode 100644 index 00000000..67a0783e --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/codegen/directives.gotpl @@ -0,0 +1,137 @@ +{{ define "implDirectives" }}{{ $in := .DirectiveObjName }} + {{- range $i, $directive := .ImplDirectives -}} + directive{{add $i 1}} := func(ctx context.Context) (interface{}, error) { + {{- range $arg := $directive.Args }} + {{- if notNil "Value" $arg }} + {{ $arg.VarName }}, err := ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, {{ $arg.Value | dump }}) + if err != nil{ + return nil, err + } + {{- else if notNil "Default" $arg }} + {{ $arg.VarName }}, err := ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, {{ $arg.Default | dump }}) + if err != nil{ + return nil, err + } + {{- end }} + {{- end }} + return ec.directives.{{$directive.Name|ucFirst}}({{$directive.ResolveArgs $in $i }}) + } + {{- end -}} +{{ end }} + +{{define "queryDirectives"}} + for _, d := range obj.Directives { + switch d.Name { + {{- range $directive := . }} + case "{{$directive.Name}}": + {{- if $directive.Args }} + rawArgs := d.ArgumentMap(ec.Variables) + args, err := ec.{{ $directive.ArgsFunc }}(ctx,rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + {{- end }} + n := next + next = func(ctx context.Context) (interface{}, error) { + return ec.directives.{{$directive.Name|ucFirst}}({{$directive.CallArgs}}) + } + {{- end }} + } + } + tmp, err := next(ctx) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if data, ok := tmp.(graphql.Marshaler); ok { + return data + } + ec.Errorf(ctx, `unexpected type %T from directive, should be graphql.Marshaler`, tmp) + return graphql.Null +{{end}} + +{{ if .Directives.LocationDirectives "QUERY" }} +func (ec *executionContext) _queryMiddleware(ctx context.Context, obj *ast.OperationDefinition, next func(ctx context.Context) (interface{}, error)) graphql.Marshaler { + {{ template "queryDirectives" .Directives.LocationDirectives "QUERY" }} +} +{{ end }} + +{{ if .Directives.LocationDirectives "MUTATION" }} +func (ec *executionContext) _mutationMiddleware(ctx context.Context, obj *ast.OperationDefinition, next func(ctx context.Context) (interface{}, error)) graphql.Marshaler { + {{ template "queryDirectives" .Directives.LocationDirectives "MUTATION" }} +} +{{ 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 { + for _, d := range obj.Directives { + switch d.Name { + {{- range $directive := .Directives.LocationDirectives "SUBSCRIPTION" }} + case "{{$directive.Name}}": + {{- if $directive.Args }} + rawArgs := d.ArgumentMap(ec.Variables) + args, err := ec.{{ $directive.ArgsFunc }}(ctx,rawArgs) + if err != nil { + ec.Error(ctx, err) + return func() graphql.Marshaler { + return graphql.Null + } + } + {{- end }} + n := next + next = func(ctx context.Context) (interface{}, error) { + return ec.directives.{{$directive.Name|ucFirst}}({{$directive.CallArgs}}) + } + {{- end }} + } + } + tmp, err := next(ctx) + if err != nil { + ec.Error(ctx, err) + return func() graphql.Marshaler { + return graphql.Null + } + } + if data, ok := tmp.(func() graphql.Marshaler); ok { + return data + } + ec.Errorf(ctx, `unexpected type %T from directive, should be graphql.Marshaler`, tmp) + return func() graphql.Marshaler { + return graphql.Null + } +} +{{ end }} + +{{ if .Directives.LocationDirectives "FIELD" }} + func (ec *executionContext) _fieldMiddleware(ctx context.Context, obj interface{}, next graphql.Resolver) interface{} { + {{- if .Directives.LocationDirectives "FIELD" }} + rctx := graphql.GetResolverContext(ctx) + for _, d := range rctx.Field.Directives { + switch d.Name { + {{- range $directive := .Directives.LocationDirectives "FIELD" }} + case "{{$directive.Name}}": + {{- if $directive.Args }} + rawArgs := d.ArgumentMap(ec.Variables) + args, err := ec.{{ $directive.ArgsFunc }}(ctx,rawArgs) + if err != nil { + ec.Error(ctx, err) + return nil + } + {{- end }} + n := next + next = func(ctx context.Context) (interface{}, error) { + return ec.directives.{{$directive.Name|ucFirst}}({{$directive.CallArgs}}) + } + {{- end }} + } + } + {{- end }} + res, err := ec.ResolverMiddleware(ctx, next) + if err != nil { + ec.Error(ctx, err) + return nil + } + return res + } +{{ end }} diff --git a/vendor/github.com/99designs/gqlgen/codegen/field.go b/vendor/github.com/99designs/gqlgen/codegen/field.go index f5f7b221..264b59ce 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/field.go +++ b/vendor/github.com/99designs/gqlgen/codegen/field.go @@ -284,7 +284,28 @@ func (b *builder) findBindStructTarget(strukt *types.Struct, name string) (types } func (f *Field) HasDirectives() bool { - return len(f.Directives) > 0 + return len(f.ImplDirectives()) > 0 +} + +func (f *Field) DirectiveObjName() string { + if f.Object.Root { + return "nil" + } + return f.GoReceiverName +} + +func (f *Field) ImplDirectives() []*Directive { + var d []*Directive + loc := ast.LocationFieldDefinition + if f.Object.IsInputType() { + loc = ast.LocationInputFieldDefinition + } + for i := range f.Directives { + if !f.Directives[i].Builtin && f.Directives[i].IsLocation(loc) { + d = append(d, f.Directives[i]) + } + } + return d } func (f *Field) IsReserved() bool { diff --git a/vendor/github.com/99designs/gqlgen/codegen/field.gotpl b/vendor/github.com/99designs/gqlgen/codegen/field.gotpl index 9718a08a..c0f6fcae 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/field.gotpl +++ b/vendor/github.com/99designs/gqlgen/codegen/field.gotpl @@ -37,9 +37,15 @@ } } {{ else }} - func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Context, field graphql.CollectedField{{ if not $object.Root }}, obj {{$object.Reference | ref}}{{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 graphql.Marshaler) { ctx = ec.Tracer.StartFieldExecution(ctx, field) - defer func () { ec.Tracer.EndFieldExecution(ctx) }() + defer func () { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + ec.Tracer.EndFieldExecution(ctx) + }() rctx := &graphql.ResolverContext{ Object: {{$object.Name|quote}}, Field: field, @@ -57,31 +63,19 @@ rctx.Args = args {{- end }} ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx) - resTmp := ec.FieldMiddleware(ctx, {{if $object.Root}}nil{{else}}obj{{end}}, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - {{- if $field.IsResolver }} - return ec.resolvers.{{ $field.ShortInvocation }} - {{- else if $field.IsMap }} - switch v := {{$field.GoReceiverName}}[{{$field.Name|quote}}].(type) { - case {{$field.TypeReference.GO | ref}}: - return v, nil - case {{$field.TypeReference.Elem.GO | ref}}: - return &v, nil - case nil: - return ({{$field.TypeReference.GO | ref}})(nil), nil - default: - return nil, fmt.Errorf("unexpected type %T for field %s", v, {{ $field.Name | quote}}) - } - {{- else if $field.IsMethod }} - {{- if $field.NoErr }} - return {{$field.GoReceiverName}}.{{$field.GoFieldName}}({{ $field.CallArgs }}), nil - {{- else }} - return {{$field.GoReceiverName}}.{{$field.GoFieldName}}({{ $field.CallArgs }}) - {{- end }} - {{- else if $field.IsVariable }} - return {{$field.GoReceiverName}}.{{$field.GoFieldName}}, nil - {{- end }} - }) + {{- if $.Directives.LocationDirectives "FIELD" }} + resTmp := ec._fieldMiddleware(ctx, {{if $object.Root}}nil{{else}}obj{{end}}, func(rctx context.Context) (interface{}, error) { + {{ template "field" $field }} + }) + {{ else }} + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + {{ template "field" $field }} + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + {{- end }} if resTmp == nil { {{- if $field.TypeReference.GQL.NonNull }} if !ec.HasError(rctx) { @@ -98,3 +92,49 @@ {{ end }} {{- end }}{{- end}} + +{{ define "field" }} + {{- if .HasDirectives -}} + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + {{ template "fieldDefinition" . }} + } + {{ template "implDirectives" . }} + tmp, err := directive{{.ImplDirectives|len}}(rctx) + if err != nil { + return nil, err + } + if data, ok := tmp.({{ .TypeReference.GO | ref }}) ; ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be {{ .TypeReference.GO }}`, tmp) + {{- else -}} + ctx = rctx // use context from middleware stack in children + {{ template "fieldDefinition" . }} + {{- end -}} +{{ end }} + +{{ define "fieldDefinition" }} + {{- if .IsResolver -}} + return ec.resolvers.{{ .ShortInvocation }} + {{- else if .IsMap -}} + switch v := {{.GoReceiverName}}[{{.Name|quote}}].(type) { + case {{.TypeReference.GO | ref}}: + return v, nil + case {{.TypeReference.Elem.GO | ref}}: + return &v, nil + case nil: + return ({{.TypeReference.GO | ref}})(nil), nil + default: + return nil, fmt.Errorf("unexpected type %T for field %s", v, {{ .Name | quote}}) + } + {{- else if .IsMethod -}} + {{- if .NoErr -}} + return {{.GoReceiverName}}.{{.GoFieldName}}({{ .CallArgs }}), nil + {{- else -}} + return {{.GoReceiverName}}.{{.GoFieldName}}({{ .CallArgs }}) + {{- end -}} + {{- else if .IsVariable -}} + return {{.GoReceiverName}}.{{.GoFieldName}}, nil + {{- end }} +{{- end }} diff --git a/vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl b/vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl index 5753f1d1..a95e57b6 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl +++ b/vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl @@ -117,7 +117,13 @@ func (e *executableSchema) Query(ctx context.Context, op *ast.OperationDefinitio ec := executionContext{graphql.GetRequestContext(ctx), e} buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte { + {{ if .Directives.LocationDirectives "QUERY" -}} + data := ec._queryMiddleware(ctx, op, func(ctx context.Context) (interface{}, error){ + return ec._{{.QueryRoot.Name}}(ctx, op.SelectionSet), nil + }) + {{- else -}} data := ec._{{.QueryRoot.Name}}(ctx, op.SelectionSet) + {{- end }} var buf bytes.Buffer data.MarshalGQL(&buf) return buf.Bytes() @@ -138,7 +144,13 @@ func (e *executableSchema) Mutation(ctx context.Context, op *ast.OperationDefini ec := executionContext{graphql.GetRequestContext(ctx), e} buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte { + {{ if .Directives.LocationDirectives "MUTATION" -}} + data := ec._mutationMiddleware(ctx, op, func(ctx context.Context) (interface{}, error){ + return ec._{{.MutationRoot.Name}}(ctx, op.SelectionSet), nil + }) + {{- else -}} data := ec._{{.MutationRoot.Name}}(ctx, op.SelectionSet) + {{- end }} var buf bytes.Buffer data.MarshalGQL(&buf) return buf.Bytes() @@ -158,7 +170,13 @@ func (e *executableSchema) Subscription(ctx context.Context, op *ast.OperationDe {{- if .SubscriptionRoot }} ec := executionContext{graphql.GetRequestContext(ctx), e} - next := ec._{{.SubscriptionRoot.Name}}(ctx, op.SelectionSet) + {{ if .Directives.LocationDirectives "SUBSCRIPTION" -}} + next := ec._subscriptionMiddleware(ctx, op, func(ctx context.Context) (interface{}, error){ + return ec._{{.SubscriptionRoot.Name}}(ctx, op.SelectionSet),nil + }) + {{- else -}} + next := ec._{{.SubscriptionRoot.Name}}(ctx, op.SelectionSet) + {{- end }} if ec.Errors != nil { return graphql.OneShot(&graphql.Response{Data: []byte("null"), Errors: ec.Errors}) } @@ -196,45 +214,6 @@ type executionContext struct { *executableSchema } -func (ec *executionContext) FieldMiddleware(ctx context.Context, obj interface{}, next graphql.Resolver) (ret interface{}) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - {{- if .Directives }} - rctx := graphql.GetResolverContext(ctx) - for _, d := range rctx.Field.Definition.Directives { - switch d.Name { - {{- range $directive := .Directives }} - case "{{$directive.Name}}": - if ec.directives.{{$directive.Name|ucFirst}} != nil { - {{- if $directive.Args }} - rawArgs := d.ArgumentMap(ec.Variables) - args, err := ec.{{ $directive.ArgsFunc }}(ctx,rawArgs) - if err != nil { - ec.Error(ctx, err) - return nil - } - {{- end }} - n := next - next = func(ctx context.Context) (interface{}, error) { - return ec.directives.{{$directive.Name|ucFirst}}({{$directive.CallArgs}}) - } - } - {{- end }} - } - } - {{- end }} - res, err := ec.ResolverMiddleware(ctx, next) - if err != nil { - ec.Error(ctx, err) - return nil - } - return res -} - func (ec *executionContext) introspectSchema() (*introspection.Schema, error) { if ec.DisableIntrospection { return nil, errors.New("introspection disabled") diff --git a/vendor/github.com/99designs/gqlgen/codegen/input.gotpl b/vendor/github.com/99designs/gqlgen/codegen/input.gotpl index c8ac7ad3..b51d53a2 100644 --- a/vendor/github.com/99designs/gqlgen/codegen/input.gotpl +++ b/vendor/github.com/99designs/gqlgen/codegen/input.gotpl @@ -1,8 +1,8 @@ {{- range $input := .Inputs }} {{- if not .HasUnmarshal }} - func (ec *executionContext) unmarshalInput{{ .Name }}(ctx context.Context, v interface{}) ({{.Type | ref}}, error) { + func (ec *executionContext) unmarshalInput{{ .Name }}(ctx context.Context, obj interface{}) ({{.Type | ref}}, error) { var it {{.Type | ref}} - var asMap = v.(map[string]interface{}) + var asMap = obj.(map[string]interface{}) {{ range $field := .Fields}} {{- if $field.Default}} if _, present := asMap[{{$field.Name|quote}}] ; !present { @@ -16,22 +16,10 @@ {{- range $field := .Fields }} case {{$field.Name|quote}}: var err error - {{- if $field.Directives }} - getField0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $field.TypeReference.UnmarshalFunc }}(ctx, v) } - - {{- range $i, $directive := $field.Directives }} - getField{{add $i 1}} := func(ctx context.Context) (res interface{}, err error) { - {{- range $dArg := $directive.Args }} - {{- if and $dArg.TypeReference.IsPtr ( notNil "Value" $dArg ) }} - {{ $dArg.VarName }} := {{ $dArg.Value | dump }} - {{- end }} - {{- end }} - n := getField{{$i}} - return ec.directives.{{$directive.Name|ucFirst}}({{$directive.ResolveArgs "it" "n" }}) - } - {{- end }} - - tmp, err := getField{{$field.Directives|len}}(ctx) + {{- if $field.ImplDirectives }} + directive0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $field.TypeReference.UnmarshalFunc }}(ctx, v) } + {{ template "implDirectives" $field }} + tmp, err := directive{{$field.ImplDirectives|len}}(ctx) if err != nil { return it, err } diff --git a/vendor/github.com/99designs/gqlgen/graphql/version.go b/vendor/github.com/99designs/gqlgen/graphql/version.go index 11dc6b01..3c5e65d6 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.9.0" +const Version = "v0.9.1" diff --git a/vendor/github.com/99designs/gqlgen/handler/graphql.go b/vendor/github.com/99designs/gqlgen/handler/graphql.go index a2254222..289901f0 100644 --- a/vendor/github.com/99designs/gqlgen/handler/graphql.go +++ b/vendor/github.com/99designs/gqlgen/handler/graphql.go @@ -2,6 +2,8 @@ package handler import ( "context" + "crypto/sha256" + "encoding/hex" "encoding/json" "errors" "fmt" @@ -28,8 +30,30 @@ type params struct { Query string `json:"query"` OperationName string `json:"operationName"` Variables map[string]interface{} `json:"variables"` + Extensions *extensions `json:"extensions"` } +type extensions struct { + PersistedQuery *persistedQuery `json:"persistedQuery"` +} + +type persistedQuery struct { + Sha256 string `json:"sha256Hash"` + Version int64 `json:"version"` +} + +const ( + errPersistedQueryNotSupported = "PersistedQueryNotSupported" + errPersistedQueryNotFound = "PersistedQueryNotFound" +) + +type PersistedQueryCache interface { + Add(ctx context.Context, hash string, query string) + Get(ctx context.Context, hash string) (string, bool) +} + +type websocketInitFunc func(ctx context.Context, initPayload InitPayload) error + type Config struct { cacheSize int upgrader websocket.Upgrader @@ -40,10 +64,12 @@ type Config struct { tracer graphql.Tracer complexityLimit int complexityLimitFunc graphql.ComplexityLimitFunc + websocketInitFunc websocketInitFunc disableIntrospection bool connectionKeepAlivePingInterval time.Duration uploadMaxMemory int64 uploadMaxSize int64 + apqCache PersistedQueryCache } func (c *Config) newRequestContext(es graphql.ExecutableSchema, doc *ast.QueryDocument, op *ast.OperationDefinition, query string, variables map[string]interface{}) *graphql.RequestContext { @@ -250,6 +276,14 @@ func (tw *tracerWrapper) EndOperationExecution(ctx context.Context) { tw.tracer1.EndOperationExecution(ctx) } +// WebsocketInitFunc is called when the server receives connection init message from the client. +// This can be used to check initial payload to see whether to accept the websocket connection. +func WebsocketInitFunc(websocketInitFunc func(ctx context.Context, initPayload InitPayload) error) Option { + return func(cfg *Config) { + cfg.websocketInitFunc = websocketInitFunc + } +} + // CacheSize sets the maximum size of the query cache. // If size is less than or equal to 0, the cache is disabled. func CacheSize(size int) Option { @@ -285,6 +319,13 @@ func WebsocketKeepAliveDuration(duration time.Duration) Option { } } +// Add cache that will hold queries for automatic persisted queries (APQ) +func EnablePersistedQueryCache(cache PersistedQueryCache) Option { + return func(cfg *Config) { + cfg.apqCache = cache + } +} + const DefaultCacheSize = 1000 const DefaultConnectionKeepAlivePingInterval = 25 * time.Second @@ -344,6 +385,11 @@ type graphqlHandler struct { exec graphql.ExecutableSchema } +func computeQueryHash(query string) string { + b := sha256.Sum256([]byte(query)) + return hex.EncodeToString(b[:]) +} + func (gh *graphqlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodOptions { w.Header().Set("Allow", "OPTIONS, GET, POST") @@ -369,6 +415,13 @@ func (gh *graphqlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } } + + if extensions := r.URL.Query().Get("extensions"); extensions != "" { + if err := jsonDecode(strings.NewReader(extensions), &reqParams.Extensions); err != nil { + sendErrorf(w, http.StatusBadRequest, "extensions could not be decoded") + return + } + } case http.MethodPost: mediaType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) if err != nil { @@ -409,6 +462,41 @@ func (gh *graphqlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { ctx := r.Context() + var queryHash string + apqRegister := false + apq := reqParams.Extensions != nil && reqParams.Extensions.PersistedQuery != nil + if apq { + // client has enabled apq + queryHash = reqParams.Extensions.PersistedQuery.Sha256 + if gh.cfg.apqCache == nil { + // server has disabled apq + sendErrorf(w, http.StatusOK, errPersistedQueryNotSupported) + return + } + if reqParams.Extensions.PersistedQuery.Version != 1 { + sendErrorf(w, http.StatusOK, "Unsupported persisted query version") + return + } + if reqParams.Query == "" { + // client sent optimistic query hash without query string + query, ok := gh.cfg.apqCache.Get(ctx, queryHash) + if !ok { + sendErrorf(w, http.StatusOK, errPersistedQueryNotFound) + return + } + reqParams.Query = query + } else { + if computeQueryHash(reqParams.Query) != queryHash { + sendErrorf(w, http.StatusOK, "provided sha does not match query") + return + } + apqRegister = true + } + } else if reqParams.Query == "" { + sendErrorf(w, http.StatusUnprocessableEntity, "Must provide query string") + return + } + var doc *ast.QueryDocument var cacheHit bool if gh.cache != nil { @@ -463,6 +551,11 @@ func (gh *graphqlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } + if apqRegister && gh.cfg.apqCache != nil { + // Add to persisted query cache + gh.cfg.apqCache.Add(ctx, queryHash, reqParams.Query) + } + switch op.Operation { case ast.Query: b, err := json.Marshal(gh.exec.Query(ctx, op)) diff --git a/vendor/github.com/99designs/gqlgen/handler/websocket.go b/vendor/github.com/99designs/gqlgen/handler/websocket.go index 58f38e5d..07a1a8c2 100644 --- a/vendor/github.com/99designs/gqlgen/handler/websocket.go +++ b/vendor/github.com/99designs/gqlgen/handler/websocket.go @@ -12,7 +12,7 @@ import ( "github.com/99designs/gqlgen/graphql" "github.com/gorilla/websocket" - "github.com/hashicorp/golang-lru" + lru "github.com/hashicorp/golang-lru" "github.com/vektah/gqlparser" "github.com/vektah/gqlparser/ast" "github.com/vektah/gqlparser/gqlerror" @@ -94,6 +94,14 @@ func (c *wsConnection) init() bool { } } + if c.cfg.websocketInitFunc != nil { + if err := c.cfg.websocketInitFunc(c.ctx, c.initPayload); err != nil { + c.sendConnectionError(err.Error()) + c.close(websocket.CloseNormalClosure, "terminated") + return false + } + } + c.write(&operationMessage{Type: connectionAckMsg}) case connectionTerminateMsg: c.close(websocket.CloseNormalClosure, "terminated") diff --git a/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go b/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go index bb400f1b..376499ae 100644 --- a/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go +++ b/vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go @@ -72,6 +72,11 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error { return err } + err = cfg.Autobind(schema) + if err != nil { + return err + } + cfg.InjectBuiltins(schema) binder, err := cfg.NewBinder(schema) diff --git a/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.go b/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.go index 00a6d5c9..6785c77c 100644 --- a/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.go +++ b/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.go @@ -19,6 +19,7 @@ type Plugin struct{} var _ plugin.CodeGenerator = &Plugin{} func (m *Plugin) Name() string { + // TODO: typo, should be resolvergen return "resovlergen" } func (m *Plugin) GenerateCode(data *codegen.Data) error { diff --git a/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.gotpl b/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.gotpl index 7d95e690..66d6efac 100644 --- a/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.gotpl +++ b/vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.gotpl @@ -20,18 +20,18 @@ type {{.ResolverType}} struct {} {{ range $object := .Objects -}} {{- if $object.HasResolvers -}} func (r *{{$.ResolverType}}) {{$object.Name}}() {{ $object.ResolverInterface | ref }} { - return &{{lcFirst $object.Name}}Resolver{r} + return &{{lcFirst $object.Name}}{{ucFirst $.ResolverType}}{r} } {{ end -}} {{ end }} {{ range $object := .Objects -}} {{- if $object.HasResolvers -}} - type {{lcFirst $object.Name}}Resolver struct { *Resolver } + type {{lcFirst $object.Name}}{{ucFirst $.ResolverType}} struct { *{{$.ResolverType}} } {{ range $field := $object.Fields -}} {{- if $field.IsResolver -}} - func (r *{{lcFirst $object.Name}}Resolver) {{$field.GoFieldName}}{{ $field.ShortResolverDeclaration }} { + func (r *{{lcFirst $object.Name}}{{ucFirst $.ResolverType}}) {{$field.GoFieldName}}{{ $field.ShortResolverDeclaration }} { panic("not implemented") } {{ end -}} diff --git a/vendor/github.com/99designs/gqlgen/plugin/schemaconfig/schemaconfig.go b/vendor/github.com/99designs/gqlgen/plugin/schemaconfig/schemaconfig.go new file mode 100644 index 00000000..1fcf4105 --- /dev/null +++ b/vendor/github.com/99designs/gqlgen/plugin/schemaconfig/schemaconfig.go @@ -0,0 +1,93 @@ +package schemaconfig + +import ( + "github.com/99designs/gqlgen/codegen/config" + "github.com/99designs/gqlgen/plugin" + "github.com/vektah/gqlparser/ast" +) + +func New() plugin.Plugin { + return &Plugin{} +} + +type Plugin struct{} + +var _ plugin.ConfigMutator = &Plugin{} + +func (m *Plugin) Name() string { + return "schemaconfig" +} + +func (m *Plugin) MutateConfig(cfg *config.Config) error { + if err := cfg.Check(); err != nil { + return err + } + + schema, _, err := cfg.LoadSchema() + if err != nil { + return err + } + + cfg.Directives["goModel"] = config.DirectiveConfig{ + SkipRuntime: true, + } + + cfg.Directives["goField"] = config.DirectiveConfig{ + SkipRuntime: true, + } + + for _, schemaType := range schema.Types { + if schemaType == schema.Query || schemaType == schema.Mutation || schemaType == schema.Subscription { + continue + } + + if bd := schemaType.Directives.ForName("goModel"); bd != nil { + if ma := bd.Arguments.ForName("model"); ma != nil { + if mv, err := ma.Value.Value(nil); err == nil { + cfg.Models.Add(schemaType.Name, mv.(string)) + } + } + if ma := bd.Arguments.ForName("models"); ma != nil { + if mvs, err := ma.Value.Value(nil); err == nil { + for _, mv := range mvs.([]interface{}) { + cfg.Models.Add(schemaType.Name, mv.(string)) + } + } + } + } + + if schemaType.Kind == ast.Object || schemaType.Kind == ast.InputObject { + for _, field := range schemaType.Fields { + if fd := field.Directives.ForName("goField"); fd != nil { + forceResolver := cfg.Models[schemaType.Name].Fields[field.Name].Resolver + fieldName := cfg.Models[schemaType.Name].Fields[field.Name].FieldName + + if ra := fd.Arguments.ForName("forceResolver"); ra != nil { + if fr, err := ra.Value.Value(nil); err == nil { + forceResolver = fr.(bool) + } + } + + if na := fd.Arguments.ForName("name"); na != nil { + if fr, err := na.Value.Value(nil); err == nil { + fieldName = fr.(string) + } + } + + if cfg.Models[schemaType.Name].Fields == nil { + cfg.Models[schemaType.Name] = config.TypeMapEntry{ + Model: cfg.Models[schemaType.Name].Model, + Fields: map[string]config.TypeMapField{}, + } + } + + cfg.Models[schemaType.Name].Fields[field.Name] = config.TypeMapField{ + FieldName: fieldName, + Resolver: forceResolver, + } + } + } + } + } + return nil +}