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/LICENSE19
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/build.go214
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/codegen.go174
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/config.go195
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/directive.go41
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/directive_build.go49
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/enum.go12
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/enum_build.go39
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/import.go29
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/import_build.go120
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/input_build.go96
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/interface.go13
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/interface_build.go70
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/model.go16
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/models_build.go90
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/object.go464
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/object_build.go181
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/templates/args.gotpl13
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/templates/data.go13
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/templates/field.gotpl74
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/templates/generated.gotpl263
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/templates/input.gotpl28
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/templates/interface.gotpl18
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/templates/models.gotpl72
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/templates/object.gotpl69
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/templates/resolver.gotpl33
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/templates/server.gotpl22
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/templates/templates.go193
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/type.go170
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/type_build.go101
-rw-r--r--vendor/github.com/99designs/gqlgen/codegen/util.go367
-rw-r--r--vendor/github.com/99designs/gqlgen/complexity/complexity.go104
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/bool.go30
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/context.go178
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/error.go31
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/exec.go135
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/float.go31
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/id.go36
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/int.go29
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/introspection/introspection.go58
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/introspection/query.go104
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/introspection/schema.go68
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/introspection/type.go174
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/jsonw.go83
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/map.go24
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/oneshot.go14
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/recovery.go19
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/response.go20
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/string.go63
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/time.go21
-rw-r--r--vendor/github.com/99designs/gqlgen/graphql/version.go3
-rw-r--r--vendor/github.com/99designs/gqlgen/handler/graphql.go283
-rw-r--r--vendor/github.com/99designs/gqlgen/handler/playground.go54
-rw-r--r--vendor/github.com/99designs/gqlgen/handler/stub.go51
-rw-r--r--vendor/github.com/99designs/gqlgen/handler/websocket.go252
-rw-r--r--vendor/github.com/99designs/gqlgen/internal/gopath/gopath.go37
56 files changed, 5160 insertions, 0 deletions
diff --git a/vendor/github.com/99designs/gqlgen/LICENSE b/vendor/github.com/99designs/gqlgen/LICENSE
new file mode 100644
index 00000000..18e1b249
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2018 Adam Scarr
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/99designs/gqlgen/codegen/build.go b/vendor/github.com/99designs/gqlgen/codegen/build.go
new file mode 100644
index 00000000..42dedbf8
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/build.go
@@ -0,0 +1,214 @@
+package codegen
+
+import (
+ "fmt"
+ "go/build"
+ "go/types"
+ "os"
+
+ "github.com/pkg/errors"
+ "golang.org/x/tools/go/loader"
+)
+
+type Build struct {
+ PackageName string
+ Objects Objects
+ Inputs Objects
+ Interfaces []*Interface
+ Imports []*Import
+ QueryRoot *Object
+ MutationRoot *Object
+ SubscriptionRoot *Object
+ SchemaRaw string
+ SchemaFilename string
+ Directives []*Directive
+}
+
+type ModelBuild struct {
+ PackageName string
+ Imports []*Import
+ Models []Model
+ Enums []Enum
+}
+
+type ResolverBuild struct {
+ PackageName string
+ Imports []*Import
+ ResolverType string
+ Objects Objects
+ ResolverFound bool
+}
+
+type ServerBuild struct {
+ PackageName string
+ Imports []*Import
+ ExecPackageName string
+ ResolverPackageName string
+}
+
+// Create a list of models that need to be generated
+func (cfg *Config) models() (*ModelBuild, error) {
+ namedTypes := cfg.buildNamedTypes()
+
+ progLoader := newLoader(namedTypes, true)
+ prog, err := progLoader.Load()
+ if err != nil {
+ return nil, errors.Wrap(err, "loading failed")
+ }
+ imports := buildImports(namedTypes, cfg.Model.Dir())
+
+ cfg.bindTypes(imports, namedTypes, cfg.Model.Dir(), prog)
+
+ models, err := cfg.buildModels(namedTypes, prog, imports)
+ if err != nil {
+ return nil, err
+ }
+ return &ModelBuild{
+ PackageName: cfg.Model.Package,
+ Models: models,
+ Enums: cfg.buildEnums(namedTypes),
+ Imports: imports.finalize(),
+ }, nil
+}
+
+// bind a schema together with some code to generate a Build
+func (cfg *Config) resolver() (*ResolverBuild, error) {
+ progLoader := newLoader(cfg.buildNamedTypes(), true)
+ progLoader.Import(cfg.Resolver.ImportPath())
+
+ prog, err := progLoader.Load()
+ if err != nil {
+ return nil, err
+ }
+
+ destDir := cfg.Resolver.Dir()
+
+ namedTypes := cfg.buildNamedTypes()
+ imports := buildImports(namedTypes, destDir)
+ imports.add(cfg.Exec.ImportPath())
+ imports.add("github.com/99designs/gqlgen/handler") // avoid import github.com/vektah/gqlgen/handler
+
+ cfg.bindTypes(imports, namedTypes, destDir, prog)
+
+ objects, err := cfg.buildObjects(namedTypes, prog, imports)
+ if err != nil {
+ return nil, err
+ }
+
+ def, _ := findGoType(prog, cfg.Resolver.ImportPath(), cfg.Resolver.Type)
+ resolverFound := def != nil
+
+ return &ResolverBuild{
+ PackageName: cfg.Resolver.Package,
+ Imports: imports.finalize(),
+ Objects: objects,
+ ResolverType: cfg.Resolver.Type,
+ ResolverFound: resolverFound,
+ }, nil
+}
+
+func (cfg *Config) server(destDir string) *ServerBuild {
+ imports := buildImports(NamedTypes{}, destDir)
+ imports.add(cfg.Exec.ImportPath())
+ imports.add(cfg.Resolver.ImportPath())
+
+ return &ServerBuild{
+ PackageName: cfg.Resolver.Package,
+ Imports: imports.finalize(),
+ ExecPackageName: cfg.Exec.Package,
+ ResolverPackageName: cfg.Resolver.Package,
+ }
+}
+
+// bind a schema together with some code to generate a Build
+func (cfg *Config) bind() (*Build, error) {
+ namedTypes := cfg.buildNamedTypes()
+
+ progLoader := newLoader(namedTypes, true)
+ prog, err := progLoader.Load()
+ if err != nil {
+ return nil, errors.Wrap(err, "loading failed")
+ }
+
+ imports := buildImports(namedTypes, cfg.Exec.Dir())
+ cfg.bindTypes(imports, namedTypes, cfg.Exec.Dir(), prog)
+
+ objects, err := cfg.buildObjects(namedTypes, prog, imports)
+ if err != nil {
+ return nil, err
+ }
+
+ inputs, err := cfg.buildInputs(namedTypes, prog, imports)
+ if err != nil {
+ return nil, err
+ }
+ directives, err := cfg.buildDirectives(namedTypes)
+ if err != nil {
+ return nil, err
+ }
+
+ b := &Build{
+ PackageName: cfg.Exec.Package,
+ Objects: objects,
+ Interfaces: cfg.buildInterfaces(namedTypes, prog),
+ Inputs: inputs,
+ Imports: imports.finalize(),
+ SchemaRaw: cfg.SchemaStr,
+ SchemaFilename: cfg.SchemaFilename,
+ Directives: directives,
+ }
+
+ if cfg.schema.Query != nil {
+ b.QueryRoot = b.Objects.ByName(cfg.schema.Query.Name)
+ } else {
+ return b, fmt.Errorf("query entry point missing")
+ }
+
+ if cfg.schema.Mutation != nil {
+ b.MutationRoot = b.Objects.ByName(cfg.schema.Mutation.Name)
+ }
+
+ if cfg.schema.Subscription != nil {
+ b.SubscriptionRoot = b.Objects.ByName(cfg.schema.Subscription.Name)
+ }
+ return b, nil
+}
+
+func (cfg *Config) validate() error {
+ progLoader := newLoader(cfg.buildNamedTypes(), false)
+ _, err := progLoader.Load()
+ return err
+}
+
+func newLoader(namedTypes NamedTypes, allowErrors bool) loader.Config {
+ conf := loader.Config{}
+ if allowErrors {
+ conf = loader.Config{
+ AllowErrors: true,
+ TypeChecker: types.Config{
+ Error: func(e error) {},
+ },
+ }
+ }
+ for _, imp := range ambientImports {
+ conf.Import(imp)
+ }
+
+ for _, imp := range namedTypes {
+ if imp.Package != "" {
+ conf.Import(imp.Package)
+ }
+ }
+ return conf
+}
+
+func resolvePkg(pkgName string) (string, error) {
+ cwd, _ := os.Getwd()
+
+ pkg, err := build.Default.Import(pkgName, cwd, build.FindOnly)
+ if err != nil {
+ return "", err
+ }
+
+ return pkg.ImportPath, nil
+}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/codegen.go b/vendor/github.com/99designs/gqlgen/codegen/codegen.go
new file mode 100644
index 00000000..27873400
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/codegen.go
@@ -0,0 +1,174 @@
+package codegen
+
+import (
+ "log"
+ "os"
+ "path/filepath"
+ "regexp"
+ "syscall"
+
+ "github.com/99designs/gqlgen/codegen/templates"
+ "github.com/pkg/errors"
+ "github.com/vektah/gqlparser"
+ "github.com/vektah/gqlparser/ast"
+ "github.com/vektah/gqlparser/gqlerror"
+)
+
+func Generate(cfg Config) error {
+ if err := cfg.normalize(); err != nil {
+ return err
+ }
+
+ _ = syscall.Unlink(cfg.Exec.Filename)
+ _ = syscall.Unlink(cfg.Model.Filename)
+
+ modelsBuild, err := cfg.models()
+ if err != nil {
+ return errors.Wrap(err, "model plan failed")
+ }
+ if len(modelsBuild.Models) > 0 || len(modelsBuild.Enums) > 0 {
+ if err = templates.RenderToFile("models.gotpl", cfg.Model.Filename, modelsBuild); err != nil {
+ return err
+ }
+
+ for _, model := range modelsBuild.Models {
+ modelCfg := cfg.Models[model.GQLType]
+ modelCfg.Model = cfg.Model.ImportPath() + "." + model.GoType
+ cfg.Models[model.GQLType] = modelCfg
+ }
+
+ for _, enum := range modelsBuild.Enums {
+ modelCfg := cfg.Models[enum.GQLType]
+ modelCfg.Model = cfg.Model.ImportPath() + "." + enum.GoType
+ cfg.Models[enum.GQLType] = modelCfg
+ }
+ }
+
+ build, err := cfg.bind()
+ if err != nil {
+ return errors.Wrap(err, "exec plan failed")
+ }
+
+ if err := templates.RenderToFile("generated.gotpl", cfg.Exec.Filename, build); err != nil {
+ return err
+ }
+
+ if cfg.Resolver.IsDefined() {
+ if err := generateResolver(cfg); err != nil {
+ return errors.Wrap(err, "generating resolver failed")
+ }
+ }
+
+ if err := cfg.validate(); err != nil {
+ return errors.Wrap(err, "validation failed")
+ }
+
+ return nil
+}
+
+func GenerateServer(cfg Config, filename string) error {
+ if err := cfg.Exec.normalize(); err != nil {
+ return errors.Wrap(err, "exec")
+ }
+ if err := cfg.Resolver.normalize(); err != nil {
+ return errors.Wrap(err, "resolver")
+ }
+
+ serverFilename := abs(filename)
+ serverBuild := cfg.server(filepath.Dir(serverFilename))
+
+ if _, err := os.Stat(serverFilename); os.IsNotExist(errors.Cause(err)) {
+ err = templates.RenderToFile("server.gotpl", serverFilename, serverBuild)
+ if err != nil {
+ return errors.Wrap(err, "generate server failed")
+ }
+ } else {
+ log.Printf("Skipped server: %s already exists\n", serverFilename)
+ }
+ return nil
+}
+
+func generateResolver(cfg Config) error {
+ resolverBuild, err := cfg.resolver()
+ if err != nil {
+ return errors.Wrap(err, "resolver build failed")
+ }
+ filename := cfg.Resolver.Filename
+
+ if resolverBuild.ResolverFound {
+ log.Printf("Skipped resolver: %s.%s already exists\n", cfg.Resolver.ImportPath(), cfg.Resolver.Type)
+ return nil
+ }
+
+ if _, err := os.Stat(filename); os.IsNotExist(errors.Cause(err)) {
+ if err := templates.RenderToFile("resolver.gotpl", filename, resolverBuild); err != nil {
+ return err
+ }
+ } else {
+ log.Printf("Skipped resolver: %s already exists\n", filename)
+ }
+
+ return nil
+}
+
+func (cfg *Config) normalize() error {
+ if err := cfg.Model.normalize(); err != nil {
+ return errors.Wrap(err, "model")
+ }
+
+ if err := cfg.Exec.normalize(); err != nil {
+ return errors.Wrap(err, "exec")
+ }
+
+ if cfg.Resolver.IsDefined() {
+ if err := cfg.Resolver.normalize(); err != nil {
+ return errors.Wrap(err, "resolver")
+ }
+ }
+
+ builtins := TypeMap{
+ "__Directive": {Model: "github.com/99designs/gqlgen/graphql/introspection.Directive"},
+ "__Type": {Model: "github.com/99designs/gqlgen/graphql/introspection.Type"},
+ "__Field": {Model: "github.com/99designs/gqlgen/graphql/introspection.Field"},
+ "__EnumValue": {Model: "github.com/99designs/gqlgen/graphql/introspection.EnumValue"},
+ "__InputValue": {Model: "github.com/99designs/gqlgen/graphql/introspection.InputValue"},
+ "__Schema": {Model: "github.com/99designs/gqlgen/graphql/introspection.Schema"},
+ "Int": {Model: "github.com/99designs/gqlgen/graphql.Int"},
+ "Float": {Model: "github.com/99designs/gqlgen/graphql.Float"},
+ "String": {Model: "github.com/99designs/gqlgen/graphql.String"},
+ "Boolean": {Model: "github.com/99designs/gqlgen/graphql.Boolean"},
+ "ID": {Model: "github.com/99designs/gqlgen/graphql.ID"},
+ "Time": {Model: "github.com/99designs/gqlgen/graphql.Time"},
+ "Map": {Model: "github.com/99designs/gqlgen/graphql.Map"},
+ }
+
+ if cfg.Models == nil {
+ cfg.Models = TypeMap{}
+ }
+ for typeName, entry := range builtins {
+ if !cfg.Models.Exists(typeName) {
+ cfg.Models[typeName] = entry
+ }
+ }
+
+ var err *gqlerror.Error
+ cfg.schema, err = gqlparser.LoadSchema(&ast.Source{Name: cfg.SchemaFilename, Input: cfg.SchemaStr})
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+var invalidPackageNameChar = regexp.MustCompile(`[^\w]`)
+
+func sanitizePackageName(pkg string) string {
+ return invalidPackageNameChar.ReplaceAllLiteralString(filepath.Base(pkg), "_")
+}
+
+func abs(path string) string {
+ absPath, err := filepath.Abs(path)
+ if err != nil {
+ panic(err)
+ }
+ return filepath.ToSlash(absPath)
+}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/config.go b/vendor/github.com/99designs/gqlgen/codegen/config.go
new file mode 100644
index 00000000..db0e467b
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/config.go
@@ -0,0 +1,195 @@
+package codegen
+
+import (
+ "fmt"
+ "go/build"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/99designs/gqlgen/internal/gopath"
+ "github.com/pkg/errors"
+ "github.com/vektah/gqlparser/ast"
+ "gopkg.in/yaml.v2"
+)
+
+var cfgFilenames = []string{".gqlgen.yml", "gqlgen.yml", "gqlgen.yaml"}
+
+// DefaultConfig creates a copy of the default config
+func DefaultConfig() *Config {
+ return &Config{
+ SchemaFilename: "schema.graphql",
+ Model: PackageConfig{Filename: "models_gen.go"},
+ Exec: PackageConfig{Filename: "generated.go"},
+ }
+}
+
+// LoadConfigFromDefaultLocations looks for a config file in the current directory, and all parent directories
+// walking up the tree. The closest config file will be returned.
+func LoadConfigFromDefaultLocations() (*Config, error) {
+ cfgFile, err := findCfg()
+ if err != nil {
+ return nil, err
+ }
+
+ err = os.Chdir(filepath.Dir(cfgFile))
+ if err != nil {
+ return nil, errors.Wrap(err, "unable to enter config dir")
+ }
+ return LoadConfig(cfgFile)
+}
+
+// LoadConfig reads the gqlgen.yml config file
+func LoadConfig(filename string) (*Config, error) {
+ config := DefaultConfig()
+
+ b, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return nil, errors.Wrap(err, "unable to read config")
+ }
+
+ if err := yaml.UnmarshalStrict(b, config); err != nil {
+ return nil, errors.Wrap(err, "unable to parse config")
+ }
+
+ config.FilePath = filename
+
+ return config, nil
+}
+
+type Config struct {
+ SchemaFilename string `yaml:"schema,omitempty"`
+ SchemaStr string `yaml:"-"`
+ Exec PackageConfig `yaml:"exec"`
+ Model PackageConfig `yaml:"model"`
+ Resolver PackageConfig `yaml:"resolver,omitempty"`
+ Models TypeMap `yaml:"models,omitempty"`
+ StructTag string `yaml:"struct_tag,omitempty"`
+
+ FilePath string `yaml:"-"`
+
+ schema *ast.Schema `yaml:"-"`
+}
+
+type PackageConfig struct {
+ Filename string `yaml:"filename,omitempty"`
+ Package string `yaml:"package,omitempty"`
+ Type string `yaml:"type,omitempty"`
+}
+
+type TypeMapEntry struct {
+ Model string `yaml:"model"`
+ Fields map[string]TypeMapField `yaml:"fields,omitempty"`
+}
+
+type TypeMapField struct {
+ Resolver bool `yaml:"resolver"`
+ FieldName string `yaml:"fieldName"`
+}
+
+func (c *PackageConfig) normalize() error {
+ if c.Filename == "" {
+ return errors.New("Filename is required")
+ }
+ c.Filename = abs(c.Filename)
+ // 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 == "" {
+ cwd, _ := os.Getwd()
+ pkg, _ := build.Default.Import(c.ImportPath(), cwd, 0)
+ if pkg.Name != "" {
+ c.Package = pkg.Name
+ } else {
+ c.Package = filepath.Base(c.Dir())
+ }
+ }
+ c.Package = sanitizePackageName(c.Package)
+ return nil
+}
+
+func (c *PackageConfig) ImportPath() string {
+ return gopath.MustDir2Import(c.Dir())
+}
+
+func (c *PackageConfig) Dir() string {
+ return filepath.Dir(c.Filename)
+}
+
+func (c *PackageConfig) Check() error {
+ if strings.ContainsAny(c.Package, "./\\") {
+ return fmt.Errorf("package should be the output package name only, do not include the output filename")
+ }
+ if c.Filename != "" && !strings.HasSuffix(c.Filename, ".go") {
+ return fmt.Errorf("filename should be path to a go source file")
+ }
+ return nil
+}
+
+func (c *PackageConfig) IsDefined() bool {
+ return c.Filename != ""
+}
+
+func (cfg *Config) Check() error {
+ if err := cfg.Models.Check(); err != nil {
+ return errors.Wrap(err, "config.models")
+ }
+ if err := cfg.Exec.Check(); err != nil {
+ return errors.Wrap(err, "config.exec")
+ }
+ if err := cfg.Model.Check(); err != nil {
+ return errors.Wrap(err, "config.model")
+ }
+ if err := cfg.Resolver.Check(); err != nil {
+ return errors.Wrap(err, "config.resolver")
+ }
+ return nil
+}
+
+type TypeMap map[string]TypeMapEntry
+
+func (tm TypeMap) Exists(typeName string) bool {
+ _, ok := tm[typeName]
+ return ok
+}
+
+func (tm TypeMap) Check() error {
+ for typeName, entry := range tm {
+ if strings.LastIndex(entry.Model, ".") < strings.LastIndex(entry.Model, "/") {
+ return fmt.Errorf("model %s: invalid type specifier \"%s\" - you need to specify a struct to map to", typeName, entry.Model)
+ }
+ }
+ return nil
+}
+
+// findCfg searches for the config file in this directory and all parents up the tree
+// looking for the closest match
+func findCfg() (string, error) {
+ dir, err := os.Getwd()
+ if err != nil {
+ return "", errors.Wrap(err, "unable to get working dir to findCfg")
+ }
+
+ cfg := findCfgInDir(dir)
+
+ for cfg == "" && dir != filepath.Dir(dir) {
+ dir = filepath.Dir(dir)
+ cfg = findCfgInDir(dir)
+ }
+
+ if cfg == "" {
+ return "", os.ErrNotExist
+ }
+
+ return cfg, nil
+}
+
+func findCfgInDir(dir string) string {
+ for _, cfgName := range cfgFilenames {
+ path := filepath.Join(dir, cfgName)
+ if _, err := os.Stat(path); err == nil {
+ return path
+ }
+ }
+ return ""
+}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/directive.go b/vendor/github.com/99designs/gqlgen/codegen/directive.go
new file mode 100644
index 00000000..8017da06
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/directive.go
@@ -0,0 +1,41 @@
+package codegen
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+type Directive struct {
+ Name string
+ Args []FieldArgument
+}
+
+func (d *Directive) ArgsFunc() string {
+ if len(d.Args) == 0 {
+ return ""
+ }
+
+ return "dir_" + d.Name + "_args"
+}
+
+func (d *Directive) CallArgs() string {
+ args := []string{"ctx", "obj", "n"}
+
+ for _, arg := range d.Args {
+ args = append(args, "args["+strconv.Quote(arg.GQLName)+"].("+arg.Signature()+")")
+ }
+
+ return strings.Join(args, ", ")
+}
+
+func (d *Directive) Declaration() string {
+ res := ucFirst(d.Name) + " func(ctx context.Context, obj interface{}, next graphql.Resolver"
+
+ for _, arg := range d.Args {
+ res += fmt.Sprintf(", %s %s", arg.GoVarName, arg.Signature())
+ }
+
+ res += ") (res interface{}, err error)"
+ return res
+}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/directive_build.go b/vendor/github.com/99designs/gqlgen/codegen/directive_build.go
new file mode 100644
index 00000000..32828841
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/directive_build.go
@@ -0,0 +1,49 @@
+package codegen
+
+import (
+ "sort"
+
+ "github.com/pkg/errors"
+)
+
+func (cfg *Config) buildDirectives(types NamedTypes) ([]*Directive, error) {
+ var directives []*Directive
+
+ for name, dir := range cfg.schema.Directives {
+ if name == "skip" || name == "include" || name == "deprecated" {
+ continue
+ }
+
+ var args []FieldArgument
+ for _, arg := range dir.Arguments {
+ newArg := FieldArgument{
+ GQLName: arg.Name,
+ Type: types.getType(arg.Type),
+ GoVarName: sanitizeArgName(arg.Name),
+ }
+
+ if !newArg.Type.IsInput && !newArg.Type.IsScalar {
+ return nil, errors.Errorf("%s cannot be used as argument of directive %s(%s) only input and scalar types are allowed", arg.Type, dir.Name, arg.Name)
+ }
+
+ if arg.DefaultValue != nil {
+ var err error
+ newArg.Default, err = arg.DefaultValue.Value(nil)
+ if err != nil {
+ return nil, errors.Errorf("default value for directive argument %s(%s) is not valid: %s", dir.Name, arg.Name, err.Error())
+ }
+ newArg.StripPtr()
+ }
+ args = append(args, newArg)
+ }
+
+ directives = append(directives, &Directive{
+ Name: name,
+ Args: args,
+ })
+ }
+
+ sort.Slice(directives, func(i, j int) bool { return directives[i].Name < directives[j].Name })
+
+ return directives, nil
+}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/enum.go b/vendor/github.com/99designs/gqlgen/codegen/enum.go
new file mode 100644
index 00000000..7804971c
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/enum.go
@@ -0,0 +1,12 @@
+package codegen
+
+type Enum struct {
+ *NamedType
+ Description string
+ Values []EnumValue
+}
+
+type EnumValue struct {
+ Name string
+ Description string
+}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/enum_build.go b/vendor/github.com/99designs/gqlgen/codegen/enum_build.go
new file mode 100644
index 00000000..457d923f
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/enum_build.go
@@ -0,0 +1,39 @@
+package codegen
+
+import (
+ "sort"
+ "strings"
+
+ "github.com/99designs/gqlgen/codegen/templates"
+ "github.com/vektah/gqlparser/ast"
+)
+
+func (cfg *Config) buildEnums(types NamedTypes) []Enum {
+ var enums []Enum
+
+ for _, typ := range cfg.schema.Types {
+ namedType := types[typ.Name]
+ if typ.Kind != ast.Enum || strings.HasPrefix(typ.Name, "__") || namedType.IsUserDefined {
+ continue
+ }
+
+ var values []EnumValue
+ for _, v := range typ.EnumValues {
+ values = append(values, EnumValue{v.Name, v.Description})
+ }
+
+ enum := Enum{
+ NamedType: namedType,
+ Values: values,
+ Description: typ.Description,
+ }
+ enum.GoType = templates.ToCamel(enum.GQLType)
+ enums = append(enums, enum)
+ }
+
+ sort.Slice(enums, func(i, j int) bool {
+ return enums[i].GQLType < enums[j].GQLType
+ })
+
+ return enums
+}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/import.go b/vendor/github.com/99designs/gqlgen/codegen/import.go
new file mode 100644
index 00000000..b511e8f6
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/import.go
@@ -0,0 +1,29 @@
+package codegen
+
+import (
+ "strconv"
+)
+
+type Import struct {
+ Name string
+ Path string
+
+ alias string
+}
+
+type Imports struct {
+ imports []*Import
+ destDir string
+}
+
+func (i *Import) Write() string {
+ return i.Alias() + " " + strconv.Quote(i.Path)
+}
+
+func (i *Import) Alias() string {
+ if i.alias == "" {
+ panic("alias called before imports are finalized")
+ }
+
+ return i.alias
+}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/import_build.go b/vendor/github.com/99designs/gqlgen/codegen/import_build.go
new file mode 100644
index 00000000..d634834e
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/import_build.go
@@ -0,0 +1,120 @@
+package codegen
+
+import (
+ "fmt"
+ "go/build"
+ "sort"
+ "strconv"
+
+ // Import and ignore the ambient imports listed below so dependency managers
+ // don't prune unused code for us. Both lists should be kept in sync.
+ _ "github.com/99designs/gqlgen/graphql"
+ _ "github.com/99designs/gqlgen/graphql/introspection"
+ "github.com/99designs/gqlgen/internal/gopath"
+ _ "github.com/vektah/gqlparser"
+ _ "github.com/vektah/gqlparser/ast"
+)
+
+// These imports are referenced by the generated code, and are assumed to have the
+// default alias. So lets make sure they get added first, and any later collisions get
+// renamed.
+var ambientImports = []string{
+ "context",
+ "fmt",
+ "io",
+ "strconv",
+ "time",
+ "sync",
+ "errors",
+
+ "github.com/vektah/gqlparser",
+ "github.com/vektah/gqlparser/ast",
+ "github.com/99designs/gqlgen/graphql",
+ "github.com/99designs/gqlgen/graphql/introspection",
+}
+
+func buildImports(types NamedTypes, destDir string) *Imports {
+ imports := Imports{
+ destDir: destDir,
+ }
+
+ for _, ambient := range ambientImports {
+ imports.add(ambient)
+ }
+
+ // Imports from top level user types
+ for _, t := range types {
+ t.Import = imports.add(t.Package)
+ }
+
+ return &imports
+}
+
+func (s *Imports) add(path string) *Import {
+ if path == "" {
+ return nil
+ }
+
+ // if we are referencing our own package we dont need an import
+ if gopath.MustDir2Import(s.destDir) == path {
+ return nil
+ }
+
+ if existing := s.findByPath(path); existing != nil {
+ return existing
+ }
+
+ pkg, err := build.Default.Import(path, s.destDir, 0)
+ if err != nil {
+ panic(err)
+ }
+
+ imp := &Import{
+ Name: pkg.Name,
+ Path: path,
+ }
+ s.imports = append(s.imports, imp)
+
+ return imp
+}
+
+func (s Imports) finalize() []*Import {
+ // ensure stable ordering by sorting
+ sort.Slice(s.imports, func(i, j int) bool {
+ return s.imports[i].Path > s.imports[j].Path
+ })
+
+ for _, imp := range s.imports {
+ alias := imp.Name
+
+ i := 1
+ for s.findByAlias(alias) != nil {
+ alias = imp.Name + strconv.Itoa(i)
+ i++
+ if i > 10 {
+ panic(fmt.Errorf("too many collisions, last attempt was %s", alias))
+ }
+ }
+ imp.alias = alias
+ }
+
+ return s.imports
+}
+
+func (s Imports) findByPath(importPath string) *Import {
+ for _, imp := range s.imports {
+ if imp.Path == importPath {
+ return imp
+ }
+ }
+ return nil
+}
+
+func (s Imports) findByAlias(alias string) *Import {
+ for _, imp := range s.imports {
+ if imp.alias == alias {
+ return imp
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/input_build.go b/vendor/github.com/99designs/gqlgen/codegen/input_build.go
new file mode 100644
index 00000000..06ff37a0
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/input_build.go
@@ -0,0 +1,96 @@
+package codegen
+
+import (
+ "go/types"
+ "sort"
+
+ "github.com/pkg/errors"
+ "github.com/vektah/gqlparser/ast"
+ "golang.org/x/tools/go/loader"
+)
+
+func (cfg *Config) buildInputs(namedTypes NamedTypes, prog *loader.Program, imports *Imports) (Objects, error) {
+ var inputs Objects
+
+ for _, typ := range cfg.schema.Types {
+ switch typ.Kind {
+ case ast.InputObject:
+ input, err := cfg.buildInput(namedTypes, typ)
+ if err != nil {
+ return nil, err
+ }
+
+ def, err := findGoType(prog, input.Package, input.GoType)
+ if err != nil {
+ return nil, errors.Wrap(err, "cannot find type")
+ }
+ if def != nil {
+ input.Marshaler = buildInputMarshaler(typ, def)
+ bindErrs := bindObject(def.Type(), input, imports, cfg.StructTag)
+ if len(bindErrs) > 0 {
+ return nil, bindErrs
+ }
+ }
+
+ inputs = append(inputs, input)
+ }
+ }
+
+ sort.Slice(inputs, func(i, j int) bool {
+ return inputs[i].GQLType < inputs[j].GQLType
+ })
+
+ return inputs, nil
+}
+
+func (cfg *Config) buildInput(types NamedTypes, typ *ast.Definition) (*Object, error) {
+ obj := &Object{NamedType: types[typ.Name]}
+ typeEntry, entryExists := cfg.Models[typ.Name]
+
+ for _, field := range typ.Fields {
+ newField := Field{
+ GQLName: field.Name,
+ Type: types.getType(field.Type),
+ Object: obj,
+ }
+
+ if entryExists {
+ if typeField, ok := typeEntry.Fields[field.Name]; ok {
+ newField.GoFieldName = typeField.FieldName
+ }
+ }
+
+ if field.DefaultValue != nil {
+ var err error
+ newField.Default, err = field.DefaultValue.Value(nil)
+ if err != nil {
+ return nil, errors.Errorf("default value for %s.%s is not valid: %s", typ.Name, field.Name, err.Error())
+ }
+ }
+
+ if !newField.Type.IsInput && !newField.Type.IsScalar {
+ return nil, errors.Errorf("%s cannot be used as a field of %s. only input and scalar types are allowed", newField.GQLType, obj.GQLType)
+ }
+
+ obj.Fields = append(obj.Fields, newField)
+
+ }
+ return obj, nil
+}
+
+// if user has implemented an UnmarshalGQL method on the input type manually, use it
+// otherwise we will generate one.
+func buildInputMarshaler(typ *ast.Definition, def types.Object) *Ref {
+ switch def := def.(type) {
+ case *types.TypeName:
+ namedType := def.Type().(*types.Named)
+ for i := 0; i < namedType.NumMethods(); i++ {
+ method := namedType.Method(i)
+ if method.Name() == "UnmarshalGQL" {
+ return nil
+ }
+ }
+ }
+
+ return &Ref{GoType: typ.Name}
+}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/interface.go b/vendor/github.com/99designs/gqlgen/codegen/interface.go
new file mode 100644
index 00000000..2de0c88a
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/interface.go
@@ -0,0 +1,13 @@
+package codegen
+
+type Interface struct {
+ *NamedType
+
+ Implementors []InterfaceImplementor
+}
+
+type InterfaceImplementor struct {
+ ValueReceiver bool
+
+ *NamedType
+}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/interface_build.go b/vendor/github.com/99designs/gqlgen/codegen/interface_build.go
new file mode 100644
index 00000000..9f4a4ff4
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/interface_build.go
@@ -0,0 +1,70 @@
+package codegen
+
+import (
+ "fmt"
+ "go/types"
+ "os"
+ "sort"
+
+ "github.com/vektah/gqlparser/ast"
+ "golang.org/x/tools/go/loader"
+)
+
+func (cfg *Config) buildInterfaces(types NamedTypes, prog *loader.Program) []*Interface {
+ var interfaces []*Interface
+ for _, typ := range cfg.schema.Types {
+ if typ.Kind == ast.Union || typ.Kind == ast.Interface {
+ interfaces = append(interfaces, cfg.buildInterface(types, typ, prog))
+ }
+ }
+
+ sort.Slice(interfaces, func(i, j int) bool {
+ return interfaces[i].GQLType < interfaces[j].GQLType
+ })
+
+ return interfaces
+}
+
+func (cfg *Config) buildInterface(types NamedTypes, typ *ast.Definition, prog *loader.Program) *Interface {
+ i := &Interface{NamedType: types[typ.Name]}
+
+ for _, implementor := range cfg.schema.GetPossibleTypes(typ) {
+ t := types[implementor.Name]
+
+ i.Implementors = append(i.Implementors, InterfaceImplementor{
+ NamedType: t,
+ ValueReceiver: cfg.isValueReceiver(types[typ.Name], t, prog),
+ })
+ }
+
+ return i
+}
+
+func (cfg *Config) isValueReceiver(intf *NamedType, implementor *NamedType, prog *loader.Program) bool {
+ interfaceType, err := findGoInterface(prog, intf.Package, intf.GoType)
+ if interfaceType == nil || err != nil {
+ return true
+ }
+
+ implementorType, err := findGoNamedType(prog, implementor.Package, implementor.GoType)
+ if implementorType == nil || err != nil {
+ return true
+ }
+
+ for i := 0; i < interfaceType.NumMethods(); i++ {
+ intfMethod := interfaceType.Method(i)
+
+ implMethod := findMethod(implementorType, intfMethod.Name())
+ if implMethod == nil {
+ fmt.Fprintf(os.Stderr, "missing method %s on %s\n", intfMethod.Name(), implementor.GoType)
+ return false
+ }
+
+ sig := implMethod.Type().(*types.Signature)
+ if _, isPtr := sig.Recv().Type().(*types.Pointer); isPtr {
+ return false
+ }
+ }
+
+ return true
+}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/model.go b/vendor/github.com/99designs/gqlgen/codegen/model.go
new file mode 100644
index 00000000..5ba50337
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/model.go
@@ -0,0 +1,16 @@
+package codegen
+
+type Model struct {
+ *NamedType
+ Description string
+ Fields []ModelField
+}
+
+type ModelField struct {
+ *Type
+ GQLName string
+ GoFieldName string
+ GoFKName string
+ GoFKType string
+ Description string
+}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/models_build.go b/vendor/github.com/99designs/gqlgen/codegen/models_build.go
new file mode 100644
index 00000000..9f98a07d
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/models_build.go
@@ -0,0 +1,90 @@
+package codegen
+
+import (
+ "sort"
+
+ "github.com/vektah/gqlparser/ast"
+ "golang.org/x/tools/go/loader"
+)
+
+func (cfg *Config) buildModels(types NamedTypes, prog *loader.Program, imports *Imports) ([]Model, error) {
+ var models []Model
+
+ for _, typ := range cfg.schema.Types {
+ var model Model
+ switch typ.Kind {
+ case ast.Object:
+ obj, err := cfg.buildObject(types, typ, imports)
+ if err != nil {
+ return nil, err
+ }
+ if obj.Root || obj.IsUserDefined {
+ continue
+ }
+ model = cfg.obj2Model(obj)
+ case ast.InputObject:
+ obj, err := cfg.buildInput(types, typ)
+ if err != nil {
+ return nil, err
+ }
+ if obj.IsUserDefined {
+ continue
+ }
+ model = cfg.obj2Model(obj)
+ case ast.Interface, ast.Union:
+ intf := cfg.buildInterface(types, typ, prog)
+ if intf.IsUserDefined {
+ continue
+ }
+ model = int2Model(intf)
+ default:
+ continue
+ }
+ model.Description = typ.Description // It's this or change both obj2Model and buildObject
+
+ models = append(models, model)
+ }
+
+ sort.Slice(models, func(i, j int) bool {
+ return models[i].GQLType < models[j].GQLType
+ })
+
+ return models, nil
+}
+
+func (cfg *Config) obj2Model(obj *Object) Model {
+ model := Model{
+ NamedType: obj.NamedType,
+ Fields: []ModelField{},
+ }
+
+ model.GoType = ucFirst(obj.GQLType)
+ model.Marshaler = &Ref{GoType: obj.GoType}
+
+ for i := range obj.Fields {
+ field := &obj.Fields[i]
+ mf := ModelField{Type: field.Type, GQLName: field.GQLName}
+
+ if field.GoFieldName != "" {
+ mf.GoFieldName = field.GoFieldName
+ } else {
+ mf.GoFieldName = field.GoNameExported()
+ }
+
+ model.Fields = append(model.Fields, mf)
+ }
+
+ return model
+}
+
+func int2Model(obj *Interface) Model {
+ model := Model{
+ NamedType: obj.NamedType,
+ Fields: []ModelField{},
+ }
+
+ model.GoType = ucFirst(obj.GQLType)
+ model.Marshaler = &Ref{GoType: obj.GoType}
+
+ return model
+}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/object.go b/vendor/github.com/99designs/gqlgen/codegen/object.go
new file mode 100644
index 00000000..d9f610f4
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/object.go
@@ -0,0 +1,464 @@
+package codegen
+
+import (
+ "bytes"
+ "fmt"
+ "strconv"
+ "strings"
+ "text/template"
+ "unicode"
+
+ "github.com/vektah/gqlparser/ast"
+)
+
+type GoFieldType int
+
+const (
+ GoFieldUndefined GoFieldType = iota
+ GoFieldMethod
+ GoFieldVariable
+)
+
+type Object struct {
+ *NamedType
+
+ Fields []Field
+ Satisfies []string
+ ResolverInterface *Ref
+ Root bool
+ DisableConcurrency bool
+ Stream bool
+}
+
+type Field struct {
+ *Type
+ Description string // Description of a field
+ GQLName string // The name of the field in graphql
+ GoFieldType GoFieldType // The field type in go, if any
+ GoReceiverName string // The name of method & var receiver in go, if any
+ GoFieldName string // The name of the method or var in go, if any
+ Args []FieldArgument // A list of arguments to be passed to this field
+ ForceResolver bool // Should be emit Resolver method
+ NoErr bool // If this is bound to a go method, does that method have an error as the second argument
+ Object *Object // A link back to the parent object
+ Default interface{} // The default value
+}
+
+type FieldArgument struct {
+ *Type
+
+ GQLName string // The name of the argument in graphql
+ GoVarName string // The name of the var in go
+ Object *Object // A link back to the parent object
+ Default interface{} // The default value
+}
+
+type Objects []*Object
+
+func (o *Object) Implementors() string {
+ satisfiedBy := strconv.Quote(o.GQLType)
+ for _, s := range o.Satisfies {
+ satisfiedBy += ", " + strconv.Quote(s)
+ }
+ return "[]string{" + satisfiedBy + "}"
+}
+
+func (o *Object) HasResolvers() bool {
+ for _, f := range o.Fields {
+ if f.IsResolver() {
+ return true
+ }
+ }
+ return false
+}
+
+func (o *Object) IsConcurrent() bool {
+ for _, f := range o.Fields {
+ if f.IsConcurrent() {
+ return true
+ }
+ }
+ return false
+}
+
+func (o *Object) IsReserved() bool {
+ return strings.HasPrefix(o.GQLType, "__")
+}
+
+func (f *Field) IsResolver() bool {
+ return f.GoFieldName == ""
+}
+
+func (f *Field) IsReserved() bool {
+ return strings.HasPrefix(f.GQLName, "__")
+}
+
+func (f *Field) IsMethod() bool {
+ return f.GoFieldType == GoFieldMethod
+}
+
+func (f *Field) IsVariable() bool {
+ return f.GoFieldType == GoFieldVariable
+}
+
+func (f *Field) IsConcurrent() bool {
+ return f.IsResolver() && !f.Object.DisableConcurrency
+}
+
+func (f *Field) GoNameExported() string {
+ return lintName(ucFirst(f.GQLName))
+}
+
+func (f *Field) GoNameUnexported() string {
+ return lintName(f.GQLName)
+}
+
+func (f *Field) ShortInvocation() string {
+ if !f.IsResolver() {
+ return ""
+ }
+
+ return fmt.Sprintf("%s().%s(%s)", f.Object.GQLType, f.GoNameExported(), f.CallArgs())
+}
+
+func (f *Field) ArgsFunc() string {
+ if len(f.Args) == 0 {
+ return ""
+ }
+
+ return "field_" + f.Object.GQLType + "_" + f.GQLName + "_args"
+}
+
+func (f *Field) ResolverType() string {
+ if !f.IsResolver() {
+ return ""
+ }
+
+ return fmt.Sprintf("%s().%s(%s)", f.Object.GQLType, f.GoNameExported(), f.CallArgs())
+}
+
+func (f *Field) ShortResolverDeclaration() string {
+ if !f.IsResolver() {
+ return ""
+ }
+ res := fmt.Sprintf("%s(ctx context.Context", f.GoNameExported())
+
+ if !f.Object.Root {
+ res += fmt.Sprintf(", obj *%s", f.Object.FullName())
+ }
+ for _, arg := range f.Args {
+ res += fmt.Sprintf(", %s %s", arg.GoVarName, arg.Signature())
+ }
+
+ result := f.Signature()
+ if f.Object.Stream {
+ result = "<-chan " + result
+ }
+
+ res += fmt.Sprintf(") (%s, error)", result)
+ return res
+}
+
+func (f *Field) ResolverDeclaration() string {
+ if !f.IsResolver() {
+ return ""
+ }
+ res := fmt.Sprintf("%s_%s(ctx context.Context", f.Object.GQLType, f.GoNameUnexported())
+
+ if !f.Object.Root {
+ res += fmt.Sprintf(", obj *%s", f.Object.FullName())
+ }
+ for _, arg := range f.Args {
+ res += fmt.Sprintf(", %s %s", arg.GoVarName, arg.Signature())
+ }
+
+ result := f.Signature()
+ if f.Object.Stream {
+ result = "<-chan " + result
+ }
+
+ res += fmt.Sprintf(") (%s, error)", result)
+ return res
+}
+
+func (f *Field) ComplexitySignature() string {
+ res := fmt.Sprintf("func(childComplexity int")
+ for _, arg := range f.Args {
+ res += fmt.Sprintf(", %s %s", arg.GoVarName, arg.Signature())
+ }
+ res += ") int"
+ return res
+}
+
+func (f *Field) ComplexityArgs() string {
+ var args []string
+ for _, arg := range f.Args {
+ args = append(args, "args["+strconv.Quote(arg.GQLName)+"].("+arg.Signature()+")")
+ }
+
+ return strings.Join(args, ", ")
+}
+
+func (f *Field) CallArgs() string {
+ var args []string
+
+ if f.IsResolver() {
+ args = append(args, "ctx")
+
+ if !f.Object.Root {
+ args = append(args, "obj")
+ }
+ }
+
+ for _, arg := range f.Args {
+ args = append(args, "args["+strconv.Quote(arg.GQLName)+"].("+arg.Signature()+")")
+ }
+
+ return strings.Join(args, ", ")
+}
+
+// should be in the template, but its recursive and has a bunch of args
+func (f *Field) WriteJson() string {
+ return f.doWriteJson("res", f.Type.Modifiers, f.ASTType, false, 1)
+}
+
+func (f *Field) doWriteJson(val string, remainingMods []string, astType *ast.Type, isPtr bool, depth int) string {
+ switch {
+ case len(remainingMods) > 0 && remainingMods[0] == modPtr:
+ return tpl(`
+ if {{.val}} == nil {
+ {{- if .nonNull }}
+ if !ec.HasError(rctx) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ {{- end }}
+ return graphql.Null
+ }
+ {{.next }}`, map[string]interface{}{
+ "val": val,
+ "nonNull": astType.NonNull,
+ "next": f.doWriteJson(val, remainingMods[1:], astType, true, depth+1),
+ })
+
+ case len(remainingMods) > 0 && remainingMods[0] == modList:
+ if isPtr {
+ val = "*" + val
+ }
+ var arr = "arr" + strconv.Itoa(depth)
+ var index = "idx" + strconv.Itoa(depth)
+ var usePtr bool
+ if len(remainingMods) == 1 && !isPtr {
+ usePtr = true
+ }
+
+ return tpl(`
+ {{.arr}} := make(graphql.Array, len({{.val}}))
+ {{ if and .top (not .isScalar) }} var wg sync.WaitGroup {{ end }}
+ {{ if not .isScalar }}
+ isLen1 := len({{.val}}) == 1
+ if !isLen1 {
+ wg.Add(len({{.val}}))
+ }
+ {{ end }}
+ for {{.index}} := range {{.val}} {
+ {{- if not .isScalar }}
+ {{.index}} := {{.index}}
+ rctx := &graphql.ResolverContext{
+ Index: &{{.index}},
+ Result: {{ if .usePtr }}&{{end}}{{.val}}[{{.index}}],
+ }
+ ctx := graphql.WithResolverContext(ctx, rctx)
+ f := func({{.index}} int) {
+ if !isLen1 {
+ defer wg.Done()
+ }
+ {{.arr}}[{{.index}}] = func() graphql.Marshaler {
+ {{ .next }}
+ }()
+ }
+ if isLen1 {
+ f({{.index}})
+ } else {
+ go f({{.index}})
+ }
+ {{ else }}
+ {{.arr}}[{{.index}}] = func() graphql.Marshaler {
+ {{ .next }}
+ }()
+ {{- end}}
+ }
+ {{ if and .top (not .isScalar) }} wg.Wait() {{ end }}
+ return {{.arr}}`, map[string]interface{}{
+ "val": val,
+ "arr": arr,
+ "index": index,
+ "top": depth == 1,
+ "arrayLen": len(val),
+ "isScalar": f.IsScalar,
+ "usePtr": usePtr,
+ "next": f.doWriteJson(val+"["+index+"]", remainingMods[1:], astType.Elem, false, depth+1),
+ })
+
+ case f.IsScalar:
+ if isPtr {
+ val = "*" + val
+ }
+ return f.Marshal(val)
+
+ default:
+ if !isPtr {
+ val = "&" + val
+ }
+ return tpl(`
+ return ec._{{.type}}(ctx, field.Selections, {{.val}})`, map[string]interface{}{
+ "type": f.GQLType,
+ "val": val,
+ })
+ }
+}
+
+func (f *FieldArgument) Stream() bool {
+ return f.Object != nil && f.Object.Stream
+}
+
+func (os Objects) ByName(name string) *Object {
+ for i, o := range os {
+ if strings.EqualFold(o.GQLType, name) {
+ return os[i]
+ }
+ }
+ return nil
+}
+
+func tpl(tpl string, vars map[string]interface{}) string {
+ b := &bytes.Buffer{}
+ err := template.Must(template.New("inline").Parse(tpl)).Execute(b, vars)
+ if err != nil {
+ panic(err)
+ }
+ return b.String()
+}
+
+func ucFirst(s string) string {
+ if s == "" {
+ return ""
+ }
+
+ r := []rune(s)
+ r[0] = unicode.ToUpper(r[0])
+ return string(r)
+}
+
+// copy from https://github.com/golang/lint/blob/06c8688daad7faa9da5a0c2f163a3d14aac986ca/lint.go#L679
+
+// lintName returns a different name if it should be different.
+func lintName(name string) (should string) {
+ // Fast path for simple cases: "_" and all lowercase.
+ if name == "_" {
+ return name
+ }
+ allLower := true
+ for _, r := range name {
+ if !unicode.IsLower(r) {
+ allLower = false
+ break
+ }
+ }
+ if allLower {
+ return name
+ }
+
+ // Split camelCase at any lower->upper transition, and split on underscores.
+ // Check each word for common initialisms.
+ runes := []rune(name)
+ w, i := 0, 0 // index of start of word, scan
+ for i+1 <= len(runes) {
+ eow := false // whether we hit the end of a word
+ if i+1 == len(runes) {
+ eow = true
+ } else if runes[i+1] == '_' {
+ // underscore; shift the remainder forward over any run of underscores
+ eow = true
+ n := 1
+ for i+n+1 < len(runes) && runes[i+n+1] == '_' {
+ n++
+ }
+
+ // Leave at most one underscore if the underscore is between two digits
+ if i+n+1 < len(runes) && unicode.IsDigit(runes[i]) && unicode.IsDigit(runes[i+n+1]) {
+ n--
+ }
+
+ copy(runes[i+1:], runes[i+n+1:])
+ runes = runes[:len(runes)-n]
+ } else if unicode.IsLower(runes[i]) && !unicode.IsLower(runes[i+1]) {
+ // lower->non-lower
+ eow = true
+ }
+ i++
+ if !eow {
+ continue
+ }
+
+ // [w,i) is a word.
+ word := string(runes[w:i])
+ if u := strings.ToUpper(word); commonInitialisms[u] {
+ // Keep consistent case, which is lowercase only at the start.
+ if w == 0 && unicode.IsLower(runes[w]) {
+ u = strings.ToLower(u)
+ }
+ // All the common initialisms are ASCII,
+ // so we can replace the bytes exactly.
+ copy(runes[w:], []rune(u))
+ } else if w > 0 && strings.ToLower(word) == word {
+ // already all lowercase, and not the first word, so uppercase the first character.
+ runes[w] = unicode.ToUpper(runes[w])
+ }
+ w = i
+ }
+ return string(runes)
+}
+
+// commonInitialisms is a set of common initialisms.
+// Only add entries that are highly unlikely to be non-initialisms.
+// For instance, "ID" is fine (Freudian code is rare), but "AND" is not.
+var commonInitialisms = map[string]bool{
+ "ACL": true,
+ "API": true,
+ "ASCII": true,
+ "CPU": true,
+ "CSS": true,
+ "DNS": true,
+ "EOF": true,
+ "GUID": true,
+ "HTML": true,
+ "HTTP": true,
+ "HTTPS": true,
+ "ID": true,
+ "IP": true,
+ "JSON": true,
+ "LHS": true,
+ "QPS": true,
+ "RAM": true,
+ "RHS": true,
+ "RPC": true,
+ "SLA": true,
+ "SMTP": true,
+ "SQL": true,
+ "SSH": true,
+ "TCP": true,
+ "TLS": true,
+ "TTL": true,
+ "UDP": true,
+ "UI": true,
+ "UID": true,
+ "UUID": true,
+ "URI": true,
+ "URL": true,
+ "UTF8": true,
+ "VM": true,
+ "XML": true,
+ "XMPP": true,
+ "XSRF": true,
+ "XSS": true,
+}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/object_build.go b/vendor/github.com/99designs/gqlgen/codegen/object_build.go
new file mode 100644
index 00000000..ee2b2f1c
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/object_build.go
@@ -0,0 +1,181 @@
+package codegen
+
+import (
+ "log"
+ "sort"
+
+ "github.com/pkg/errors"
+ "github.com/vektah/gqlparser/ast"
+ "golang.org/x/tools/go/loader"
+)
+
+func (cfg *Config) buildObjects(types NamedTypes, prog *loader.Program, imports *Imports) (Objects, error) {
+ var objects Objects
+
+ for _, typ := range cfg.schema.Types {
+ if typ.Kind != ast.Object {
+ continue
+ }
+
+ obj, err := cfg.buildObject(types, typ, imports)
+ if err != nil {
+ return nil, err
+ }
+
+ def, err := findGoType(prog, obj.Package, obj.GoType)
+ if err != nil {
+ return nil, err
+ }
+ if def != nil {
+ for _, bindErr := range bindObject(def.Type(), obj, imports, cfg.StructTag) {
+ log.Println(bindErr.Error())
+ log.Println(" Adding resolver method")
+ }
+ }
+
+ objects = append(objects, obj)
+ }
+
+ sort.Slice(objects, func(i, j int) bool {
+ return objects[i].GQLType < objects[j].GQLType
+ })
+
+ return objects, nil
+}
+
+var keywords = []string{
+ "break",
+ "default",
+ "func",
+ "interface",
+ "select",
+ "case",
+ "defer",
+ "go",
+ "map",
+ "struct",
+ "chan",
+ "else",
+ "goto",
+ "package",
+ "switch",
+ "const",
+ "fallthrough",
+ "if",
+ "range",
+ "type",
+ "continue",
+ "for",
+ "import",
+ "return",
+ "var",
+}
+
+// sanitizeArgName prevents collisions with go keywords for arguments to resolver functions
+func sanitizeArgName(name string) string {
+ for _, k := range keywords {
+ if name == k {
+ return name + "Arg"
+ }
+ }
+ return name
+}
+
+func (cfg *Config) buildObject(types NamedTypes, typ *ast.Definition, imports *Imports) (*Object, error) {
+ obj := &Object{NamedType: types[typ.Name]}
+ typeEntry, entryExists := cfg.Models[typ.Name]
+
+ imp := imports.findByPath(cfg.Exec.ImportPath())
+ obj.ResolverInterface = &Ref{GoType: obj.GQLType + "Resolver", Import: imp}
+
+ if typ == cfg.schema.Query {
+ obj.Root = true
+ }
+
+ if typ == cfg.schema.Mutation {
+ obj.Root = true
+ obj.DisableConcurrency = true
+ }
+
+ if typ == cfg.schema.Subscription {
+ obj.Root = true
+ obj.Stream = true
+ }
+
+ obj.Satisfies = append(obj.Satisfies, typ.Interfaces...)
+
+ for _, field := range typ.Fields {
+ if typ == cfg.schema.Query && field.Name == "__type" {
+ obj.Fields = append(obj.Fields, Field{
+ Type: &Type{types["__Schema"], []string{modPtr}, ast.NamedType("__Schema", nil), nil},
+ GQLName: "__schema",
+ NoErr: true,
+ GoFieldType: GoFieldMethod,
+ GoReceiverName: "ec",
+ GoFieldName: "introspectSchema",
+ Object: obj,
+ Description: field.Description,
+ })
+ continue
+ }
+ if typ == cfg.schema.Query && field.Name == "__schema" {
+ obj.Fields = append(obj.Fields, Field{
+ Type: &Type{types["__Type"], []string{modPtr}, ast.NamedType("__Schema", nil), nil},
+ GQLName: "__type",
+ NoErr: true,
+ GoFieldType: GoFieldMethod,
+ GoReceiverName: "ec",
+ GoFieldName: "introspectType",
+ Args: []FieldArgument{
+ {GQLName: "name", Type: &Type{types["String"], []string{}, ast.NamedType("String", nil), nil}, Object: &Object{}},
+ },
+ Object: obj,
+ })
+ continue
+ }
+
+ var forceResolver bool
+ var goName string
+ if entryExists {
+ if typeField, ok := typeEntry.Fields[field.Name]; ok {
+ goName = typeField.FieldName
+ forceResolver = typeField.Resolver
+ }
+ }
+
+ var args []FieldArgument
+ for _, arg := range field.Arguments {
+ newArg := FieldArgument{
+ GQLName: arg.Name,
+ Type: types.getType(arg.Type),
+ Object: obj,
+ GoVarName: sanitizeArgName(arg.Name),
+ }
+
+ if !newArg.Type.IsInput && !newArg.Type.IsScalar {
+ return nil, errors.Errorf("%s cannot be used as argument of %s.%s. only input and scalar types are allowed", arg.Type, obj.GQLType, field.Name)
+ }
+
+ if arg.DefaultValue != nil {
+ var err error
+ newArg.Default, err = arg.DefaultValue.Value(nil)
+ if err != nil {
+ return nil, errors.Errorf("default value for %s.%s is not valid: %s", typ.Name, field.Name, err.Error())
+ }
+ newArg.StripPtr()
+ }
+ args = append(args, newArg)
+ }
+
+ obj.Fields = append(obj.Fields, Field{
+ GQLName: field.Name,
+ Type: types.getType(field.Type),
+ Args: args,
+ Object: obj,
+ GoFieldName: goName,
+ ForceResolver: forceResolver,
+ })
+ }
+
+ return obj, nil
+}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/templates/args.gotpl b/vendor/github.com/99designs/gqlgen/codegen/templates/args.gotpl
new file mode 100644
index 00000000..870a99ed
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/templates/args.gotpl
@@ -0,0 +1,13 @@
+ args := map[string]interface{}{}
+ {{- range $i, $arg := . }}
+ var arg{{$i}} {{$arg.Signature }}
+ if tmp, ok := rawArgs[{{$arg.GQLName|quote}}]; ok {
+ var err error
+ {{$arg.Unmarshal (print "arg" $i) "tmp" }}
+ if err != nil {
+ return nil, err
+ }
+ }
+ args[{{$arg.GQLName|quote}}] = arg{{$i}}
+ {{- end }}
+ return args, nil
diff --git a/vendor/github.com/99designs/gqlgen/codegen/templates/data.go b/vendor/github.com/99designs/gqlgen/codegen/templates/data.go
new file mode 100644
index 00000000..d168fa31
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/templates/data.go
@@ -0,0 +1,13 @@
+package templates
+
+var data = map[string]string{
+ "args.gotpl": "\targs := map[string]interface{}{}\n\t{{- range $i, $arg := . }}\n\t\tvar arg{{$i}} {{$arg.Signature }}\n\t\tif tmp, ok := rawArgs[{{$arg.GQLName|quote}}]; ok {\n\t\t\tvar err error\n\t\t\t{{$arg.Unmarshal (print \"arg\" $i) \"tmp\" }}\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t}\n\t\targs[{{$arg.GQLName|quote}}] = arg{{$i}}\n\t{{- end }}\n\treturn args, nil\n",
+ "field.gotpl": "{{ $field := . }}\n{{ $object := $field.Object }}\n\n{{- if $object.Stream }}\n\tfunc (ec *executionContext) _{{$object.GQLType}}_{{$field.GQLName}}(ctx context.Context, field graphql.CollectedField) func() graphql.Marshaler {\n\t\t{{- if $field.Args }}\n\t\t\trawArgs := field.ArgumentMap(ec.Variables)\n\t\t\targs, err := {{ $field.ArgsFunc }}(rawArgs)\n\t\t\tif err != nil {\n\t\t\t\tec.Error(ctx, err)\n\t\t\t\treturn nil\n\t\t\t}\n\t\t{{- end }}\n\t\tctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{\n\t\t\tField: field,\n\t\t})\n\t\tresults, err := ec.resolvers.{{ $field.ShortInvocation }}\n\t\tif err != nil {\n\t\t\tec.Error(ctx, err)\n\t\t\treturn nil\n\t\t}\n\t\treturn func() graphql.Marshaler {\n\t\t\tres, ok := <-results\n\t\t\tif !ok {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\tvar out graphql.OrderedMap\n\t\t\tout.Add(field.Alias, func() graphql.Marshaler { {{ $field.WriteJson }} }())\n\t\t\treturn &out\n\t\t}\n\t}\n{{ else }}\n\t// nolint: vetshadow\n\tfunc (ec *executionContext) _{{$object.GQLType}}_{{$field.GQLName}}(ctx context.Context, field graphql.CollectedField, {{if not $object.Root}}obj *{{$object.FullName}}{{end}}) graphql.Marshaler {\n\t\t{{- if $field.Args }}\n\t\t\trawArgs := field.ArgumentMap(ec.Variables)\n\t\t\targs, err := {{ $field.ArgsFunc }}(rawArgs)\n\t\t\tif err != nil {\n\t\t\t\tec.Error(ctx, err)\n\t\t\t\treturn graphql.Null\n\t\t\t}\n\t\t{{- end }}\n\t\trctx := &graphql.ResolverContext{\n\t\t\tObject: {{$object.GQLType|quote}},\n\t\t\tArgs: {{if $field.Args }}args{{else}}nil{{end}},\n\t\t\tField: field,\n\t\t}\n\t\tctx = graphql.WithResolverContext(ctx, rctx)\n\t\tresTmp := ec.FieldMiddleware(ctx, {{if $object.Root}}nil{{else}}obj{{end}}, func(ctx context.Context) (interface{}, error) {\n\t\t\t{{- if $field.IsResolver }}\n\t\t\t\treturn ec.resolvers.{{ $field.ShortInvocation }}\n\t\t\t{{- else if $field.IsMethod }}\n\t\t\t\t{{- if $field.NoErr }}\n\t\t\t\t\treturn {{$field.GoReceiverName}}.{{$field.GoFieldName}}({{ $field.CallArgs }}), nil\n\t\t\t\t{{- else }}\n\t\t\t\t\treturn {{$field.GoReceiverName}}.{{$field.GoFieldName}}({{ $field.CallArgs }})\n\t\t\t\t{{- end }}\n\t\t\t{{- else if $field.IsVariable }}\n\t\t\t\treturn {{$field.GoReceiverName}}.{{$field.GoFieldName}}, nil\n\t\t\t{{- end }}\n\t\t})\n\t\tif resTmp == nil {\n\t\t\t{{- if $field.ASTType.NonNull }}\n\t\t\t\tif !ec.HasError(rctx) {\n\t\t\t\t\tec.Errorf(ctx, \"must not be null\")\n\t\t\t\t}\n\t\t\t{{- end }}\n\t\t\treturn graphql.Null\n\t\t}\n\t\tres := resTmp.({{$field.Signature}})\n\t\trctx.Result = res\n\t\t{{ $field.WriteJson }}\n\t}\n{{ end }}\n",
+ "generated.gotpl": "// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.\n\npackage {{ .PackageName }}\n\nimport (\n{{- range $import := .Imports }}\n\t{{- $import.Write }}\n{{ end }}\n)\n\n// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.\nfunc NewExecutableSchema(cfg Config) graphql.ExecutableSchema {\n\treturn &executableSchema{\n\t\tresolvers: cfg.Resolvers,\n\t\tdirectives: cfg.Directives,\n\t\tcomplexity: cfg.Complexity,\n\t}\n}\n\ntype Config struct {\n\tResolvers ResolverRoot\n\tDirectives DirectiveRoot\n\tComplexity ComplexityRoot\n}\n\ntype ResolverRoot interface {\n{{- range $object := .Objects -}}\n\t{{ if $object.HasResolvers -}}\n\t\t{{$object.GQLType}}() {{$object.GQLType}}Resolver\n\t{{ end }}\n{{- end }}\n}\n\ntype DirectiveRoot struct {\n{{ range $directive := .Directives }}\n\t{{ $directive.Declaration }}\n{{ end }}\n}\n\ntype ComplexityRoot struct {\n{{ range $object := .Objects }}\n\t{{ if not $object.IsReserved -}}\n\t\t{{ $object.GQLType|toCamel }} struct {\n\t\t{{ range $field := $object.Fields -}}\n\t\t\t{{ if not $field.IsReserved -}}\n\t\t\t\t{{ $field.GQLName|toCamel }} {{ $field.ComplexitySignature }}\n\t\t\t{{ end }}\n\t\t{{- end }}\n\t\t}\n\t{{- end }}\n{{ end }}\n}\n\n{{ range $object := .Objects -}}\n\t{{ if $object.HasResolvers }}\n\t\ttype {{$object.GQLType}}Resolver interface {\n\t\t{{ range $field := $object.Fields -}}\n\t\t\t{{ $field.ShortResolverDeclaration }}\n\t\t{{ end }}\n\t\t}\n\t{{- end }}\n{{- end }}\n\n{{ range $object := .Objects -}}\n\t{{ range $field := $object.Fields -}}\n\t\t{{ if $field.Args }}\n\t\t\tfunc {{ $field.ArgsFunc }}(rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\t\t\t{{ template \"args.gotpl\" $field.Args }}\n\t\t\t}\n\t\t{{ end }}\n\t{{ end }}\n{{- end }}\n\n{{ range $directive := .Directives }}\n\t{{ if $directive.Args }}\n\t\tfunc {{ $directive.ArgsFunc }}(rawArgs map[string]interface{}) (map[string]interface{}, error) {\n\t\t{{ template \"args.gotpl\" $directive.Args }}\n\t\t}\n\t{{ end }}\n{{ end }}\n\ntype executableSchema struct {\n\tresolvers ResolverRoot\n\tdirectives DirectiveRoot\n\tcomplexity ComplexityRoot\n}\n\nfunc (e *executableSchema) Schema() *ast.Schema {\n\treturn parsedSchema\n}\n\nfunc (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) {\n\tswitch typeName + \".\" + field {\n\t{{ range $object := .Objects }}\n\t\t{{ if not $object.IsReserved }}\n\t\t\t{{ range $field := $object.Fields }}\n\t\t\t\t{{ if not $field.IsReserved }}\n\t\t\t\t\tcase \"{{$object.GQLType}}.{{$field.GQLName}}\":\n\t\t\t\t\t\tif e.complexity.{{$object.GQLType|toCamel}}.{{$field.GQLName|toCamel}} == nil {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\t{{ if $field.Args }}\n\t\t\t\t\t\t\targs, err := {{ $field.ArgsFunc }}(rawArgs)\n\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\treturn 0, false\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t{{ end }}\n\t\t\t\t\t\treturn e.complexity.{{$object.GQLType|toCamel}}.{{$field.GQLName|toCamel}}(childComplexity{{if $field.Args}}, {{$field.ComplexityArgs}} {{end}}), true\n\t\t\t\t{{ end }}\n\t\t\t{{ end }}\n\t\t{{ end }}\n\t{{ end }}\n\t}\n\treturn 0, false\n}\n\nfunc (e *executableSchema) Query(ctx context.Context, op *ast.OperationDefinition) *graphql.Response {\n\t{{- if .QueryRoot }}\n\t\tec := executionContext{graphql.GetRequestContext(ctx), e}\n\n\t\tbuf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte {\n\t\t\tdata := ec._{{.QueryRoot.GQLType}}(ctx, op.SelectionSet)\n\t\t\tvar buf bytes.Buffer\n\t\t\tdata.MarshalGQL(&buf)\n\t\t\treturn buf.Bytes()\n\t\t})\n\n\t\treturn &graphql.Response{\n\t\t\tData: buf,\n\t\t\tErrors: ec.Errors,\n\t\t}\n\t{{- else }}\n\t\treturn graphql.ErrorResponse(ctx, \"queries are not supported\")\n\t{{- end }}\n}\n\nfunc (e *executableSchema) Mutation(ctx context.Context, op *ast.OperationDefinition) *graphql.Response {\n\t{{- if .MutationRoot }}\n\t\tec := executionContext{graphql.GetRequestContext(ctx), e}\n\n\t\tbuf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte {\n\t\t\tdata := ec._{{.MutationRoot.GQLType}}(ctx, op.SelectionSet)\n\t\t\tvar buf bytes.Buffer\n\t\t\tdata.MarshalGQL(&buf)\n\t\t\treturn buf.Bytes()\n\t\t})\n\n\t\treturn &graphql.Response{\n\t\t\tData: buf,\n\t\t\tErrors: ec.Errors,\n\t\t}\n\t{{- else }}\n\t\treturn graphql.ErrorResponse(ctx, \"mutations are not supported\")\n\t{{- end }}\n}\n\nfunc (e *executableSchema) Subscription(ctx context.Context, op *ast.OperationDefinition) func() *graphql.Response {\n\t{{- if .SubscriptionRoot }}\n\t\tec := executionContext{graphql.GetRequestContext(ctx), e}\n\n\t\tnext := ec._{{.SubscriptionRoot.GQLType}}(ctx, op.SelectionSet)\n\t\tif ec.Errors != nil {\n\t\t\treturn graphql.OneShot(&graphql.Response{Data: []byte(\"null\"), Errors: ec.Errors})\n\t\t}\n\n\t\tvar buf bytes.Buffer\n\t\treturn func() *graphql.Response {\n\t\t\tbuf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte {\n\t\t\t\tbuf.Reset()\n\t\t\t\tdata := next()\n\n\t\t\t\tif data == nil {\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\tdata.MarshalGQL(&buf)\n\t\t\t\treturn buf.Bytes()\n\t\t\t})\n\n\t\t\tif buf == nil {\n\t\t\t\treturn nil\n\t\t\t}\n\n\t\t\treturn &graphql.Response{\n\t\t\t\tData: buf,\n\t\t\t\tErrors: ec.Errors,\n\t\t\t}\n\t\t}\n\t{{- else }}\n\t\treturn graphql.OneShot(graphql.ErrorResponse(ctx, \"subscriptions are not supported\"))\n\t{{- end }}\n}\n\ntype executionContext struct {\n\t*graphql.RequestContext\n\t*executableSchema\n}\n\n{{- range $object := .Objects }}\n\t{{ template \"object.gotpl\" $object }}\n\n\t{{- range $field := $object.Fields }}\n\t\t{{ template \"field.gotpl\" $field }}\n\t{{ end }}\n{{- end}}\n\n{{- range $interface := .Interfaces }}\n\t{{ template \"interface.gotpl\" $interface }}\n{{- end }}\n\n{{- range $input := .Inputs }}\n\t{{ template \"input.gotpl\" $input }}\n{{- end }}\n\nfunc (ec *executionContext) FieldMiddleware(ctx context.Context, obj interface{}, next graphql.Resolver) (ret interface{}) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tec.Error(ctx, ec.Recover(ctx, r))\n\t\t\tret = nil\n\t\t}\n\t}()\n\t{{- if .Directives }}\n\trctx := graphql.GetResolverContext(ctx)\n\tfor _, d := range rctx.Field.Definition.Directives {\n\t\tswitch d.Name {\n\t\t{{- range $directive := .Directives }}\n\t\tcase \"{{$directive.Name}}\":\n\t\t\tif ec.directives.{{$directive.Name|ucFirst}} != nil {\n\t\t\t\t{{- if $directive.Args }}\n\t\t\t\t\trawArgs := d.ArgumentMap(ec.Variables)\n\t\t\t\t\targs, err := {{ $directive.ArgsFunc }}(rawArgs)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tec.Error(ctx, err)\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}\n\t\t\t\t{{- end }}\n\t\t\t\tn := next\n\t\t\t\tnext = func(ctx context.Context) (interface{}, error) {\n\t\t\t\t\treturn ec.directives.{{$directive.Name|ucFirst}}({{$directive.CallArgs}})\n\t\t\t\t}\n\t\t\t}\n\t\t{{- end }}\n\t\t}\n\t}\n\t{{- end }}\n\tres, err := ec.ResolverMiddleware(ctx, next)\n\tif err != nil {\n\t\tec.Error(ctx, err)\n\t\treturn nil\n\t}\n\treturn res\n}\n\nfunc (ec *executionContext) introspectSchema() *introspection.Schema {\n\treturn introspection.WrapSchema(parsedSchema)\n}\n\nfunc (ec *executionContext) introspectType(name string) *introspection.Type {\n\treturn introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name])\n}\n\nvar parsedSchema = gqlparser.MustLoadSchema(\n\t&ast.Source{Name: {{.SchemaFilename|quote}}, Input: {{.SchemaRaw|rawQuote}}},\n)\n",
+ "input.gotpl": "\t{{- if .IsMarshaled }}\n\tfunc Unmarshal{{ .GQLType }}(v interface{}) ({{.FullName}}, error) {\n\t\tvar it {{.FullName}}\n\t\tvar asMap = v.(map[string]interface{})\n\t\t{{ range $field := .Fields}}\n\t\t\t{{- if $field.Default}}\n\t\t\t\tif _, present := asMap[{{$field.GQLName|quote}}] ; !present {\n\t\t\t\t\tasMap[{{$field.GQLName|quote}}] = {{ $field.Default | dump }}\n\t\t\t\t}\n\t\t\t{{- end}}\n\t\t{{- end }}\n\n\t\tfor k, v := range asMap {\n\t\t\tswitch k {\n\t\t\t{{- range $field := .Fields }}\n\t\t\tcase {{$field.GQLName|quote}}:\n\t\t\t\tvar err error\n\t\t\t\t{{ $field.Unmarshal (print \"it.\" $field.GoFieldName) \"v\" }}\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn it, err\n\t\t\t\t}\n\t\t\t{{- end }}\n\t\t\t}\n\t\t}\n\n\t\treturn it, nil\n\t}\n\t{{- end }}\n",
+ "interface.gotpl": "{{- $interface := . }}\n\nfunc (ec *executionContext) _{{$interface.GQLType}}(ctx context.Context, sel ast.SelectionSet, obj *{{$interface.FullName}}) graphql.Marshaler {\n\tswitch obj := (*obj).(type) {\n\tcase nil:\n\t\treturn graphql.Null\n\t{{- range $implementor := $interface.Implementors }}\n\t\t{{- if $implementor.ValueReceiver }}\n\t\t\tcase {{$implementor.FullName}}:\n\t\t\t\treturn ec._{{$implementor.GQLType}}(ctx, sel, &obj)\n\t\t{{- end}}\n\t\tcase *{{$implementor.FullName}}:\n\t\t\treturn ec._{{$implementor.GQLType}}(ctx, sel, obj)\n\t{{- end }}\n\tdefault:\n\t\tpanic(fmt.Errorf(\"unexpected type %T\", obj))\n\t}\n}\n",
+ "models.gotpl": "// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.\n\npackage {{ .PackageName }}\n\nimport (\n{{- range $import := .Imports }}\n\t{{- $import.Write }}\n{{ end }}\n)\n\n{{ range $model := .Models }}\n\t{{with .Description}} {{.|prefixLines \"// \"}} {{end}}\n\t{{- if .IsInterface }}\n\t\ttype {{.GoType}} interface {}\n\t{{- else }}\n\t\ttype {{.GoType}} struct {\n\t\t\t{{- range $field := .Fields }}\n\t\t\t\t{{- with .Description}}\n\t\t\t\t\t{{.|prefixLines \"// \"}}\n\t\t\t\t{{- end}}\n\t\t\t\t{{- if $field.GoFieldName }}\n\t\t\t\t\t{{ $field.GoFieldName }} {{$field.Signature}} `json:\"{{$field.GQLName}}\"`\n\t\t\t\t{{- else }}\n\t\t\t\t\t{{ $field.GoFKName }} {{$field.GoFKType}}\n\t\t\t\t{{- end }}\n\t\t\t{{- end }}\n\t\t}\n\t{{- end }}\n{{- end}}\n\n{{ range $enum := .Enums }}\n\t{{with .Description}}{{.|prefixLines \"// \"}} {{end}}\n\ttype {{.GoType}} string\n\tconst (\n\t{{- range $value := .Values}}\n\t\t{{- with .Description}}\n\t\t\t{{.|prefixLines \"// \"}}\n\t\t{{- end}}\n\t\t{{$enum.GoType}}{{ .Name|toCamel }} {{$enum.GoType}} = {{.Name|quote}}\n\t{{- end }}\n\t)\n\n\tfunc (e {{.GoType}}) IsValid() bool {\n\t\tswitch e {\n\t\tcase {{ range $index, $element := .Values}}{{if $index}},{{end}}{{ $enum.GoType }}{{ $element.Name|toCamel }}{{end}}:\n\t\t\treturn true\n\t\t}\n\t\treturn false\n\t}\n\n\tfunc (e {{.GoType}}) String() string {\n\t\treturn string(e)\n\t}\n\n\tfunc (e *{{.GoType}}) UnmarshalGQL(v interface{}) error {\n\t\tstr, ok := v.(string)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"enums must be strings\")\n\t\t}\n\n\t\t*e = {{.GoType}}(str)\n\t\tif !e.IsValid() {\n\t\t\treturn fmt.Errorf(\"%s is not a valid {{.GQLType}}\", str)\n\t\t}\n\t\treturn nil\n\t}\n\n\tfunc (e {{.GoType}}) MarshalGQL(w io.Writer) {\n\t\tfmt.Fprint(w, strconv.Quote(e.String()))\n\t}\n\n{{- end }}\n",
+ "object.gotpl": "{{ $object := . }}\n\nvar {{ $object.GQLType|lcFirst}}Implementors = {{$object.Implementors}}\n\n// nolint: gocyclo, errcheck, gas, goconst\n{{- if .Stream }}\nfunc (ec *executionContext) _{{$object.GQLType}}(ctx context.Context, sel ast.SelectionSet) func() graphql.Marshaler {\n\tfields := graphql.CollectFields(ctx, sel, {{$object.GQLType|lcFirst}}Implementors)\n\tctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{\n\t\tObject: {{$object.GQLType|quote}},\n\t})\n\tif len(fields) != 1 {\n\t\tec.Errorf(ctx, \"must subscribe to exactly one stream\")\n\t\treturn nil\n\t}\n\n\tswitch fields[0].Name {\n\t{{- range $field := $object.Fields }}\n\tcase \"{{$field.GQLName}}\":\n\t\treturn ec._{{$object.GQLType}}_{{$field.GQLName}}(ctx, fields[0])\n\t{{- end }}\n\tdefault:\n\t\tpanic(\"unknown field \" + strconv.Quote(fields[0].Name))\n\t}\n}\n{{- else }}\nfunc (ec *executionContext) _{{$object.GQLType}}(ctx context.Context, sel ast.SelectionSet{{if not $object.Root}}, obj *{{$object.FullName}} {{end}}) graphql.Marshaler {\n\tfields := graphql.CollectFields(ctx, sel, {{$object.GQLType|lcFirst}}Implementors)\n\t{{if $object.Root}}\n\t\tctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{\n\t\t\tObject: {{$object.GQLType|quote}},\n\t\t})\n\t{{end}}\n\n\t{{if $object.IsConcurrent}} var wg sync.WaitGroup {{end}}\n\tout := graphql.NewOrderedMap(len(fields))\n\tinvalid := false\n\tfor i, field := range fields {\n\t\tout.Keys[i] = field.Alias\n\n\t\tswitch field.Name {\n\t\tcase \"__typename\":\n\t\t\tout.Values[i] = graphql.MarshalString({{$object.GQLType|quote}})\n\t\t{{- range $field := $object.Fields }}\n\t\tcase \"{{$field.GQLName}}\":\n\t\t\t{{- if $field.IsConcurrent }}\n\t\t\t\twg.Add(1)\n\t\t\t\tgo func(i int, field graphql.CollectedField) {\n\t\t\t{{- end }}\n\t\t\t\tout.Values[i] = ec._{{$object.GQLType}}_{{$field.GQLName}}(ctx, field{{if not $object.Root}}, obj{{end}})\n\t\t\t\t{{- if $field.ASTType.NonNull }}\n\t\t\t\t\tif out.Values[i] == graphql.Null {\n\t\t\t\t\t\tinvalid = true\n\t\t\t\t\t}\n\t\t\t\t{{- end }}\n\t\t\t{{- if $field.IsConcurrent }}\n\t\t\t\t\twg.Done()\n\t\t\t\t}(i, field)\n\t\t\t{{- end }}\n\t\t{{- end }}\n\t\tdefault:\n\t\t\tpanic(\"unknown field \" + strconv.Quote(field.Name))\n\t\t}\n\t}\n\t{{if $object.IsConcurrent}} wg.Wait() {{end}}\n\tif invalid { return graphql.Null }\n\treturn out\n}\n{{- end }}\n",
+ "resolver.gotpl": "//go:generate gorunpkg github.com/99designs/gqlgen\n\npackage {{ .PackageName }}\n\nimport (\n{{- range $import := .Imports }}\n\t{{- $import.Write }}\n{{ end }}\n)\n\ntype {{.ResolverType}} struct {}\n\n{{ range $object := .Objects -}}\n\t{{- if $object.HasResolvers -}}\n\t\tfunc (r *{{$.ResolverType}}) {{$object.GQLType}}() {{ $object.ResolverInterface.FullName }} {\n\t\t\treturn &{{lcFirst $object.GQLType}}Resolver{r}\n\t\t}\n\t{{ end -}}\n{{ end }}\n\n{{ range $object := .Objects -}}\n\t{{- if $object.HasResolvers -}}\n\t\ttype {{lcFirst $object.GQLType}}Resolver struct { *Resolver }\n\n\t\t{{ range $field := $object.Fields -}}\n\t\t\t{{- if $field.IsResolver -}}\n\t\t\tfunc (r *{{lcFirst $object.GQLType}}Resolver) {{ $field.ShortResolverDeclaration }} {\n\t\t\t\tpanic(\"not implemented\")\n\t\t\t}\n\t\t\t{{ end -}}\n\t\t{{ end -}}\n\t{{ end -}}\n{{ end }}\n",
+ "server.gotpl": "package main\n\nimport (\n{{- range $import := .Imports }}\n\t{{- $import.Write }}\n{{ end }}\n)\n\nconst defaultPort = \"8080\"\n\nfunc main() {\n\tport := os.Getenv(\"PORT\")\n\tif port == \"\" {\n\t\tport = defaultPort\n\t}\n\n\thttp.Handle(\"/\", handler.Playground(\"GraphQL playground\", \"/query\"))\n\thttp.Handle(\"/query\", handler.GraphQL({{.ExecPackageName}}.NewExecutableSchema({{.ExecPackageName}}.Config{Resolvers: &{{.ResolverPackageName}}.Resolver{}})))\n\n\tlog.Printf(\"connect to http://localhost:%s/ for GraphQL playground\", port)\n\tlog.Fatal(http.ListenAndServe(\":\" + port, nil))\n}\n",
+}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/templates/field.gotpl b/vendor/github.com/99designs/gqlgen/codegen/templates/field.gotpl
new file mode 100644
index 00000000..b33f2123
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/templates/field.gotpl
@@ -0,0 +1,74 @@
+{{ $field := . }}
+{{ $object := $field.Object }}
+
+{{- if $object.Stream }}
+ func (ec *executionContext) _{{$object.GQLType}}_{{$field.GQLName}}(ctx context.Context, field graphql.CollectedField) func() graphql.Marshaler {
+ {{- if $field.Args }}
+ rawArgs := field.ArgumentMap(ec.Variables)
+ args, err := {{ $field.ArgsFunc }}(rawArgs)
+ if err != nil {
+ ec.Error(ctx, err)
+ return nil
+ }
+ {{- end }}
+ ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{
+ Field: field,
+ })
+ results, err := ec.resolvers.{{ $field.ShortInvocation }}
+ if err != nil {
+ ec.Error(ctx, err)
+ return nil
+ }
+ return func() graphql.Marshaler {
+ res, ok := <-results
+ if !ok {
+ return nil
+ }
+ var out graphql.OrderedMap
+ out.Add(field.Alias, func() graphql.Marshaler { {{ $field.WriteJson }} }())
+ return &out
+ }
+ }
+{{ else }}
+ // nolint: vetshadow
+ func (ec *executionContext) _{{$object.GQLType}}_{{$field.GQLName}}(ctx context.Context, field graphql.CollectedField, {{if not $object.Root}}obj *{{$object.FullName}}{{end}}) graphql.Marshaler {
+ {{- if $field.Args }}
+ rawArgs := field.ArgumentMap(ec.Variables)
+ args, err := {{ $field.ArgsFunc }}(rawArgs)
+ if err != nil {
+ ec.Error(ctx, err)
+ return graphql.Null
+ }
+ {{- end }}
+ rctx := &graphql.ResolverContext{
+ Object: {{$object.GQLType|quote}},
+ Args: {{if $field.Args }}args{{else}}nil{{end}},
+ Field: field,
+ }
+ ctx = graphql.WithResolverContext(ctx, rctx)
+ resTmp := ec.FieldMiddleware(ctx, {{if $object.Root}}nil{{else}}obj{{end}}, func(ctx context.Context) (interface{}, error) {
+ {{- if $field.IsResolver }}
+ return ec.resolvers.{{ $field.ShortInvocation }}
+ {{- 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 resTmp == nil {
+ {{- if $field.ASTType.NonNull }}
+ if !ec.HasError(rctx) {
+ ec.Errorf(ctx, "must not be null")
+ }
+ {{- end }}
+ return graphql.Null
+ }
+ res := resTmp.({{$field.Signature}})
+ rctx.Result = res
+ {{ $field.WriteJson }}
+ }
+{{ end }}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/templates/generated.gotpl b/vendor/github.com/99designs/gqlgen/codegen/templates/generated.gotpl
new file mode 100644
index 00000000..8250bc7a
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/templates/generated.gotpl
@@ -0,0 +1,263 @@
+// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
+
+package {{ .PackageName }}
+
+import (
+{{- range $import := .Imports }}
+ {{- $import.Write }}
+{{ end }}
+)
+
+// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
+func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
+ return &executableSchema{
+ resolvers: cfg.Resolvers,
+ directives: cfg.Directives,
+ complexity: cfg.Complexity,
+ }
+}
+
+type Config struct {
+ Resolvers ResolverRoot
+ Directives DirectiveRoot
+ Complexity ComplexityRoot
+}
+
+type ResolverRoot interface {
+{{- range $object := .Objects -}}
+ {{ if $object.HasResolvers -}}
+ {{$object.GQLType}}() {{$object.GQLType}}Resolver
+ {{ end }}
+{{- end }}
+}
+
+type DirectiveRoot struct {
+{{ range $directive := .Directives }}
+ {{ $directive.Declaration }}
+{{ end }}
+}
+
+type ComplexityRoot struct {
+{{ range $object := .Objects }}
+ {{ if not $object.IsReserved -}}
+ {{ $object.GQLType|toCamel }} struct {
+ {{ range $field := $object.Fields -}}
+ {{ if not $field.IsReserved -}}
+ {{ $field.GQLName|toCamel }} {{ $field.ComplexitySignature }}
+ {{ end }}
+ {{- end }}
+ }
+ {{- end }}
+{{ end }}
+}
+
+{{ range $object := .Objects -}}
+ {{ if $object.HasResolvers }}
+ type {{$object.GQLType}}Resolver interface {
+ {{ range $field := $object.Fields -}}
+ {{ $field.ShortResolverDeclaration }}
+ {{ end }}
+ }
+ {{- end }}
+{{- end }}
+
+{{ range $object := .Objects -}}
+ {{ range $field := $object.Fields -}}
+ {{ if $field.Args }}
+ func {{ $field.ArgsFunc }}(rawArgs map[string]interface{}) (map[string]interface{}, error) {
+ {{ template "args.gotpl" $field.Args }}
+ }
+ {{ end }}
+ {{ end }}
+{{- end }}
+
+{{ range $directive := .Directives }}
+ {{ if $directive.Args }}
+ func {{ $directive.ArgsFunc }}(rawArgs map[string]interface{}) (map[string]interface{}, error) {
+ {{ template "args.gotpl" $directive.Args }}
+ }
+ {{ end }}
+{{ end }}
+
+type executableSchema struct {
+ resolvers ResolverRoot
+ directives DirectiveRoot
+ complexity ComplexityRoot
+}
+
+func (e *executableSchema) Schema() *ast.Schema {
+ return parsedSchema
+}
+
+func (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) {
+ switch typeName + "." + field {
+ {{ range $object := .Objects }}
+ {{ if not $object.IsReserved }}
+ {{ range $field := $object.Fields }}
+ {{ if not $field.IsReserved }}
+ case "{{$object.GQLType}}.{{$field.GQLName}}":
+ if e.complexity.{{$object.GQLType|toCamel}}.{{$field.GQLName|toCamel}} == nil {
+ break
+ }
+ {{ if $field.Args }}
+ args, err := {{ $field.ArgsFunc }}(rawArgs)
+ if err != nil {
+ return 0, false
+ }
+ {{ end }}
+ return e.complexity.{{$object.GQLType|toCamel}}.{{$field.GQLName|toCamel}}(childComplexity{{if $field.Args}}, {{$field.ComplexityArgs}} {{end}}), true
+ {{ end }}
+ {{ end }}
+ {{ end }}
+ {{ end }}
+ }
+ return 0, false
+}
+
+func (e *executableSchema) Query(ctx context.Context, op *ast.OperationDefinition) *graphql.Response {
+ {{- if .QueryRoot }}
+ ec := executionContext{graphql.GetRequestContext(ctx), e}
+
+ buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte {
+ data := ec._{{.QueryRoot.GQLType}}(ctx, op.SelectionSet)
+ var buf bytes.Buffer
+ data.MarshalGQL(&buf)
+ return buf.Bytes()
+ })
+
+ return &graphql.Response{
+ Data: buf,
+ Errors: ec.Errors,
+ }
+ {{- else }}
+ return graphql.ErrorResponse(ctx, "queries are not supported")
+ {{- end }}
+}
+
+func (e *executableSchema) Mutation(ctx context.Context, op *ast.OperationDefinition) *graphql.Response {
+ {{- if .MutationRoot }}
+ ec := executionContext{graphql.GetRequestContext(ctx), e}
+
+ buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte {
+ data := ec._{{.MutationRoot.GQLType}}(ctx, op.SelectionSet)
+ var buf bytes.Buffer
+ data.MarshalGQL(&buf)
+ return buf.Bytes()
+ })
+
+ return &graphql.Response{
+ Data: buf,
+ Errors: ec.Errors,
+ }
+ {{- else }}
+ return graphql.ErrorResponse(ctx, "mutations are not supported")
+ {{- end }}
+}
+
+func (e *executableSchema) Subscription(ctx context.Context, op *ast.OperationDefinition) func() *graphql.Response {
+ {{- if .SubscriptionRoot }}
+ ec := executionContext{graphql.GetRequestContext(ctx), e}
+
+ next := ec._{{.SubscriptionRoot.GQLType}}(ctx, op.SelectionSet)
+ if ec.Errors != nil {
+ return graphql.OneShot(&graphql.Response{Data: []byte("null"), Errors: ec.Errors})
+ }
+
+ var buf bytes.Buffer
+ return func() *graphql.Response {
+ buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte {
+ buf.Reset()
+ data := next()
+
+ if data == nil {
+ return nil
+ }
+ data.MarshalGQL(&buf)
+ return buf.Bytes()
+ })
+
+ if buf == nil {
+ return nil
+ }
+
+ return &graphql.Response{
+ Data: buf,
+ Errors: ec.Errors,
+ }
+ }
+ {{- else }}
+ return graphql.OneShot(graphql.ErrorResponse(ctx, "subscriptions are not supported"))
+ {{- end }}
+}
+
+type executionContext struct {
+ *graphql.RequestContext
+ *executableSchema
+}
+
+{{- range $object := .Objects }}
+ {{ template "object.gotpl" $object }}
+
+ {{- range $field := $object.Fields }}
+ {{ template "field.gotpl" $field }}
+ {{ end }}
+{{- end}}
+
+{{- range $interface := .Interfaces }}
+ {{ template "interface.gotpl" $interface }}
+{{- end }}
+
+{{- range $input := .Inputs }}
+ {{ template "input.gotpl" $input }}
+{{- end }}
+
+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 := {{ $directive.ArgsFunc }}(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 {
+ return introspection.WrapSchema(parsedSchema)
+}
+
+func (ec *executionContext) introspectType(name string) *introspection.Type {
+ return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name])
+}
+
+var parsedSchema = gqlparser.MustLoadSchema(
+ &ast.Source{Name: {{.SchemaFilename|quote}}, Input: {{.SchemaRaw|rawQuote}}},
+)
diff --git a/vendor/github.com/99designs/gqlgen/codegen/templates/input.gotpl b/vendor/github.com/99designs/gqlgen/codegen/templates/input.gotpl
new file mode 100644
index 00000000..f543608d
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/templates/input.gotpl
@@ -0,0 +1,28 @@
+ {{- if .IsMarshaled }}
+ func Unmarshal{{ .GQLType }}(v interface{}) ({{.FullName}}, error) {
+ var it {{.FullName}}
+ var asMap = v.(map[string]interface{})
+ {{ range $field := .Fields}}
+ {{- if $field.Default}}
+ if _, present := asMap[{{$field.GQLName|quote}}] ; !present {
+ asMap[{{$field.GQLName|quote}}] = {{ $field.Default | dump }}
+ }
+ {{- end}}
+ {{- end }}
+
+ for k, v := range asMap {
+ switch k {
+ {{- range $field := .Fields }}
+ case {{$field.GQLName|quote}}:
+ var err error
+ {{ $field.Unmarshal (print "it." $field.GoFieldName) "v" }}
+ if err != nil {
+ return it, err
+ }
+ {{- end }}
+ }
+ }
+
+ return it, nil
+ }
+ {{- end }}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/templates/interface.gotpl b/vendor/github.com/99designs/gqlgen/codegen/templates/interface.gotpl
new file mode 100644
index 00000000..84cbe500
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/templates/interface.gotpl
@@ -0,0 +1,18 @@
+{{- $interface := . }}
+
+func (ec *executionContext) _{{$interface.GQLType}}(ctx context.Context, sel ast.SelectionSet, obj *{{$interface.FullName}}) graphql.Marshaler {
+ switch obj := (*obj).(type) {
+ case nil:
+ return graphql.Null
+ {{- range $implementor := $interface.Implementors }}
+ {{- if $implementor.ValueReceiver }}
+ case {{$implementor.FullName}}:
+ return ec._{{$implementor.GQLType}}(ctx, sel, &obj)
+ {{- end}}
+ case *{{$implementor.FullName}}:
+ return ec._{{$implementor.GQLType}}(ctx, sel, obj)
+ {{- end }}
+ default:
+ panic(fmt.Errorf("unexpected type %T", obj))
+ }
+}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/templates/models.gotpl b/vendor/github.com/99designs/gqlgen/codegen/templates/models.gotpl
new file mode 100644
index 00000000..7427d71d
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/templates/models.gotpl
@@ -0,0 +1,72 @@
+// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.
+
+package {{ .PackageName }}
+
+import (
+{{- range $import := .Imports }}
+ {{- $import.Write }}
+{{ end }}
+)
+
+{{ range $model := .Models }}
+ {{with .Description}} {{.|prefixLines "// "}} {{end}}
+ {{- if .IsInterface }}
+ type {{.GoType}} interface {}
+ {{- else }}
+ type {{.GoType}} struct {
+ {{- range $field := .Fields }}
+ {{- with .Description}}
+ {{.|prefixLines "// "}}
+ {{- end}}
+ {{- if $field.GoFieldName }}
+ {{ $field.GoFieldName }} {{$field.Signature}} `json:"{{$field.GQLName}}"`
+ {{- else }}
+ {{ $field.GoFKName }} {{$field.GoFKType}}
+ {{- end }}
+ {{- end }}
+ }
+ {{- end }}
+{{- end}}
+
+{{ range $enum := .Enums }}
+ {{with .Description}}{{.|prefixLines "// "}} {{end}}
+ type {{.GoType}} string
+ const (
+ {{- range $value := .Values}}
+ {{- with .Description}}
+ {{.|prefixLines "// "}}
+ {{- end}}
+ {{$enum.GoType}}{{ .Name|toCamel }} {{$enum.GoType}} = {{.Name|quote}}
+ {{- end }}
+ )
+
+ func (e {{.GoType}}) IsValid() bool {
+ switch e {
+ case {{ range $index, $element := .Values}}{{if $index}},{{end}}{{ $enum.GoType }}{{ $element.Name|toCamel }}{{end}}:
+ return true
+ }
+ return false
+ }
+
+ func (e {{.GoType}}) String() string {
+ return string(e)
+ }
+
+ func (e *{{.GoType}}) UnmarshalGQL(v interface{}) error {
+ str, ok := v.(string)
+ if !ok {
+ return fmt.Errorf("enums must be strings")
+ }
+
+ *e = {{.GoType}}(str)
+ if !e.IsValid() {
+ return fmt.Errorf("%s is not a valid {{.GQLType}}", str)
+ }
+ return nil
+ }
+
+ func (e {{.GoType}}) MarshalGQL(w io.Writer) {
+ fmt.Fprint(w, strconv.Quote(e.String()))
+ }
+
+{{- end }}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/templates/object.gotpl b/vendor/github.com/99designs/gqlgen/codegen/templates/object.gotpl
new file mode 100644
index 00000000..e98cbe1e
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/templates/object.gotpl
@@ -0,0 +1,69 @@
+{{ $object := . }}
+
+var {{ $object.GQLType|lcFirst}}Implementors = {{$object.Implementors}}
+
+// nolint: gocyclo, errcheck, gas, goconst
+{{- if .Stream }}
+func (ec *executionContext) _{{$object.GQLType}}(ctx context.Context, sel ast.SelectionSet) func() graphql.Marshaler {
+ fields := graphql.CollectFields(ctx, sel, {{$object.GQLType|lcFirst}}Implementors)
+ ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{
+ Object: {{$object.GQLType|quote}},
+ })
+ if len(fields) != 1 {
+ ec.Errorf(ctx, "must subscribe to exactly one stream")
+ return nil
+ }
+
+ switch fields[0].Name {
+ {{- range $field := $object.Fields }}
+ case "{{$field.GQLName}}":
+ return ec._{{$object.GQLType}}_{{$field.GQLName}}(ctx, fields[0])
+ {{- end }}
+ default:
+ panic("unknown field " + strconv.Quote(fields[0].Name))
+ }
+}
+{{- else }}
+func (ec *executionContext) _{{$object.GQLType}}(ctx context.Context, sel ast.SelectionSet{{if not $object.Root}}, obj *{{$object.FullName}} {{end}}) graphql.Marshaler {
+ fields := graphql.CollectFields(ctx, sel, {{$object.GQLType|lcFirst}}Implementors)
+ {{if $object.Root}}
+ ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{
+ Object: {{$object.GQLType|quote}},
+ })
+ {{end}}
+
+ {{if $object.IsConcurrent}} var wg sync.WaitGroup {{end}}
+ out := graphql.NewOrderedMap(len(fields))
+ invalid := false
+ for i, field := range fields {
+ out.Keys[i] = field.Alias
+
+ switch field.Name {
+ case "__typename":
+ out.Values[i] = graphql.MarshalString({{$object.GQLType|quote}})
+ {{- range $field := $object.Fields }}
+ case "{{$field.GQLName}}":
+ {{- if $field.IsConcurrent }}
+ wg.Add(1)
+ go func(i int, field graphql.CollectedField) {
+ {{- end }}
+ out.Values[i] = ec._{{$object.GQLType}}_{{$field.GQLName}}(ctx, field{{if not $object.Root}}, obj{{end}})
+ {{- if $field.ASTType.NonNull }}
+ if out.Values[i] == graphql.Null {
+ invalid = true
+ }
+ {{- end }}
+ {{- if $field.IsConcurrent }}
+ wg.Done()
+ }(i, field)
+ {{- end }}
+ {{- end }}
+ default:
+ panic("unknown field " + strconv.Quote(field.Name))
+ }
+ }
+ {{if $object.IsConcurrent}} wg.Wait() {{end}}
+ if invalid { return graphql.Null }
+ return out
+}
+{{- end }}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/templates/resolver.gotpl b/vendor/github.com/99designs/gqlgen/codegen/templates/resolver.gotpl
new file mode 100644
index 00000000..dd8acf24
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/templates/resolver.gotpl
@@ -0,0 +1,33 @@
+//go:generate gorunpkg github.com/99designs/gqlgen
+
+package {{ .PackageName }}
+
+import (
+{{- range $import := .Imports }}
+ {{- $import.Write }}
+{{ end }}
+)
+
+type {{.ResolverType}} struct {}
+
+{{ range $object := .Objects -}}
+ {{- if $object.HasResolvers -}}
+ func (r *{{$.ResolverType}}) {{$object.GQLType}}() {{ $object.ResolverInterface.FullName }} {
+ return &{{lcFirst $object.GQLType}}Resolver{r}
+ }
+ {{ end -}}
+{{ end }}
+
+{{ range $object := .Objects -}}
+ {{- if $object.HasResolvers -}}
+ type {{lcFirst $object.GQLType}}Resolver struct { *Resolver }
+
+ {{ range $field := $object.Fields -}}
+ {{- if $field.IsResolver -}}
+ func (r *{{lcFirst $object.GQLType}}Resolver) {{ $field.ShortResolverDeclaration }} {
+ panic("not implemented")
+ }
+ {{ end -}}
+ {{ end -}}
+ {{ end -}}
+{{ end }}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/templates/server.gotpl b/vendor/github.com/99designs/gqlgen/codegen/templates/server.gotpl
new file mode 100644
index 00000000..f23b30e1
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/templates/server.gotpl
@@ -0,0 +1,22 @@
+package main
+
+import (
+{{- range $import := .Imports }}
+ {{- $import.Write }}
+{{ end }}
+)
+
+const defaultPort = "8080"
+
+func main() {
+ port := os.Getenv("PORT")
+ if port == "" {
+ port = defaultPort
+ }
+
+ http.Handle("/", handler.Playground("GraphQL playground", "/query"))
+ http.Handle("/query", handler.GraphQL({{.ExecPackageName}}.NewExecutableSchema({{.ExecPackageName}}.Config{Resolvers: &{{.ResolverPackageName}}.Resolver{}})))
+
+ log.Printf("connect to http://localhost:%s/ for GraphQL playground", port)
+ log.Fatal(http.ListenAndServe(":" + port, nil))
+}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/templates/templates.go b/vendor/github.com/99designs/gqlgen/codegen/templates/templates.go
new file mode 100644
index 00000000..df909cb5
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/templates/templates.go
@@ -0,0 +1,193 @@
+//go:generate go run ./inliner/inliner.go
+
+package templates
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "sort"
+ "strconv"
+ "strings"
+ "text/template"
+ "unicode"
+
+ "log"
+
+ "github.com/pkg/errors"
+ "golang.org/x/tools/imports"
+)
+
+func Run(name string, tpldata interface{}) (*bytes.Buffer, error) {
+ t := template.New("").Funcs(template.FuncMap{
+ "ucFirst": ucFirst,
+ "lcFirst": lcFirst,
+ "quote": strconv.Quote,
+ "rawQuote": rawQuote,
+ "toCamel": ToCamel,
+ "dump": dump,
+ "prefixLines": prefixLines,
+ })
+
+ for filename, data := range data {
+ _, err := t.New(filename).Parse(data)
+ if err != nil {
+ panic(err)
+ }
+ }
+
+ buf := &bytes.Buffer{}
+ err := t.Lookup(name).Execute(buf, tpldata)
+ if err != nil {
+ return nil, err
+ }
+
+ return buf, nil
+}
+
+func ucFirst(s string) string {
+ if s == "" {
+ return ""
+ }
+ r := []rune(s)
+ r[0] = unicode.ToUpper(r[0])
+ return string(r)
+}
+
+func lcFirst(s string) string {
+ if s == "" {
+ return ""
+ }
+
+ r := []rune(s)
+ r[0] = unicode.ToLower(r[0])
+ return string(r)
+}
+
+func isDelimiter(c rune) bool {
+ return c == '-' || c == '_' || unicode.IsSpace(c)
+}
+
+func ToCamel(s string) string {
+ buffer := make([]rune, 0, len(s))
+ upper := true
+ lastWasUpper := false
+
+ for _, c := range s {
+ if isDelimiter(c) {
+ upper = true
+ continue
+ }
+ if !lastWasUpper && unicode.IsUpper(c) {
+ upper = true
+ }
+
+ if upper {
+ buffer = append(buffer, unicode.ToUpper(c))
+ } else {
+ buffer = append(buffer, unicode.ToLower(c))
+ }
+ upper = false
+ lastWasUpper = unicode.IsUpper(c)
+ }
+
+ return string(buffer)
+}
+
+func rawQuote(s string) string {
+ return "`" + strings.Replace(s, "`", "`+\"`\"+`", -1) + "`"
+}
+
+func dump(val interface{}) string {
+ switch val := val.(type) {
+ case int:
+ return strconv.Itoa(val)
+ case int64:
+ return fmt.Sprintf("%d", val)
+ case float64:
+ return fmt.Sprintf("%f", val)
+ case string:
+ return strconv.Quote(val)
+ case bool:
+ return strconv.FormatBool(val)
+ case nil:
+ return "nil"
+ case []interface{}:
+ var parts []string
+ for _, part := range val {
+ parts = append(parts, dump(part))
+ }
+ return "[]interface{}{" + strings.Join(parts, ",") + "}"
+ case map[string]interface{}:
+ buf := bytes.Buffer{}
+ buf.WriteString("map[string]interface{}{")
+ var keys []string
+ for key := range val {
+ keys = append(keys, key)
+ }
+ sort.Strings(keys)
+
+ for _, key := range keys {
+ data := val[key]
+
+ buf.WriteString(strconv.Quote(key))
+ buf.WriteString(":")
+ buf.WriteString(dump(data))
+ buf.WriteString(",")
+ }
+ buf.WriteString("}")
+ return buf.String()
+ default:
+ panic(fmt.Errorf("unsupported type %T", val))
+ }
+}
+
+func prefixLines(prefix, s string) string {
+ return prefix + strings.Replace(s, "\n", "\n"+prefix, -1)
+}
+
+func RenderToFile(tpl string, filename string, data interface{}) error {
+ var buf *bytes.Buffer
+ buf, err := Run(tpl, data)
+ if err != nil {
+ return errors.Wrap(err, filename+" generation failed")
+ }
+
+ if err := write(filename, buf.Bytes()); err != nil {
+ return err
+ }
+
+ log.Println(filename)
+
+ return nil
+}
+
+func gofmt(filename string, b []byte) ([]byte, error) {
+ out, err := imports.Process(filename, b, nil)
+ if err != nil {
+ return b, errors.Wrap(err, "unable to gofmt")
+ }
+ return out, nil
+}
+
+func write(filename string, b []byte) error {
+ err := os.MkdirAll(filepath.Dir(filename), 0755)
+ if err != nil {
+ return errors.Wrap(err, "failed to create directory")
+ }
+
+ formatted, err := gofmt(filename, b)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "gofmt failed: %s\n", err.Error())
+ formatted = b
+ }
+
+ err = ioutil.WriteFile(filename, formatted, 0644)
+ if err != nil {
+ return errors.Wrapf(err, "failed to write %s", filename)
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/type.go b/vendor/github.com/99designs/gqlgen/codegen/type.go
new file mode 100644
index 00000000..8c53fe55
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/type.go
@@ -0,0 +1,170 @@
+package codegen
+
+import (
+ "strconv"
+ "strings"
+
+ "github.com/vektah/gqlparser/ast"
+)
+
+type NamedTypes map[string]*NamedType
+
+type NamedType struct {
+ Ref
+ IsScalar bool
+ IsInterface bool
+ IsInput bool
+ GQLType string // Name of the graphql type
+ Marshaler *Ref // If this type has an external marshaler this will be set
+}
+
+type Ref struct {
+ GoType string // Name of the go type
+ Package string // the package the go type lives in
+ Import *Import // the resolved import with alias
+ IsUserDefined bool // does the type exist in the typemap
+}
+
+type Type struct {
+ *NamedType
+
+ Modifiers []string
+ ASTType *ast.Type
+ AliasedType *Ref
+}
+
+const (
+ modList = "[]"
+ modPtr = "*"
+)
+
+func (t Ref) FullName() string {
+ return t.PkgDot() + t.GoType
+}
+
+func (t Ref) PkgDot() string {
+ if t.Import == nil || t.Import.Alias() == "" {
+ return ""
+ }
+ return t.Import.Alias() + "."
+}
+
+func (t Type) Signature() string {
+ if t.AliasedType != nil {
+ return strings.Join(t.Modifiers, "") + t.AliasedType.FullName()
+ }
+ return strings.Join(t.Modifiers, "") + t.FullName()
+}
+
+func (t Type) FullSignature() string {
+ pkg := ""
+ if t.Package != "" {
+ pkg = t.Package + "."
+ }
+
+ return strings.Join(t.Modifiers, "") + pkg + t.GoType
+}
+
+func (t Type) IsPtr() bool {
+ return len(t.Modifiers) > 0 && t.Modifiers[0] == modPtr
+}
+
+func (t *Type) StripPtr() {
+ if !t.IsPtr() {
+ return
+ }
+ t.Modifiers = t.Modifiers[0 : len(t.Modifiers)-1]
+}
+
+func (t Type) IsSlice() bool {
+ return len(t.Modifiers) > 0 && t.Modifiers[0] == modList ||
+ len(t.Modifiers) > 1 && t.Modifiers[0] == modPtr && t.Modifiers[1] == modList
+}
+
+func (t NamedType) IsMarshaled() bool {
+ return t.Marshaler != nil
+}
+
+func (t Type) Unmarshal(result, raw string) string {
+ return t.unmarshal(result, raw, t.Modifiers, 1)
+}
+
+func (t Type) unmarshal(result, raw string, remainingMods []string, depth int) string {
+ switch {
+ case len(remainingMods) > 0 && remainingMods[0] == modPtr:
+ ptr := "ptr" + strconv.Itoa(depth)
+ return tpl(`var {{.ptr}} {{.mods}}{{.t.FullName}}
+ if {{.raw}} != nil {
+ {{.next}}
+ {{.result}} = &{{.ptr -}}
+ }
+ `, map[string]interface{}{
+ "ptr": ptr,
+ "t": t,
+ "raw": raw,
+ "result": result,
+ "mods": strings.Join(remainingMods[1:], ""),
+ "next": t.unmarshal(ptr, raw, remainingMods[1:], depth+1),
+ })
+
+ case len(remainingMods) > 0 && remainingMods[0] == modList:
+ var rawIf = "rawIf" + strconv.Itoa(depth)
+ var index = "idx" + strconv.Itoa(depth)
+
+ return tpl(`var {{.rawSlice}} []interface{}
+ if {{.raw}} != nil {
+ if tmp1, ok := {{.raw}}.([]interface{}); ok {
+ {{.rawSlice}} = tmp1
+ } else {
+ {{.rawSlice}} = []interface{}{ {{.raw}} }
+ }
+ }
+ {{.result}} = make({{.type}}, len({{.rawSlice}}))
+ for {{.index}} := range {{.rawSlice}} {
+ {{ .next -}}
+ }`, map[string]interface{}{
+ "raw": raw,
+ "rawSlice": rawIf,
+ "index": index,
+ "result": result,
+ "type": strings.Join(remainingMods, "") + t.NamedType.FullName(),
+ "next": t.unmarshal(result+"["+index+"]", rawIf+"["+index+"]", remainingMods[1:], depth+1),
+ })
+ }
+
+ realResult := result
+ if t.AliasedType != nil {
+ result = "castTmp"
+ }
+
+ return tpl(`{{- if .t.AliasedType }}
+ var castTmp {{.t.FullName}}
+ {{ end }}
+ {{- if eq .t.GoType "map[string]interface{}" }}
+ {{- .result }} = {{.raw}}.(map[string]interface{})
+ {{- else if .t.Marshaler }}
+ {{- .result }}, err = {{ .t.Marshaler.PkgDot }}Unmarshal{{.t.Marshaler.GoType}}({{.raw}})
+ {{- else -}}
+ err = (&{{.result}}).UnmarshalGQL({{.raw}})
+ {{- end }}
+ {{- if .t.AliasedType }}
+ {{ .realResult }} = {{.t.AliasedType.FullName}}(castTmp)
+ {{- end }}`, map[string]interface{}{
+ "realResult": realResult,
+ "result": result,
+ "raw": raw,
+ "t": t,
+ })
+}
+
+func (t Type) Marshal(val string) string {
+ if t.AliasedType != nil {
+ val = t.GoType + "(" + val + ")"
+ }
+
+ if t.Marshaler != nil {
+ return "return " + t.Marshaler.PkgDot() + "Marshal" + t.Marshaler.GoType + "(" + val + ")"
+ }
+
+ return "return " + val
+}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/type_build.go b/vendor/github.com/99designs/gqlgen/codegen/type_build.go
new file mode 100644
index 00000000..f0ec6785
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/type_build.go
@@ -0,0 +1,101 @@
+package codegen
+
+import (
+ "go/types"
+ "strings"
+
+ "github.com/vektah/gqlparser/ast"
+ "golang.org/x/tools/go/loader"
+)
+
+// namedTypeFromSchema objects for every graphql type, including scalars. There should only be one instance of Type for each thing
+func (cfg *Config) buildNamedTypes() NamedTypes {
+ types := map[string]*NamedType{}
+ for _, schemaType := range cfg.schema.Types {
+ t := namedTypeFromSchema(schemaType)
+
+ if userEntry, ok := cfg.Models[t.GQLType]; ok && userEntry.Model != "" {
+ t.IsUserDefined = true
+ t.Package, t.GoType = pkgAndType(userEntry.Model)
+ } else if t.IsScalar {
+ t.Package = "github.com/99designs/gqlgen/graphql"
+ t.GoType = "String"
+ }
+
+ types[t.GQLType] = t
+ }
+ return types
+}
+
+func (cfg *Config) bindTypes(imports *Imports, namedTypes NamedTypes, destDir string, prog *loader.Program) {
+ for _, t := range namedTypes {
+ if t.Package == "" {
+ continue
+ }
+
+ def, _ := findGoType(prog, t.Package, "Marshal"+t.GoType)
+ switch def := def.(type) {
+ case *types.Func:
+ sig := def.Type().(*types.Signature)
+ cpy := t.Ref
+ t.Marshaler = &cpy
+
+ t.Package, t.GoType = pkgAndType(sig.Params().At(0).Type().String())
+ t.Import = imports.add(t.Package)
+ }
+ }
+}
+
+// namedTypeFromSchema objects for every graphql type, including primitives.
+// don't recurse into object fields or interfaces yet, lets make sure we have collected everything first.
+func namedTypeFromSchema(schemaType *ast.Definition) *NamedType {
+ switch schemaType.Kind {
+ case ast.Scalar, ast.Enum:
+ return &NamedType{GQLType: schemaType.Name, IsScalar: true}
+ case ast.Interface, ast.Union:
+ return &NamedType{GQLType: schemaType.Name, IsInterface: true}
+ case ast.InputObject:
+ return &NamedType{GQLType: schemaType.Name, IsInput: true}
+ default:
+ return &NamedType{GQLType: schemaType.Name}
+ }
+}
+
+// take a string in the form github.com/package/blah.Type and split it into package and type
+func pkgAndType(name string) (string, string) {
+ parts := strings.Split(name, ".")
+ if len(parts) == 1 {
+ return "", name
+ }
+
+ return normalizeVendor(strings.Join(parts[:len(parts)-1], ".")), parts[len(parts)-1]
+}
+
+func (n NamedTypes) getType(t *ast.Type) *Type {
+ orig := t
+ var modifiers []string
+ for {
+ if t.Elem != nil {
+ modifiers = append(modifiers, modList)
+ t = t.Elem
+ } else {
+ if !t.NonNull {
+ modifiers = append(modifiers, modPtr)
+ }
+ if n[t.NamedType] == nil {
+ panic("missing type " + t.NamedType)
+ }
+ res := &Type{
+ NamedType: n[t.NamedType],
+ Modifiers: modifiers,
+ ASTType: orig,
+ }
+
+ if res.IsInterface {
+ res.StripPtr()
+ }
+
+ return res
+ }
+ }
+}
diff --git a/vendor/github.com/99designs/gqlgen/codegen/util.go b/vendor/github.com/99designs/gqlgen/codegen/util.go
new file mode 100644
index 00000000..1849f100
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/codegen/util.go
@@ -0,0 +1,367 @@
+package codegen
+
+import (
+ "fmt"
+ "go/types"
+ "reflect"
+ "regexp"
+ "strings"
+
+ "github.com/pkg/errors"
+ "golang.org/x/tools/go/loader"
+)
+
+func findGoType(prog *loader.Program, pkgName string, typeName string) (types.Object, error) {
+ if pkgName == "" {
+ return nil, nil
+ }
+ fullName := typeName
+ if pkgName != "" {
+ fullName = pkgName + "." + typeName
+ }
+
+ pkgName, err := resolvePkg(pkgName)
+ if err != nil {
+ return nil, errors.Errorf("unable to resolve package for %s: %s\n", fullName, err.Error())
+ }
+
+ pkg := prog.Imported[pkgName]
+ if pkg == nil {
+ return nil, errors.Errorf("required package was not loaded: %s", fullName)
+ }
+
+ for astNode, def := range pkg.Defs {
+ if astNode.Name != typeName || def.Parent() == nil || def.Parent() != pkg.Pkg.Scope() {
+ continue
+ }
+
+ return def, nil
+ }
+
+ return nil, errors.Errorf("unable to find type %s\n", fullName)
+}
+
+func findGoNamedType(prog *loader.Program, pkgName string, typeName string) (*types.Named, error) {
+ def, err := findGoType(prog, pkgName, typeName)
+ if err != nil {
+ return nil, err
+ }
+ if def == nil {
+ return nil, nil
+ }
+
+ namedType, ok := def.Type().(*types.Named)
+ if !ok {
+ return nil, errors.Errorf("expected %s to be a named type, instead found %T\n", typeName, def.Type())
+ }
+
+ return namedType, nil
+}
+
+func findGoInterface(prog *loader.Program, pkgName string, typeName string) (*types.Interface, error) {
+ namedType, err := findGoNamedType(prog, pkgName, typeName)
+ if err != nil {
+ return nil, err
+ }
+ if namedType == nil {
+ return nil, nil
+ }
+
+ underlying, ok := namedType.Underlying().(*types.Interface)
+ if !ok {
+ return nil, errors.Errorf("expected %s to be a named interface, instead found %s", typeName, namedType.String())
+ }
+
+ return underlying, nil
+}
+
+func findMethod(typ *types.Named, name string) *types.Func {
+ for i := 0; i < typ.NumMethods(); i++ {
+ method := typ.Method(i)
+ if !method.Exported() {
+ continue
+ }
+
+ if strings.EqualFold(method.Name(), name) {
+ return method
+ }
+ }
+
+ if s, ok := typ.Underlying().(*types.Struct); ok {
+ for i := 0; i < s.NumFields(); i++ {
+ field := s.Field(i)
+ if !field.Anonymous() {
+ continue
+ }
+
+ if named, ok := field.Type().(*types.Named); ok {
+ if f := findMethod(named, name); f != nil {
+ return f
+ }
+ }
+ }
+ }
+
+ return nil
+}
+
+// findField attempts to match the name to a struct field with the following
+// priorites:
+// 1. If struct tag is passed then struct tag has highest priority
+// 2. Field in an embedded struct
+// 3. Actual Field name
+func findField(typ *types.Struct, name, structTag string) (*types.Var, error) {
+ var foundField *types.Var
+ foundFieldWasTag := false
+
+ for i := 0; i < typ.NumFields(); i++ {
+ field := typ.Field(i)
+
+ if structTag != "" {
+ tags := reflect.StructTag(typ.Tag(i))
+ if val, ok := tags.Lookup(structTag); ok {
+ if strings.EqualFold(val, name) {
+ if foundField != nil && foundFieldWasTag {
+ return nil, errors.Errorf("tag %s is ambigious; multiple fields have the same tag value of %s", structTag, val)
+ }
+
+ foundField = field
+ foundFieldWasTag = true
+ }
+ }
+ }
+
+ if field.Anonymous() {
+ if named, ok := field.Type().(*types.Struct); ok {
+ f, err := findField(named, name, structTag)
+ if err != nil && !strings.HasPrefix(err.Error(), "no field named") {
+ return nil, err
+ }
+ if f != nil && foundField == nil {
+ foundField = f
+ }
+ }
+
+ if named, ok := field.Type().Underlying().(*types.Struct); ok {
+ f, err := findField(named, name, structTag)
+ if err != nil && !strings.HasPrefix(err.Error(), "no field named") {
+ return nil, err
+ }
+ if f != nil && foundField == nil {
+ foundField = f
+ }
+ }
+ }
+
+ if !field.Exported() {
+ continue
+ }
+
+ if strings.EqualFold(field.Name(), name) && foundField == nil {
+ foundField = field
+ }
+ }
+
+ if foundField == nil {
+ return nil, fmt.Errorf("no field named %s", name)
+ }
+
+ return foundField, nil
+}
+
+type BindError struct {
+ object *Object
+ field *Field
+ typ types.Type
+ methodErr error
+ varErr error
+}
+
+func (b BindError) Error() string {
+ return fmt.Sprintf(
+ "Unable to bind %s.%s to %s\n %s\n %s",
+ b.object.GQLType,
+ b.field.GQLName,
+ b.typ.String(),
+ b.methodErr.Error(),
+ b.varErr.Error(),
+ )
+}
+
+type BindErrors []BindError
+
+func (b BindErrors) Error() string {
+ var errs []string
+ for _, err := range b {
+ errs = append(errs, err.Error())
+ }
+ return strings.Join(errs, "\n\n")
+}
+
+func bindObject(t types.Type, object *Object, imports *Imports, structTag string) BindErrors {
+ var errs BindErrors
+ for i := range object.Fields {
+ field := &object.Fields[i]
+
+ if field.ForceResolver {
+ continue
+ }
+
+ // first try binding to a method
+ methodErr := bindMethod(imports, t, field)
+ if methodErr == nil {
+ continue
+ }
+
+ // otherwise try binding to a var
+ varErr := bindVar(imports, t, field, structTag)
+
+ if varErr != nil {
+ errs = append(errs, BindError{
+ object: object,
+ typ: t,
+ field: field,
+ varErr: varErr,
+ methodErr: methodErr,
+ })
+ }
+ }
+ return errs
+}
+
+func bindMethod(imports *Imports, t types.Type, field *Field) error {
+ namedType, ok := t.(*types.Named)
+ if !ok {
+ return fmt.Errorf("not a named type")
+ }
+
+ goName := field.GQLName
+ if field.GoFieldName != "" {
+ goName = field.GoFieldName
+ }
+ method := findMethod(namedType, goName)
+ if method == nil {
+ return fmt.Errorf("no method named %s", field.GQLName)
+ }
+ sig := method.Type().(*types.Signature)
+
+ if sig.Results().Len() == 1 {
+ field.NoErr = true
+ } else if sig.Results().Len() != 2 {
+ return fmt.Errorf("method has wrong number of args")
+ }
+ newArgs, err := matchArgs(field, sig.Params())
+ if err != nil {
+ return err
+ }
+
+ result := sig.Results().At(0)
+ if err := validateTypeBinding(imports, field, result.Type()); err != nil {
+ return errors.Wrap(err, "method has wrong return type")
+ }
+
+ // success, args and return type match. Bind to method
+ field.GoFieldType = GoFieldMethod
+ field.GoReceiverName = "obj"
+ field.GoFieldName = method.Name()
+ field.Args = newArgs
+ return nil
+}
+
+func bindVar(imports *Imports, t types.Type, field *Field, structTag string) error {
+ underlying, ok := t.Underlying().(*types.Struct)
+ if !ok {
+ return fmt.Errorf("not a struct")
+ }
+
+ goName := field.GQLName
+ if field.GoFieldName != "" {
+ goName = field.GoFieldName
+ }
+ structField, err := findField(underlying, goName, structTag)
+ if err != nil {
+ return err
+ }
+
+ if err := validateTypeBinding(imports, field, structField.Type()); err != nil {
+ return errors.Wrap(err, "field has wrong type")
+ }
+
+ // success, bind to var
+ field.GoFieldType = GoFieldVariable
+ field.GoReceiverName = "obj"
+ field.GoFieldName = structField.Name()
+ return nil
+}
+
+func matchArgs(field *Field, params *types.Tuple) ([]FieldArgument, error) {
+ var newArgs []FieldArgument
+
+nextArg:
+ for j := 0; j < params.Len(); j++ {
+ param := params.At(j)
+ for _, oldArg := range field.Args {
+ if strings.EqualFold(oldArg.GQLName, param.Name()) {
+ if !field.ForceResolver {
+ oldArg.Type.Modifiers = modifiersFromGoType(param.Type())
+ }
+ newArgs = append(newArgs, oldArg)
+ continue nextArg
+ }
+ }
+
+ // no matching arg found, abort
+ return nil, fmt.Errorf("arg %s not found on method", param.Name())
+ }
+ return newArgs, nil
+}
+
+func validateTypeBinding(imports *Imports, field *Field, goType types.Type) error {
+ gqlType := normalizeVendor(field.Type.FullSignature())
+ goTypeStr := normalizeVendor(goType.String())
+
+ if goTypeStr == gqlType || "*"+goTypeStr == gqlType || goTypeStr == "*"+gqlType {
+ field.Type.Modifiers = modifiersFromGoType(goType)
+ return nil
+ }
+
+ // deal with type aliases
+ underlyingStr := normalizeVendor(goType.Underlying().String())
+ if underlyingStr == gqlType || "*"+underlyingStr == gqlType || underlyingStr == "*"+gqlType {
+ field.Type.Modifiers = modifiersFromGoType(goType)
+ pkg, typ := pkgAndType(goType.String())
+ imp := imports.findByPath(pkg)
+ field.AliasedType = &Ref{GoType: typ, Import: imp}
+ return nil
+ }
+
+ return fmt.Errorf("%s is not compatible with %s", gqlType, goTypeStr)
+}
+
+func modifiersFromGoType(t types.Type) []string {
+ var modifiers []string
+ for {
+ switch val := t.(type) {
+ case *types.Pointer:
+ modifiers = append(modifiers, modPtr)
+ t = val.Elem()
+ case *types.Array:
+ modifiers = append(modifiers, modList)
+ t = val.Elem()
+ case *types.Slice:
+ modifiers = append(modifiers, modList)
+ t = val.Elem()
+ default:
+ return modifiers
+ }
+ }
+}
+
+var modsRegex = regexp.MustCompile(`^(\*|\[\])*`)
+
+func normalizeVendor(pkg string) string {
+ modifiers := modsRegex.FindAllString(pkg, 1)[0]
+ pkg = strings.TrimPrefix(pkg, modifiers)
+ parts := strings.Split(pkg, "/vendor/")
+ return modifiers + parts[len(parts)-1]
+}
diff --git a/vendor/github.com/99designs/gqlgen/complexity/complexity.go b/vendor/github.com/99designs/gqlgen/complexity/complexity.go
new file mode 100644
index 00000000..d5b46bf4
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/complexity/complexity.go
@@ -0,0 +1,104 @@
+package complexity
+
+import (
+ "github.com/99designs/gqlgen/graphql"
+ "github.com/vektah/gqlparser/ast"
+)
+
+func Calculate(es graphql.ExecutableSchema, op *ast.OperationDefinition, vars map[string]interface{}) int {
+ walker := complexityWalker{
+ es: es,
+ schema: es.Schema(),
+ vars: vars,
+ }
+ return walker.selectionSetComplexity(op.SelectionSet)
+}
+
+type complexityWalker struct {
+ es graphql.ExecutableSchema
+ schema *ast.Schema
+ vars map[string]interface{}
+}
+
+func (cw complexityWalker) selectionSetComplexity(selectionSet ast.SelectionSet) int {
+ var complexity int
+ for _, selection := range selectionSet {
+ switch s := selection.(type) {
+ case *ast.Field:
+ fieldDefinition := cw.schema.Types[s.Definition.Type.Name()]
+ var childComplexity int
+ switch fieldDefinition.Kind {
+ case ast.Object, ast.Interface, ast.Union:
+ childComplexity = cw.selectionSetComplexity(s.SelectionSet)
+ }
+
+ args := s.ArgumentMap(cw.vars)
+ var fieldComplexity int
+ if s.ObjectDefinition.Kind == ast.Interface {
+ fieldComplexity = cw.interfaceFieldComplexity(s.ObjectDefinition, s.Name, childComplexity, args)
+ } else {
+ fieldComplexity = cw.fieldComplexity(s.ObjectDefinition.Name, s.Name, childComplexity, args)
+ }
+ complexity = safeAdd(complexity, fieldComplexity)
+
+ case *ast.FragmentSpread:
+ complexity = safeAdd(complexity, cw.selectionSetComplexity(s.Definition.SelectionSet))
+
+ case *ast.InlineFragment:
+ complexity = safeAdd(complexity, cw.selectionSetComplexity(s.SelectionSet))
+ }
+ }
+ return complexity
+}
+
+func (cw complexityWalker) interfaceFieldComplexity(def *ast.Definition, field string, childComplexity int, args map[string]interface{}) int {
+ // Interfaces don't have their own separate field costs, so they have to assume the worst case.
+ // We iterate over all implementors and choose the most expensive one.
+ maxComplexity := 0
+ implementors := cw.schema.GetPossibleTypes(def)
+ for _, t := range implementors {
+ fieldComplexity := cw.fieldComplexity(t.Name, field, childComplexity, args)
+ if fieldComplexity > maxComplexity {
+ maxComplexity = fieldComplexity
+ }
+ }
+ return maxComplexity
+}
+
+func (cw complexityWalker) fieldComplexity(object, field string, childComplexity int, args map[string]interface{}) int {
+ if customComplexity, ok := cw.es.Complexity(object, field, childComplexity, args); ok && customComplexity >= childComplexity {
+ return customComplexity
+ }
+ // default complexity calculation
+ return safeAdd(1, childComplexity)
+}
+
+const maxInt = int(^uint(0) >> 1)
+
+// safeAdd is a saturating add of a and b that ignores negative operands.
+// If a + b would overflow through normal Go addition,
+// it returns the maximum integer value instead.
+//
+// Adding complexities with this function prevents attackers from intentionally
+// overflowing the complexity calculation to allow overly-complex queries.
+//
+// It also helps mitigate the impact of custom complexities that accidentally
+// return negative values.
+func safeAdd(a, b int) int {
+ // Ignore negative operands.
+ if a < 0 {
+ if b < 0 {
+ return 1
+ }
+ return b
+ } else if b < 0 {
+ return a
+ }
+
+ c := a + b
+ if c < a {
+ // Set c to maximum integer instead of overflowing.
+ c = maxInt
+ }
+ return c
+}
diff --git a/vendor/github.com/99designs/gqlgen/graphql/bool.go b/vendor/github.com/99designs/gqlgen/graphql/bool.go
new file mode 100644
index 00000000..7053bbca
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/graphql/bool.go
@@ -0,0 +1,30 @@
+package graphql
+
+import (
+ "fmt"
+ "io"
+ "strings"
+)
+
+func MarshalBoolean(b bool) Marshaler {
+ return WriterFunc(func(w io.Writer) {
+ if b {
+ w.Write(trueLit)
+ } else {
+ w.Write(falseLit)
+ }
+ })
+}
+
+func UnmarshalBoolean(v interface{}) (bool, error) {
+ switch v := v.(type) {
+ case string:
+ return "true" == strings.ToLower(v), nil
+ case int:
+ return v != 0, nil
+ case bool:
+ return v, nil
+ default:
+ return false, fmt.Errorf("%T is not a bool", v)
+ }
+}
diff --git a/vendor/github.com/99designs/gqlgen/graphql/context.go b/vendor/github.com/99designs/gqlgen/graphql/context.go
new file mode 100644
index 00000000..6baee83c
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/graphql/context.go
@@ -0,0 +1,178 @@
+package graphql
+
+import (
+ "context"
+ "fmt"
+ "sync"
+
+ "github.com/vektah/gqlparser/ast"
+ "github.com/vektah/gqlparser/gqlerror"
+)
+
+type Resolver func(ctx context.Context) (res interface{}, err error)
+type FieldMiddleware func(ctx context.Context, next Resolver) (res interface{}, err error)
+type RequestMiddleware func(ctx context.Context, next func(ctx context.Context) []byte) []byte
+
+type RequestContext struct {
+ RawQuery string
+ Variables map[string]interface{}
+ Doc *ast.QueryDocument
+ // ErrorPresenter will be used to generate the error
+ // message from errors given to Error().
+ ErrorPresenter ErrorPresenterFunc
+ Recover RecoverFunc
+ ResolverMiddleware FieldMiddleware
+ DirectiveMiddleware FieldMiddleware
+ RequestMiddleware RequestMiddleware
+
+ errorsMu sync.Mutex
+ Errors gqlerror.List
+}
+
+func DefaultResolverMiddleware(ctx context.Context, next Resolver) (res interface{}, err error) {
+ return next(ctx)
+}
+
+func DefaultDirectiveMiddleware(ctx context.Context, next Resolver) (res interface{}, err error) {
+ return next(ctx)
+}
+
+func DefaultRequestMiddleware(ctx context.Context, next func(ctx context.Context) []byte) []byte {
+ return next(ctx)
+}
+
+func NewRequestContext(doc *ast.QueryDocument, query string, variables map[string]interface{}) *RequestContext {
+ return &RequestContext{
+ Doc: doc,
+ RawQuery: query,
+ Variables: variables,
+ ResolverMiddleware: DefaultResolverMiddleware,
+ DirectiveMiddleware: DefaultDirectiveMiddleware,
+ RequestMiddleware: DefaultRequestMiddleware,
+ Recover: DefaultRecover,
+ ErrorPresenter: DefaultErrorPresenter,
+ }
+}
+
+type key string
+
+const (
+ request key = "request_context"
+ resolver key = "resolver_context"
+)
+
+func GetRequestContext(ctx context.Context) *RequestContext {
+ val := ctx.Value(request)
+ if val == nil {
+ return nil
+ }
+
+ return val.(*RequestContext)
+}
+
+func WithRequestContext(ctx context.Context, rc *RequestContext) context.Context {
+ return context.WithValue(ctx, request, rc)
+}
+
+type ResolverContext struct {
+ Parent *ResolverContext
+ // The name of the type this field belongs to
+ Object string
+ // These are the args after processing, they can be mutated in middleware to change what the resolver will get.
+ Args map[string]interface{}
+ // The raw field
+ Field CollectedField
+ // The index of array in path.
+ Index *int
+ // The result object of resolver
+ Result interface{}
+}
+
+func (r *ResolverContext) Path() []interface{} {
+ var path []interface{}
+ for it := r; it != nil; it = it.Parent {
+ if it.Index != nil {
+ path = append(path, *it.Index)
+ } else if it.Field.Field != nil {
+ path = append(path, it.Field.Alias)
+ }
+ }
+
+ // because we are walking up the chain, all the elements are backwards, do an inplace flip.
+ for i := len(path)/2 - 1; i >= 0; i-- {
+ opp := len(path) - 1 - i
+ path[i], path[opp] = path[opp], path[i]
+ }
+
+ return path
+}
+
+func GetResolverContext(ctx context.Context) *ResolverContext {
+ val, _ := ctx.Value(resolver).(*ResolverContext)
+ return val
+}
+
+func WithResolverContext(ctx context.Context, rc *ResolverContext) context.Context {
+ rc.Parent = GetResolverContext(ctx)
+ return context.WithValue(ctx, resolver, rc)
+}
+
+// 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)
+}
+
+// Errorf sends an error string to the client, passing it through the formatter.
+func (c *RequestContext) Errorf(ctx context.Context, format string, args ...interface{}) {
+ c.errorsMu.Lock()
+ defer c.errorsMu.Unlock()
+
+ c.Errors = append(c.Errors, c.ErrorPresenter(ctx, fmt.Errorf(format, args...)))
+}
+
+// Error sends an error to the client, passing it through the formatter.
+func (c *RequestContext) Error(ctx context.Context, err error) {
+ c.errorsMu.Lock()
+ defer c.errorsMu.Unlock()
+
+ c.Errors = append(c.Errors, c.ErrorPresenter(ctx, err))
+}
+
+// HasError returns true if the current field has already errored
+func (c *RequestContext) HasError(rctx *ResolverContext) bool {
+ c.errorsMu.Lock()
+ defer c.errorsMu.Unlock()
+ path := rctx.Path()
+
+ for _, err := range c.Errors {
+ if equalPath(err.Path, path) {
+ return true
+ }
+ }
+ return false
+}
+
+func equalPath(a []interface{}, b []interface{}) bool {
+ if len(a) != len(b) {
+ return false
+ }
+
+ for i := 0; i < len(a); i++ {
+ if a[i] != b[i] {
+ return false
+ }
+ }
+
+ return true
+}
+
+// AddError is a convenience method for adding an error to the current response
+func AddError(ctx context.Context, err error) {
+ GetRequestContext(ctx).Error(ctx, err)
+}
+
+// AddErrorf is a convenience method for adding an error to the current response
+func AddErrorf(ctx context.Context, format string, args ...interface{}) {
+ GetRequestContext(ctx).Errorf(ctx, format, args...)
+}
diff --git a/vendor/github.com/99designs/gqlgen/graphql/error.go b/vendor/github.com/99designs/gqlgen/graphql/error.go
new file mode 100644
index 00000000..7f161a43
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/graphql/error.go
@@ -0,0 +1,31 @@
+package graphql
+
+import (
+ "context"
+
+ "github.com/vektah/gqlparser/gqlerror"
+)
+
+type ErrorPresenterFunc func(context.Context, error) *gqlerror.Error
+
+type ExtendedError interface {
+ Extensions() map[string]interface{}
+}
+
+func DefaultErrorPresenter(ctx context.Context, err error) *gqlerror.Error {
+ if gqlerr, ok := err.(*gqlerror.Error); ok {
+ gqlerr.Path = GetResolverContext(ctx).Path()
+ return gqlerr
+ }
+
+ var extensions map[string]interface{}
+ if ee, ok := err.(ExtendedError); ok {
+ extensions = ee.Extensions()
+ }
+
+ return &gqlerror.Error{
+ Message: err.Error(),
+ Path: GetResolverContext(ctx).Path(),
+ Extensions: extensions,
+ }
+}
diff --git a/vendor/github.com/99designs/gqlgen/graphql/exec.go b/vendor/github.com/99designs/gqlgen/graphql/exec.go
new file mode 100644
index 00000000..9beb3149
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/graphql/exec.go
@@ -0,0 +1,135 @@
+package graphql
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/vektah/gqlparser/ast"
+)
+
+type ExecutableSchema interface {
+ Schema() *ast.Schema
+
+ Complexity(typeName, fieldName string, childComplexity int, args map[string]interface{}) (int, bool)
+ Query(ctx context.Context, op *ast.OperationDefinition) *Response
+ Mutation(ctx context.Context, op *ast.OperationDefinition) *Response
+ Subscription(ctx context.Context, op *ast.OperationDefinition) func() *Response
+}
+
+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, visited map[string]bool) []CollectedField {
+ var groupedFields []CollectedField
+
+ for _, sel := range selSet {
+ switch sel := sel.(type) {
+ case *ast.Field:
+ if !shouldIncludeNode(sel.Directives, reqCtx.Variables) {
+ continue
+ }
+ f := getOrCreateField(&groupedFields, sel.Alias, func() CollectedField {
+ return CollectedField{Field: sel}
+ })
+
+ f.Selections = append(f.Selections, sel.SelectionSet...)
+ case *ast.InlineFragment:
+ if !shouldIncludeNode(sel.Directives, reqCtx.Variables) || !instanceOf(sel.TypeCondition, satisfies) {
+ continue
+ }
+ for _, childField := range collectFields(reqCtx, sel.SelectionSet, satisfies, visited) {
+ f := getOrCreateField(&groupedFields, childField.Name, func() CollectedField { return childField })
+ f.Selections = append(f.Selections, childField.Selections...)
+ }
+
+ case *ast.FragmentSpread:
+ if !shouldIncludeNode(sel.Directives, reqCtx.Variables) {
+ continue
+ }
+ fragmentName := sel.Name
+ if _, seen := visited[fragmentName]; seen {
+ continue
+ }
+ visited[fragmentName] = true
+
+ fragment := reqCtx.Doc.Fragments.ForName(fragmentName)
+ if fragment == nil {
+ // should never happen, validator has already run
+ panic(fmt.Errorf("missing fragment %s", fragmentName))
+ }
+
+ if !instanceOf(fragment.TypeCondition, satisfies) {
+ continue
+ }
+
+ for _, childField := range collectFields(reqCtx, fragment.SelectionSet, satisfies, visited) {
+ f := getOrCreateField(&groupedFields, childField.Name, func() CollectedField { return childField })
+ f.Selections = append(f.Selections, childField.Selections...)
+ }
+
+ default:
+ panic(fmt.Errorf("unsupported %T", sel))
+ }
+ }
+
+ return groupedFields
+}
+
+type CollectedField struct {
+ *ast.Field
+
+ Selections ast.SelectionSet
+}
+
+func instanceOf(val string, satisfies []string) bool {
+ for _, s := range satisfies {
+ if val == s {
+ return true
+ }
+ }
+ return false
+}
+
+func getOrCreateField(c *[]CollectedField, name string, creator func() CollectedField) *CollectedField {
+ for i, cf := range *c {
+ if cf.Alias == name {
+ return &(*c)[i]
+ }
+ }
+
+ f := creator()
+
+ *c = append(*c, f)
+ return &(*c)[len(*c)-1]
+}
+
+func shouldIncludeNode(directives ast.DirectiveList, variables map[string]interface{}) bool {
+ skip, include := false, true
+
+ if d := directives.ForName("skip"); d != nil {
+ skip = resolveIfArgument(d, variables)
+ }
+
+ if d := directives.ForName("include"); d != nil {
+ include = resolveIfArgument(d, variables)
+ }
+
+ return !skip && include
+}
+
+func resolveIfArgument(d *ast.Directive, variables map[string]interface{}) bool {
+ arg := d.Arguments.ForName("if")
+ if arg == nil {
+ panic(fmt.Sprintf("%s: argument 'if' not defined", d.Name))
+ }
+ value, err := arg.Value.Value(variables)
+ if err != nil {
+ panic(err)
+ }
+ ret, ok := value.(bool)
+ if !ok {
+ panic(fmt.Sprintf("%s: argument 'if' is not a boolean", d.Name))
+ }
+ return ret
+}
diff --git a/vendor/github.com/99designs/gqlgen/graphql/float.go b/vendor/github.com/99designs/gqlgen/graphql/float.go
new file mode 100644
index 00000000..d204335c
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/graphql/float.go
@@ -0,0 +1,31 @@
+package graphql
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "strconv"
+)
+
+func MarshalFloat(f float64) Marshaler {
+ return WriterFunc(func(w io.Writer) {
+ io.WriteString(w, fmt.Sprintf("%f", f))
+ })
+}
+
+func UnmarshalFloat(v interface{}) (float64, error) {
+ switch v := v.(type) {
+ case string:
+ return strconv.ParseFloat(v, 64)
+ case int:
+ return float64(v), nil
+ case int64:
+ return float64(v), nil
+ case float64:
+ return v, nil
+ case json.Number:
+ return strconv.ParseFloat(string(v), 64)
+ default:
+ return 0, fmt.Errorf("%T is not an float", v)
+ }
+}
diff --git a/vendor/github.com/99designs/gqlgen/graphql/id.go b/vendor/github.com/99designs/gqlgen/graphql/id.go
new file mode 100644
index 00000000..a5a7960f
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/graphql/id.go
@@ -0,0 +1,36 @@
+package graphql
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "strconv"
+)
+
+func MarshalID(s string) Marshaler {
+ return WriterFunc(func(w io.Writer) {
+ io.WriteString(w, strconv.Quote(s))
+ })
+}
+func UnmarshalID(v interface{}) (string, error) {
+ switch v := v.(type) {
+ case string:
+ return v, nil
+ case json.Number:
+ return string(v), nil
+ case int:
+ return strconv.Itoa(v), nil
+ case float64:
+ return fmt.Sprintf("%f", v), nil
+ case bool:
+ if v {
+ return "true", nil
+ } else {
+ return "false", nil
+ }
+ case nil:
+ return "null", nil
+ default:
+ return "", fmt.Errorf("%T is not a string", v)
+ }
+}
diff --git a/vendor/github.com/99designs/gqlgen/graphql/int.go b/vendor/github.com/99designs/gqlgen/graphql/int.go
new file mode 100644
index 00000000..ff87574c
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/graphql/int.go
@@ -0,0 +1,29 @@
+package graphql
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "strconv"
+)
+
+func MarshalInt(i int) Marshaler {
+ return WriterFunc(func(w io.Writer) {
+ io.WriteString(w, strconv.Itoa(i))
+ })
+}
+
+func UnmarshalInt(v interface{}) (int, error) {
+ switch v := v.(type) {
+ case string:
+ return strconv.Atoi(v)
+ case int:
+ return v, nil
+ case int64:
+ return int(v), nil
+ case json.Number:
+ return strconv.Atoi(string(v))
+ default:
+ return 0, fmt.Errorf("%T is not an int", v)
+ }
+}
diff --git a/vendor/github.com/99designs/gqlgen/graphql/introspection/introspection.go b/vendor/github.com/99designs/gqlgen/graphql/introspection/introspection.go
new file mode 100644
index 00000000..baff882e
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/graphql/introspection/introspection.go
@@ -0,0 +1,58 @@
+// introspection implements the spec defined in https://github.com/facebook/graphql/blob/master/spec/Section%204%20--%20Introspection.md#schema-introspection
+package introspection
+
+import "github.com/vektah/gqlparser/ast"
+
+type (
+ Directive struct {
+ Name string
+ Description string
+ Locations []string
+ Args []InputValue
+ }
+
+ EnumValue struct {
+ Name string
+ Description string
+ IsDeprecated bool
+ DeprecationReason string
+ }
+
+ Field struct {
+ Name string
+ Description string
+ Type *Type
+ Args []InputValue
+ IsDeprecated bool
+ DeprecationReason string
+ }
+
+ InputValue struct {
+ Name string
+ Description string
+ DefaultValue *string
+ Type *Type
+ }
+)
+
+func WrapSchema(schema *ast.Schema) *Schema {
+ return &Schema{schema: schema}
+}
+
+func isDeprecated(directives ast.DirectiveList) bool {
+ return directives.ForName("deprecated") != nil
+}
+
+func deprecationReason(directives ast.DirectiveList) string {
+ deprecation := directives.ForName("deprecated")
+ if deprecation == nil {
+ return ""
+ }
+
+ reason := deprecation.Arguments.ForName("reason")
+ if reason == nil {
+ return ""
+ }
+
+ return reason.Value.Raw
+}
diff --git a/vendor/github.com/99designs/gqlgen/graphql/introspection/query.go b/vendor/github.com/99designs/gqlgen/graphql/introspection/query.go
new file mode 100644
index 00000000..b1e4fbc6
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/graphql/introspection/query.go
@@ -0,0 +1,104 @@
+package introspection
+
+// Query is the query generated by graphiql to determine type information
+const Query = `
+query IntrospectionQuery {
+ __schema {
+ queryType {
+ name
+ }
+ mutationType {
+ name
+ }
+ subscriptionType {
+ name
+ }
+ types {
+ ...FullType
+ }
+ directives {
+ name
+ description
+ locations
+ args {
+ ...InputValue
+ }
+ }
+ }
+}
+
+fragment FullType on __Type {
+ kind
+ name
+ description
+ fields(includeDeprecated: true) {
+ name
+ description
+ args {
+ ...InputValue
+ }
+ type {
+ ...TypeRef
+ }
+ isDeprecated
+ deprecationReason
+ }
+ inputFields {
+ ...InputValue
+ }
+ interfaces {
+ ...TypeRef
+ }
+ enumValues(includeDeprecated: true) {
+ name
+ description
+ isDeprecated
+ deprecationReason
+ }
+ possibleTypes {
+ ...TypeRef
+ }
+}
+
+fragment InputValue on __InputValue {
+ name
+ description
+ type {
+ ...TypeRef
+ }
+ defaultValue
+}
+
+fragment TypeRef on __Type {
+ kind
+ name
+ ofType {
+ kind
+ name
+ ofType {
+ kind
+ name
+ ofType {
+ kind
+ name
+ ofType {
+ kind
+ name
+ ofType {
+ kind
+ name
+ ofType {
+ kind
+ name
+ ofType {
+ kind
+ name
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+`
diff --git a/vendor/github.com/99designs/gqlgen/graphql/introspection/schema.go b/vendor/github.com/99designs/gqlgen/graphql/introspection/schema.go
new file mode 100644
index 00000000..b5d2c482
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/graphql/introspection/schema.go
@@ -0,0 +1,68 @@
+package introspection
+
+import (
+ "strings"
+
+ "github.com/vektah/gqlparser/ast"
+)
+
+type Schema struct {
+ schema *ast.Schema
+}
+
+func (s *Schema) Types() []Type {
+ var types []Type
+ for _, typ := range s.schema.Types {
+ if strings.HasPrefix(typ.Name, "__") {
+ continue
+ }
+ types = append(types, *WrapTypeFromDef(s.schema, typ))
+ }
+ return types
+}
+
+func (s *Schema) QueryType() *Type {
+ return WrapTypeFromDef(s.schema, s.schema.Query)
+}
+
+func (s *Schema) MutationType() *Type {
+ return WrapTypeFromDef(s.schema, s.schema.Mutation)
+}
+
+func (s *Schema) SubscriptionType() *Type {
+ return WrapTypeFromDef(s.schema, s.schema.Subscription)
+}
+
+func (s *Schema) Directives() []Directive {
+ var res []Directive
+
+ for _, d := range s.schema.Directives {
+ res = append(res, s.directiveFromDef(d))
+ }
+
+ return res
+}
+
+func (s *Schema) directiveFromDef(d *ast.DirectiveDefinition) Directive {
+ var locs []string
+ for _, loc := range d.Locations {
+ locs = append(locs, string(loc))
+ }
+
+ var args []InputValue
+ for _, arg := range d.Arguments {
+ args = append(args, InputValue{
+ Name: arg.Name,
+ Description: arg.Description,
+ DefaultValue: defaultValue(arg.DefaultValue),
+ Type: WrapTypeFromType(s.schema, arg.Type),
+ })
+ }
+
+ return Directive{
+ Name: d.Name,
+ Description: d.Description,
+ Locations: locs,
+ Args: args,
+ }
+}
diff --git a/vendor/github.com/99designs/gqlgen/graphql/introspection/type.go b/vendor/github.com/99designs/gqlgen/graphql/introspection/type.go
new file mode 100644
index 00000000..dce144e0
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/graphql/introspection/type.go
@@ -0,0 +1,174 @@
+package introspection
+
+import (
+ "strings"
+
+ "github.com/vektah/gqlparser/ast"
+)
+
+type Type struct {
+ schema *ast.Schema
+ def *ast.Definition
+ typ *ast.Type
+}
+
+func WrapTypeFromDef(s *ast.Schema, def *ast.Definition) *Type {
+ if def == nil {
+ return nil
+ }
+ return &Type{schema: s, def: def}
+}
+
+func WrapTypeFromType(s *ast.Schema, typ *ast.Type) *Type {
+ if typ == nil {
+ return nil
+ }
+
+ if !typ.NonNull && typ.NamedType != "" {
+ return &Type{schema: s, def: s.Types[typ.NamedType]}
+ }
+ return &Type{schema: s, typ: typ}
+}
+
+func (t *Type) Kind() string {
+ if t.typ != nil {
+ if t.typ.NonNull {
+ return "NON_NULL"
+ }
+
+ if t.typ.Elem != nil {
+ return "LIST"
+ }
+ } else {
+ return string(t.def.Kind)
+ }
+
+ panic("UNKNOWN")
+}
+
+func (t *Type) Name() *string {
+ if t.def == nil {
+ return nil
+ }
+ return &t.def.Name
+}
+
+func (t *Type) Description() string {
+ if t.def == nil {
+ return ""
+ }
+ return t.def.Description
+}
+
+func (t *Type) Fields(includeDeprecated bool) []Field {
+ if t.def == nil || (t.def.Kind != ast.Object && t.def.Kind != ast.Interface) {
+ return nil
+ }
+ var fields []Field
+ for _, f := range t.def.Fields {
+ if strings.HasPrefix(f.Name, "__") {
+ continue
+ }
+
+ var args []InputValue
+ for _, arg := range f.Arguments {
+ args = append(args, InputValue{
+ Type: WrapTypeFromType(t.schema, arg.Type),
+ Name: arg.Name,
+ Description: arg.Description,
+ DefaultValue: defaultValue(arg.DefaultValue),
+ })
+ }
+
+ fields = append(fields, Field{
+ Name: f.Name,
+ Description: f.Description,
+ Args: args,
+ Type: WrapTypeFromType(t.schema, f.Type),
+ IsDeprecated: isDeprecated(f.Directives),
+ DeprecationReason: deprecationReason(f.Directives),
+ })
+ }
+ return fields
+}
+
+func (t *Type) InputFields() []InputValue {
+ if t.def == nil || t.def.Kind != ast.InputObject {
+ return nil
+ }
+
+ var res []InputValue
+ for _, f := range t.def.Fields {
+ res = append(res, InputValue{
+ Name: f.Name,
+ Description: f.Description,
+ Type: WrapTypeFromType(t.schema, f.Type),
+ DefaultValue: defaultValue(f.DefaultValue),
+ })
+ }
+ return res
+}
+
+func defaultValue(value *ast.Value) *string {
+ if value == nil {
+ return nil
+ }
+ val := value.String()
+ return &val
+}
+
+func (t *Type) Interfaces() []Type {
+ if t.def == nil || t.def.Kind != ast.Object {
+ return nil
+ }
+
+ var res []Type
+ for _, intf := range t.def.Interfaces {
+ res = append(res, *WrapTypeFromDef(t.schema, t.schema.Types[intf]))
+ }
+
+ return res
+}
+
+func (t *Type) PossibleTypes() []Type {
+ if t.def == nil || (t.def.Kind != ast.Interface && t.def.Kind != ast.Union) {
+ return nil
+ }
+
+ var res []Type
+ for _, pt := range t.schema.GetPossibleTypes(t.def) {
+ res = append(res, *WrapTypeFromDef(t.schema, pt))
+ }
+ return res
+}
+
+func (t *Type) EnumValues(includeDeprecated bool) []EnumValue {
+ if t.def == nil || t.def.Kind != ast.Enum {
+ return nil
+ }
+
+ var res []EnumValue
+ for _, val := range t.def.EnumValues {
+ res = append(res, EnumValue{
+ Name: val.Name,
+ Description: val.Description,
+ IsDeprecated: isDeprecated(val.Directives),
+ DeprecationReason: deprecationReason(val.Directives),
+ })
+ }
+ return res
+}
+
+func (t *Type) OfType() *Type {
+ if t.typ == nil {
+ return nil
+ }
+ if t.typ.NonNull {
+ // fake non null nodes
+ cpy := *t.typ
+ cpy.NonNull = false
+
+ return WrapTypeFromType(t.schema, &cpy)
+ }
+ return WrapTypeFromType(t.schema, t.typ.Elem)
+}
diff --git a/vendor/github.com/99designs/gqlgen/graphql/jsonw.go b/vendor/github.com/99designs/gqlgen/graphql/jsonw.go
new file mode 100644
index 00000000..c112444a
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/graphql/jsonw.go
@@ -0,0 +1,83 @@
+package graphql
+
+import (
+ "io"
+ "strconv"
+)
+
+var nullLit = []byte(`null`)
+var trueLit = []byte(`true`)
+var falseLit = []byte(`false`)
+var openBrace = []byte(`{`)
+var closeBrace = []byte(`}`)
+var openBracket = []byte(`[`)
+var closeBracket = []byte(`]`)
+var colon = []byte(`:`)
+var comma = []byte(`,`)
+
+var Null = &lit{nullLit}
+var True = &lit{trueLit}
+var False = &lit{falseLit}
+
+type Marshaler interface {
+ MarshalGQL(w io.Writer)
+}
+
+type Unmarshaler interface {
+ UnmarshalGQL(v interface{}) error
+}
+
+type OrderedMap struct {
+ Keys []string
+ Values []Marshaler
+}
+
+type WriterFunc func(writer io.Writer)
+
+func (f WriterFunc) MarshalGQL(w io.Writer) {
+ f(w)
+}
+
+func NewOrderedMap(len int) *OrderedMap {
+ return &OrderedMap{
+ Keys: make([]string, len),
+ Values: make([]Marshaler, len),
+ }
+}
+
+func (m *OrderedMap) Add(key string, value Marshaler) {
+ m.Keys = append(m.Keys, key)
+ m.Values = append(m.Values, value)
+}
+
+func (m *OrderedMap) MarshalGQL(writer io.Writer) {
+ writer.Write(openBrace)
+ for i, key := range m.Keys {
+ if i != 0 {
+ writer.Write(comma)
+ }
+ io.WriteString(writer, strconv.Quote(key))
+ writer.Write(colon)
+ m.Values[i].MarshalGQL(writer)
+ }
+ writer.Write(closeBrace)
+}
+
+type Array []Marshaler
+
+func (a Array) MarshalGQL(writer io.Writer) {
+ writer.Write(openBracket)
+ for i, val := range a {
+ if i != 0 {
+ writer.Write(comma)
+ }
+ val.MarshalGQL(writer)
+ }
+ writer.Write(closeBracket)
+}
+
+type lit struct{ b []byte }
+
+func (l lit) MarshalGQL(w io.Writer) {
+ w.Write(l.b)
+}
diff --git a/vendor/github.com/99designs/gqlgen/graphql/map.go b/vendor/github.com/99designs/gqlgen/graphql/map.go
new file mode 100644
index 00000000..1e91d1d9
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/graphql/map.go
@@ -0,0 +1,24 @@
+package graphql
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+)
+
+func MarshalMap(val map[string]interface{}) Marshaler {
+ return WriterFunc(func(w io.Writer) {
+ err := json.NewEncoder(w).Encode(val)
+ if err != nil {
+ panic(err)
+ }
+ })
+}
+
+func UnmarshalMap(v interface{}) (map[string]interface{}, error) {
+ if m, ok := v.(map[string]interface{}); ok {
+ return m, nil
+ }
+
+ return nil, fmt.Errorf("%T is not a map", v)
+}
diff --git a/vendor/github.com/99designs/gqlgen/graphql/oneshot.go b/vendor/github.com/99designs/gqlgen/graphql/oneshot.go
new file mode 100644
index 00000000..dd31f5ba
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/graphql/oneshot.go
@@ -0,0 +1,14 @@
+package graphql
+
+func OneShot(resp *Response) func() *Response {
+ var oneshot bool
+
+ return func() *Response {
+ if oneshot {
+ return nil
+ }
+ oneshot = true
+
+ return resp
+ }
+}
diff --git a/vendor/github.com/99designs/gqlgen/graphql/recovery.go b/vendor/github.com/99designs/gqlgen/graphql/recovery.go
new file mode 100644
index 00000000..3aa032dc
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/graphql/recovery.go
@@ -0,0 +1,19 @@
+package graphql
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "os"
+ "runtime/debug"
+)
+
+type RecoverFunc func(ctx context.Context, err interface{}) (userMessage error)
+
+func DefaultRecover(ctx context.Context, err interface{}) error {
+ fmt.Fprintln(os.Stderr, err)
+ fmt.Fprintln(os.Stderr)
+ debug.PrintStack()
+
+ return errors.New("internal system error")
+}
diff --git a/vendor/github.com/99designs/gqlgen/graphql/response.go b/vendor/github.com/99designs/gqlgen/graphql/response.go
new file mode 100644
index 00000000..18664dca
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/graphql/response.go
@@ -0,0 +1,20 @@
+package graphql
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+
+ "github.com/vektah/gqlparser/gqlerror"
+)
+
+type Response struct {
+ Data json.RawMessage `json:"data"`
+ Errors gqlerror.List `json:"errors,omitempty"`
+}
+
+func ErrorResponse(ctx context.Context, messagef string, args ...interface{}) *Response {
+ return &Response{
+ Errors: gqlerror.List{{Message: fmt.Sprintf(messagef, args...)}},
+ }
+}
diff --git a/vendor/github.com/99designs/gqlgen/graphql/string.go b/vendor/github.com/99designs/gqlgen/graphql/string.go
new file mode 100644
index 00000000..d5fb3294
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/graphql/string.go
@@ -0,0 +1,63 @@
+package graphql
+
+import (
+ "fmt"
+ "io"
+ "strconv"
+)
+
+const encodeHex = "0123456789ABCDEF"
+
+func MarshalString(s string) Marshaler {
+ return WriterFunc(func(w io.Writer) {
+ start := 0
+ io.WriteString(w, `"`)
+
+ for i, c := range s {
+ if c < 0x20 || c == '\\' || c == '"' {
+ io.WriteString(w, s[start:i])
+
+ switch c {
+ case '\t':
+ io.WriteString(w, `\t`)
+ case '\r':
+ io.WriteString(w, `\r`)
+ case '\n':
+ io.WriteString(w, `\n`)
+ case '\\':
+ io.WriteString(w, `\\`)
+ case '"':
+ io.WriteString(w, `\"`)
+ default:
+ io.WriteString(w, `\u00`)
+ w.Write([]byte{encodeHex[c>>4], encodeHex[c&0xf]})
+ }
+
+ start = i + 1
+ }
+ }
+
+ io.WriteString(w, s[start:])
+ io.WriteString(w, `"`)
+ })
+}
+func UnmarshalString(v interface{}) (string, error) {
+ switch v := v.(type) {
+ case string:
+ return v, nil
+ case int:
+ return strconv.Itoa(v), nil
+ case float64:
+ return fmt.Sprintf("%f", v), nil
+ case bool:
+ if v {
+ return "true", nil
+ } else {
+ return "false", nil
+ }
+ case nil:
+ return "null", nil
+ default:
+ return "", fmt.Errorf("%T is not a string", v)
+ }
+}
diff --git a/vendor/github.com/99designs/gqlgen/graphql/time.go b/vendor/github.com/99designs/gqlgen/graphql/time.go
new file mode 100644
index 00000000..4f448560
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/graphql/time.go
@@ -0,0 +1,21 @@
+package graphql
+
+import (
+ "errors"
+ "io"
+ "strconv"
+ "time"
+)
+
+func MarshalTime(t time.Time) Marshaler {
+ return WriterFunc(func(w io.Writer) {
+ io.WriteString(w, strconv.Quote(t.Format(time.RFC3339)))
+ })
+}
+
+func UnmarshalTime(v interface{}) (time.Time, error) {
+ if tmpStr, ok := v.(string); ok {
+ return time.Parse(time.RFC3339, tmpStr)
+ }
+ return time.Time{}, errors.New("time should be RFC3339 formatted string")
+}
diff --git a/vendor/github.com/99designs/gqlgen/graphql/version.go b/vendor/github.com/99designs/gqlgen/graphql/version.go
new file mode 100644
index 00000000..38d3720b
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/graphql/version.go
@@ -0,0 +1,3 @@
+package graphql
+
+const Version = "v0.5.1"
diff --git a/vendor/github.com/99designs/gqlgen/handler/graphql.go b/vendor/github.com/99designs/gqlgen/handler/graphql.go
new file mode 100644
index 00000000..9d222826
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/handler/graphql.go
@@ -0,0 +1,283 @@
+package handler
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+
+ "github.com/99designs/gqlgen/complexity"
+ "github.com/99designs/gqlgen/graphql"
+ "github.com/gorilla/websocket"
+ "github.com/hashicorp/golang-lru"
+ "github.com/vektah/gqlparser"
+ "github.com/vektah/gqlparser/ast"
+ "github.com/vektah/gqlparser/gqlerror"
+ "github.com/vektah/gqlparser/validator"
+)
+
+type params struct {
+ Query string `json:"query"`
+ OperationName string `json:"operationName"`
+ Variables map[string]interface{} `json:"variables"`
+}
+
+type Config struct {
+ cacheSize int
+ upgrader websocket.Upgrader
+ recover graphql.RecoverFunc
+ errorPresenter graphql.ErrorPresenterFunc
+ resolverHook graphql.FieldMiddleware
+ requestHook graphql.RequestMiddleware
+ complexityLimit int
+}
+
+func (c *Config) newRequestContext(doc *ast.QueryDocument, query string, variables map[string]interface{}) *graphql.RequestContext {
+ reqCtx := graphql.NewRequestContext(doc, query, variables)
+ if hook := c.recover; hook != nil {
+ reqCtx.Recover = hook
+ }
+
+ if hook := c.errorPresenter; hook != nil {
+ reqCtx.ErrorPresenter = hook
+ }
+
+ if hook := c.resolverHook; hook != nil {
+ reqCtx.ResolverMiddleware = hook
+ }
+
+ if hook := c.requestHook; hook != nil {
+ reqCtx.RequestMiddleware = hook
+ }
+
+ return reqCtx
+}
+
+type Option func(cfg *Config)
+
+func WebsocketUpgrader(upgrader websocket.Upgrader) Option {
+ return func(cfg *Config) {
+ cfg.upgrader = upgrader
+ }
+}
+
+func RecoverFunc(recover graphql.RecoverFunc) Option {
+ return func(cfg *Config) {
+ cfg.recover = recover
+ }
+}
+
+// ErrorPresenter transforms errors found while resolving into errors that will be returned to the user. It provides
+// a good place to add any extra fields, like error.type, that might be desired by your frontend. Check the default
+// implementation in graphql.DefaultErrorPresenter for an example.
+func ErrorPresenter(f graphql.ErrorPresenterFunc) Option {
+ return func(cfg *Config) {
+ cfg.errorPresenter = f
+ }
+}
+
+// ComplexityLimit sets a maximum query complexity that is allowed to be executed.
+// If a query is submitted that exceeds the limit, a 422 status code will be returned.
+func ComplexityLimit(limit int) Option {
+ return func(cfg *Config) {
+ cfg.complexityLimit = limit
+ }
+}
+
+// ResolverMiddleware allows you to define a function that will be called around every resolver,
+// useful for tracing and logging.
+func ResolverMiddleware(middleware graphql.FieldMiddleware) Option {
+ return func(cfg *Config) {
+ if cfg.resolverHook == nil {
+ cfg.resolverHook = middleware
+ return
+ }
+
+ lastResolve := cfg.resolverHook
+ cfg.resolverHook = func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
+ return lastResolve(ctx, func(ctx context.Context) (res interface{}, err error) {
+ return middleware(ctx, next)
+ })
+ }
+ }
+}
+
+// RequestMiddleware allows you to define a function that will be called around the root request,
+// after the query has been parsed. This is useful for logging and tracing
+func RequestMiddleware(middleware graphql.RequestMiddleware) Option {
+ return func(cfg *Config) {
+ if cfg.requestHook == nil {
+ cfg.requestHook = middleware
+ return
+ }
+
+ lastResolve := cfg.requestHook
+ cfg.requestHook = func(ctx context.Context, next func(ctx context.Context) []byte) []byte {
+ return lastResolve(ctx, func(ctx context.Context) []byte {
+ return middleware(ctx, next)
+ })
+ }
+ }
+}
+
+// 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 {
+ return func(cfg *Config) {
+ cfg.cacheSize = size
+ }
+}
+
+const DefaultCacheSize = 1000
+
+func GraphQL(exec graphql.ExecutableSchema, options ...Option) http.HandlerFunc {
+ cfg := Config{
+ cacheSize: DefaultCacheSize,
+ upgrader: websocket.Upgrader{
+ ReadBufferSize: 1024,
+ WriteBufferSize: 1024,
+ },
+ }
+
+ for _, option := range options {
+ option(&cfg)
+ }
+
+ var cache *lru.Cache
+ if cfg.cacheSize > 0 {
+ var err error
+ cache, err = lru.New(DefaultCacheSize)
+ if err != nil {
+ // An error is only returned for non-positive cache size
+ // and we already checked for that.
+ panic("unexpected error creating cache: " + err.Error())
+ }
+ }
+
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == http.MethodOptions {
+ w.Header().Set("Allow", "OPTIONS, GET, POST")
+ w.WriteHeader(http.StatusOK)
+ return
+ }
+
+ if strings.Contains(r.Header.Get("Upgrade"), "websocket") {
+ connectWs(exec, w, r, &cfg)
+ return
+ }
+
+ var reqParams params
+ switch r.Method {
+ case http.MethodGet:
+ reqParams.Query = r.URL.Query().Get("query")
+ reqParams.OperationName = r.URL.Query().Get("operationName")
+
+ if variables := r.URL.Query().Get("variables"); variables != "" {
+ if err := jsonDecode(strings.NewReader(variables), &reqParams.Variables); err != nil {
+ sendErrorf(w, http.StatusBadRequest, "variables could not be decoded")
+ return
+ }
+ }
+ case http.MethodPost:
+ if err := jsonDecode(r.Body, &reqParams); err != nil {
+ sendErrorf(w, http.StatusBadRequest, "json body could not be decoded: "+err.Error())
+ return
+ }
+ default:
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ return
+ }
+ w.Header().Set("Content-Type", "application/json")
+
+ var doc *ast.QueryDocument
+ if cache != nil {
+ val, ok := cache.Get(reqParams.Query)
+ if ok {
+ doc = val.(*ast.QueryDocument)
+ }
+ }
+ if doc == nil {
+ var qErr gqlerror.List
+ doc, qErr = gqlparser.LoadQuery(exec.Schema(), reqParams.Query)
+ if len(qErr) > 0 {
+ sendError(w, http.StatusUnprocessableEntity, qErr...)
+ return
+ }
+ if cache != nil {
+ cache.Add(reqParams.Query, doc)
+ }
+ }
+
+ op := doc.Operations.ForName(reqParams.OperationName)
+ if op == nil {
+ sendErrorf(w, http.StatusUnprocessableEntity, "operation %s not found", reqParams.OperationName)
+ return
+ }
+
+ if op.Operation != ast.Query && r.Method == http.MethodGet {
+ sendErrorf(w, http.StatusUnprocessableEntity, "GET requests only allow query operations")
+ return
+ }
+
+ vars, err := validator.VariableValues(exec.Schema(), op, reqParams.Variables)
+ if err != nil {
+ sendError(w, http.StatusUnprocessableEntity, err)
+ return
+ }
+ reqCtx := cfg.newRequestContext(doc, reqParams.Query, vars)
+ ctx := graphql.WithRequestContext(r.Context(), reqCtx)
+
+ defer func() {
+ if err := recover(); err != nil {
+ userErr := reqCtx.Recover(ctx, err)
+ sendErrorf(w, http.StatusUnprocessableEntity, userErr.Error())
+ }
+ }()
+
+ if cfg.complexityLimit > 0 {
+ queryComplexity := complexity.Calculate(exec, op, vars)
+ if queryComplexity > cfg.complexityLimit {
+ sendErrorf(w, http.StatusUnprocessableEntity, "query has complexity %d, which exceeds the limit of %d", queryComplexity, cfg.complexityLimit)
+ return
+ }
+ }
+
+ switch op.Operation {
+ case ast.Query:
+ b, err := json.Marshal(exec.Query(ctx, op))
+ if err != nil {
+ panic(err)
+ }
+ w.Write(b)
+ case ast.Mutation:
+ b, err := json.Marshal(exec.Mutation(ctx, op))
+ if err != nil {
+ panic(err)
+ }
+ w.Write(b)
+ default:
+ sendErrorf(w, http.StatusBadRequest, "unsupported operation type")
+ }
+ })
+}
+
+func jsonDecode(r io.Reader, val interface{}) error {
+ dec := json.NewDecoder(r)
+ dec.UseNumber()
+ return dec.Decode(val)
+}
+
+func sendError(w http.ResponseWriter, code int, errors ...*gqlerror.Error) {
+ w.WriteHeader(code)
+ b, err := json.Marshal(&graphql.Response{Errors: errors})
+ if err != nil {
+ panic(err)
+ }
+ w.Write(b)
+}
+
+func sendErrorf(w http.ResponseWriter, code int, format string, args ...interface{}) {
+ sendError(w, code, &gqlerror.Error{Message: fmt.Sprintf(format, args...)})
+}
diff --git a/vendor/github.com/99designs/gqlgen/handler/playground.go b/vendor/github.com/99designs/gqlgen/handler/playground.go
new file mode 100644
index 00000000..d0ada8ca
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/handler/playground.go
@@ -0,0 +1,54 @@
+package handler
+
+import (
+ "html/template"
+ "net/http"
+)
+
+var page = template.Must(template.New("graphiql").Parse(`<!DOCTYPE html>
+<html>
+<head>
+ <meta charset=utf-8/>
+ <meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
+ <link rel="shortcut icon" href="https://graphcool-playground.netlify.com/favicon.png">
+ <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/static/css/index.css"/>
+ <link rel="shortcut icon" href="//cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/favicon.png"/>
+ <script src="//cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/static/js/middleware.js"></script>
+ <title>{{.title}}</title>
+</head>
+<body>
+<style type="text/css">
+ html { font-family: "Open Sans", sans-serif; overflow: hidden; }
+ body { margin: 0; background: #172a3a; }
+</style>
+<div id="root"/>
+<script type="text/javascript">
+ window.addEventListener('load', function (event) {
+ const root = document.getElementById('root');
+ root.classList.add('playgroundIn');
+ const wsProto = location.protocol == 'https:' ? 'wss:' : 'ws:'
+ GraphQLPlayground.init(root, {
+ endpoint: location.protocol + '//' + location.host + '{{.endpoint}}',
+ subscriptionsEndpoint: wsProto + '//' + location.host + '{{.endpoint }}',
+ settings: {
+ 'request.credentials': 'same-origin'
+ }
+ })
+ })
+</script>
+</body>
+</html>
+`))
+
+func Playground(title string, endpoint string) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ err := page.Execute(w, map[string]string{
+ "title": title,
+ "endpoint": endpoint,
+ "version": "1.6.2",
+ })
+ if err != nil {
+ panic(err)
+ }
+ }
+}
diff --git a/vendor/github.com/99designs/gqlgen/handler/stub.go b/vendor/github.com/99designs/gqlgen/handler/stub.go
new file mode 100644
index 00000000..d237e188
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/handler/stub.go
@@ -0,0 +1,51 @@
+package handler
+
+import (
+ "context"
+
+ "github.com/99designs/gqlgen/graphql"
+ "github.com/vektah/gqlparser"
+ "github.com/vektah/gqlparser/ast"
+)
+
+type executableSchemaStub struct {
+ NextResp chan struct{}
+}
+
+var _ graphql.ExecutableSchema = &executableSchemaStub{}
+
+func (e *executableSchemaStub) Schema() *ast.Schema {
+ return gqlparser.MustLoadSchema(&ast.Source{Input: `
+ schema { query: Query }
+ type Query {
+ me: User!
+ user(id: Int): User!
+ }
+ type User { name: String! }
+ `})
+}
+
+func (e *executableSchemaStub) Complexity(typeName, field string, childComplexity int, args map[string]interface{}) (int, bool) {
+ return 0, false
+}
+
+func (e *executableSchemaStub) Query(ctx context.Context, op *ast.OperationDefinition) *graphql.Response {
+ return &graphql.Response{Data: []byte(`{"name":"test"}`)}
+}
+
+func (e *executableSchemaStub) Mutation(ctx context.Context, op *ast.OperationDefinition) *graphql.Response {
+ return graphql.ErrorResponse(ctx, "mutations are not supported")
+}
+
+func (e *executableSchemaStub) Subscription(ctx context.Context, op *ast.OperationDefinition) func() *graphql.Response {
+ return func() *graphql.Response {
+ select {
+ case <-ctx.Done():
+ return nil
+ case <-e.NextResp:
+ return &graphql.Response{
+ Data: []byte(`{"name":"test"}`),
+ }
+ }
+ }
+}
diff --git a/vendor/github.com/99designs/gqlgen/handler/websocket.go b/vendor/github.com/99designs/gqlgen/handler/websocket.go
new file mode 100644
index 00000000..2be1e87f
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/handler/websocket.go
@@ -0,0 +1,252 @@
+package handler
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "log"
+ "net/http"
+ "sync"
+
+ "github.com/99designs/gqlgen/graphql"
+ "github.com/gorilla/websocket"
+ "github.com/vektah/gqlparser"
+ "github.com/vektah/gqlparser/ast"
+ "github.com/vektah/gqlparser/gqlerror"
+ "github.com/vektah/gqlparser/validator"
+)
+
+const (
+ connectionInitMsg = "connection_init" // Client -> Server
+ connectionTerminateMsg = "connection_terminate" // Client -> Server
+ startMsg = "start" // Client -> Server
+ stopMsg = "stop" // Client -> Server
+ connectionAckMsg = "connection_ack" // Server -> Client
+ connectionErrorMsg = "connection_error" // Server -> Client
+ dataMsg = "data" // Server -> Client
+ errorMsg = "error" // Server -> Client
+ completeMsg = "complete" // Server -> Client
+ //connectionKeepAliveMsg = "ka" // Server -> Client TODO: keepalives
+)
+
+type operationMessage struct {
+ Payload json.RawMessage `json:"payload,omitempty"`
+ ID string `json:"id,omitempty"`
+ Type string `json:"type"`
+}
+
+type wsConnection struct {
+ ctx context.Context
+ conn *websocket.Conn
+ exec graphql.ExecutableSchema
+ active map[string]context.CancelFunc
+ mu sync.Mutex
+ cfg *Config
+}
+
+func connectWs(exec graphql.ExecutableSchema, w http.ResponseWriter, r *http.Request, cfg *Config) {
+ ws, err := cfg.upgrader.Upgrade(w, r, http.Header{
+ "Sec-Websocket-Protocol": []string{"graphql-ws"},
+ })
+ if err != nil {
+ log.Printf("unable to upgrade %T to websocket %s: ", w, err.Error())
+ sendErrorf(w, http.StatusBadRequest, "unable to upgrade")
+ return
+ }
+
+ conn := wsConnection{
+ active: map[string]context.CancelFunc{},
+ exec: exec,
+ conn: ws,
+ ctx: r.Context(),
+ cfg: cfg,
+ }
+
+ if !conn.init() {
+ return
+ }
+
+ conn.run()
+}
+
+func (c *wsConnection) init() bool {
+ message := c.readOp()
+ if message == nil {
+ c.close(websocket.CloseProtocolError, "decoding error")
+ return false
+ }
+
+ switch message.Type {
+ case connectionInitMsg:
+ c.write(&operationMessage{Type: connectionAckMsg})
+ case connectionTerminateMsg:
+ c.close(websocket.CloseNormalClosure, "terminated")
+ return false
+ default:
+ c.sendConnectionError("unexpected message %s", message.Type)
+ c.close(websocket.CloseProtocolError, "unexpected message")
+ return false
+ }
+
+ return true
+}
+
+func (c *wsConnection) write(msg *operationMessage) {
+ c.mu.Lock()
+ c.conn.WriteJSON(msg)
+ c.mu.Unlock()
+}
+
+func (c *wsConnection) run() {
+ for {
+ message := c.readOp()
+ if message == nil {
+ return
+ }
+
+ switch message.Type {
+ case startMsg:
+ if !c.subscribe(message) {
+ return
+ }
+ case stopMsg:
+ c.mu.Lock()
+ closer := c.active[message.ID]
+ c.mu.Unlock()
+ if closer == nil {
+ c.sendError(message.ID, gqlerror.Errorf("%s is not running, cannot stop", message.ID))
+ continue
+ }
+
+ closer()
+ case connectionTerminateMsg:
+ c.close(websocket.CloseNormalClosure, "terminated")
+ return
+ default:
+ c.sendConnectionError("unexpected message %s", message.Type)
+ c.close(websocket.CloseProtocolError, "unexpected message")
+ return
+ }
+ }
+}
+
+func (c *wsConnection) subscribe(message *operationMessage) bool {
+ var reqParams params
+ if err := jsonDecode(bytes.NewReader(message.Payload), &reqParams); err != nil {
+ c.sendConnectionError("invalid json")
+ return false
+ }
+
+ doc, qErr := gqlparser.LoadQuery(c.exec.Schema(), reqParams.Query)
+ if qErr != nil {
+ c.sendError(message.ID, qErr...)
+ return true
+ }
+
+ op := doc.Operations.ForName(reqParams.OperationName)
+ if op == nil {
+ c.sendError(message.ID, gqlerror.Errorf("operation %s not found", reqParams.OperationName))
+ return true
+ }
+
+ vars, err := validator.VariableValues(c.exec.Schema(), op, reqParams.Variables)
+ if err != nil {
+ c.sendError(message.ID, err)
+ return true
+ }
+ reqCtx := c.cfg.newRequestContext(doc, reqParams.Query, vars)
+ ctx := graphql.WithRequestContext(c.ctx, reqCtx)
+
+ if op.Operation != ast.Subscription {
+ var result *graphql.Response
+ if op.Operation == ast.Query {
+ result = c.exec.Query(ctx, op)
+ } else {
+ result = c.exec.Mutation(ctx, op)
+ }
+
+ c.sendData(message.ID, result)
+ c.write(&operationMessage{ID: message.ID, Type: completeMsg})
+ return true
+ }
+
+ ctx, cancel := context.WithCancel(ctx)
+ c.mu.Lock()
+ c.active[message.ID] = cancel
+ c.mu.Unlock()
+ go func() {
+ defer func() {
+ if r := recover(); r != nil {
+ userErr := reqCtx.Recover(ctx, r)
+ c.sendError(message.ID, &gqlerror.Error{Message: userErr.Error()})
+ }
+ }()
+ next := c.exec.Subscription(ctx, op)
+ for result := next(); result != nil; result = next() {
+ c.sendData(message.ID, result)
+ }
+
+ c.write(&operationMessage{ID: message.ID, Type: completeMsg})
+
+ c.mu.Lock()
+ delete(c.active, message.ID)
+ c.mu.Unlock()
+ cancel()
+ }()
+
+ return true
+}
+
+func (c *wsConnection) sendData(id string, response *graphql.Response) {
+ b, err := json.Marshal(response)
+ if err != nil {
+ c.sendError(id, gqlerror.Errorf("unable to encode json response: %s", err.Error()))
+ return
+ }
+
+ c.write(&operationMessage{Type: dataMsg, ID: id, Payload: b})
+}
+
+func (c *wsConnection) sendError(id string, errors ...*gqlerror.Error) {
+ var errs []error
+ for _, err := range errors {
+ errs = append(errs, err)
+ }
+ b, err := json.Marshal(errs)
+ if err != nil {
+ panic(err)
+ }
+ c.write(&operationMessage{Type: errorMsg, ID: id, Payload: b})
+}
+
+func (c *wsConnection) sendConnectionError(format string, args ...interface{}) {
+ b, err := json.Marshal(&gqlerror.Error{Message: fmt.Sprintf(format, args...)})
+ if err != nil {
+ panic(err)
+ }
+
+ c.write(&operationMessage{Type: connectionErrorMsg, Payload: b})
+}
+
+func (c *wsConnection) readOp() *operationMessage {
+ _, r, err := c.conn.NextReader()
+ if err != nil {
+ c.sendConnectionError("invalid json")
+ return nil
+ }
+ message := operationMessage{}
+ if err := jsonDecode(r, &message); err != nil {
+ c.sendConnectionError("invalid json")
+ return nil
+ }
+
+ return &message
+}
+
+func (c *wsConnection) close(closeCode int, message string) {
+ c.mu.Lock()
+ _ = c.conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(closeCode, message))
+ c.mu.Unlock()
+ _ = c.conn.Close()
+}
diff --git a/vendor/github.com/99designs/gqlgen/internal/gopath/gopath.go b/vendor/github.com/99designs/gqlgen/internal/gopath/gopath.go
new file mode 100644
index 00000000..c9b66167
--- /dev/null
+++ b/vendor/github.com/99designs/gqlgen/internal/gopath/gopath.go
@@ -0,0 +1,37 @@
+package gopath
+
+import (
+ "fmt"
+ "go/build"
+ "path/filepath"
+ "strings"
+)
+
+var NotFound = fmt.Errorf("not on GOPATH")
+
+// Contains returns true if the given directory is in the GOPATH
+func Contains(dir string) bool {
+ _, err := Dir2Import(dir)
+ return err == nil
+}
+
+// Dir2Import 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 Dir2Import(dir string) (string, error) {
+ dir = filepath.ToSlash(dir)
+ for _, gopath := range filepath.SplitList(build.Default.GOPATH) {
+ gopath = filepath.ToSlash(filepath.Join(gopath, "src"))
+ if len(gopath) < len(dir) && strings.EqualFold(gopath, dir[0:len(gopath)]) {
+ return dir[len(gopath)+1:], nil
+ }
+ }
+ return "", NotFound
+}
+
+// MustDir2Import takes an *absolute* path and returns a golang import path for the package, and panics if it isn't on the gopath
+func MustDir2Import(dir string) string {
+ pkg, err := Dir2Import(dir)
+ if err != nil {
+ panic(err)
+ }
+ return pkg
+}