mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 20:34:37 +03:00
Support Go 1.18: Upgrade gqlgen to v0.17.2 (#2443)
* Upgrade gqlgen to v0.17.2 This enables builds on Go 1.18. github.com/vektah/gqlparser is upgraded to the newest version too. Getting this to work is a bit of a hazzle. I had to first remove vendoring from the repository, perform the upgrade and then re-introduce the vendor directory. I think gqlgens analysis went wrong for some reason on the upgrade. It would seem a clean-room installation fixed it. * Bump project to 1.18 * Update all packages, address gqlgenc breaking changes * Let `go mod tidy` handle the go.mod file * Upgrade linter to 1.45.2 * Introduce v1.45.2 of the linter The linter now correctly warns on `strings.Title` because it isn't unicode-aware. Fix this by using the suggested fix from x/text/cases to produce unicode-aware strings. The mapping isn't entirely 1-1 as this new approach has a larger iface: it spans all of unicode rather than just ASCII. It coincides for ASCII however, so things should be largely the same. * Ready ourselves for errchkjson and contextcheck. * Revert dockerfile golang version changes for now Co-authored-by: Kermie <kermie@isinthe.house> Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
This commit is contained in:
2
vendor/github.com/99designs/gqlgen/.gitattributes
generated
vendored
2
vendor/github.com/99designs/gqlgen/.gitattributes
generated
vendored
@@ -1,3 +1,3 @@
|
||||
/codegen/templates/data.go linguist-generated
|
||||
/example/dataloader/*_gen.go linguist-generated
|
||||
/_examples/dataloader/*_gen.go linguist-generated
|
||||
generated.go linguist-generated
|
||||
|
||||
10
vendor/github.com/99designs/gqlgen/.gitignore
generated
vendored
10
vendor/github.com/99designs/gqlgen/.gitignore
generated
vendored
@@ -1,14 +1,16 @@
|
||||
/vendor
|
||||
/docs/public
|
||||
/example/chat/node_modules
|
||||
/docs/.hugo_build.lock
|
||||
/_examples/chat/node_modules
|
||||
/integration/node_modules
|
||||
/integration/schema-fetched.graphql
|
||||
/example/chat/package-lock.json
|
||||
/example/federation/package-lock.json
|
||||
/example/federation/node_modules
|
||||
/_examples/chat/package-lock.json
|
||||
/_examples/federation/package-lock.json
|
||||
/_examples/federation/node_modules
|
||||
/codegen/gen
|
||||
/gen
|
||||
|
||||
/.vscode
|
||||
.idea/
|
||||
*.test
|
||||
*.out
|
||||
|
||||
2
vendor/github.com/99designs/gqlgen/.golangci.yml
generated
vendored
2
vendor/github.com/99designs/gqlgen/.golangci.yml
generated
vendored
@@ -21,12 +21,12 @@ linters:
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- interfacer
|
||||
- misspell
|
||||
- nakedret
|
||||
- prealloc
|
||||
- staticcheck
|
||||
- structcheck
|
||||
- typecheck
|
||||
- unconvert
|
||||
- unused
|
||||
- varcheck
|
||||
|
||||
8634
vendor/github.com/99designs/gqlgen/CHANGELOG.md
generated
vendored
Normal file
8634
vendor/github.com/99designs/gqlgen/CHANGELOG.md
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
vendor/github.com/99designs/gqlgen/CONTRIBUTING.md
generated
vendored
2
vendor/github.com/99designs/gqlgen/CONTRIBUTING.md
generated
vendored
@@ -4,7 +4,7 @@ Want to contribute to gqlgen? Here are some guidelines for how we accept help.
|
||||
|
||||
## Getting in Touch
|
||||
|
||||
Our [gitter](https://gitter.im/gqlgen/Lobby) channel is the best place to ask questions or get advice on using gqlgen.
|
||||
Our [discord](https://discord.gg/DYEq3EMs4U) server is the best place to ask questions or get advice on using gqlgen.
|
||||
|
||||
## Reporting Bugs and Issues
|
||||
|
||||
|
||||
61
vendor/github.com/99designs/gqlgen/README.md
generated
vendored
61
vendor/github.com/99designs/gqlgen/README.md
generated
vendored
@@ -1,24 +1,42 @@
|
||||
# gqlgen [](https://github.com/99designs/gqlgen/actions) [](http://gqlgen.com/) [](https://godoc.org/github.com/99designs/gqlgen)
|
||||

|
||||
|
||||

|
||||
|
||||
# gqlgen [](https://github.com/99designs/gqlgen/actions) [](https://coveralls.io/github/99designs/gqlgen?branch=master) [](https://goreportcard.com/report/github.com/99designs/gqlgen) [](https://pkg.go.dev/github.com/99designs/gqlgen) [](http://gqlgen.com/)
|
||||
|
||||
## What is gqlgen?
|
||||
|
||||
[gqlgen](https://github.com/99designs/gqlgen) is a Go library for building GraphQL servers without any fuss.<br/>
|
||||
[gqlgen](https://github.com/99designs/gqlgen) is a Go library for building GraphQL servers without any fuss.<br/>
|
||||
|
||||
- **gqlgen is based on a Schema first approach** — You get to Define your API using the GraphQL [Schema Definition Language](http://graphql.org/learn/schema/).
|
||||
- **gqlgen priortizes Type safety** — You should never see `map[string]interface{}` here.
|
||||
- **gqlgen prioritizes Type safety** — You should never see `map[string]interface{}` here.
|
||||
- **gqlgen enables Codegen** — We generate the boring bits, so you can focus on building your app quickly.
|
||||
|
||||
Still not convinced enough to use **gqlgen**? Compare **gqlgen** with other Go graphql [implementations](https://gqlgen.com/feature-comparison/)
|
||||
|
||||
## Getting Started
|
||||
- To install gqlgen run the comand `go get github.com/99designs/gqlgen` in your project directory.<br/>
|
||||
- You could initialize a new project using the recommended folder structure by running this command `go run github.com/99designs/gqlgen init`.
|
||||
## Quick start
|
||||
1. [Initialise a new go module](https://golang.org/doc/tutorial/create-module)
|
||||
|
||||
You could find a more comprehensive guide to help you get started [here](https://gqlgen.com/getting-started/).<br/>
|
||||
We also have a couple of real-world [examples](https://github.com/99designs/gqlgen/tree/master/example) that show how to GraphQL applicatons with **gqlgen** seamlessly,
|
||||
You can see these [examples](https://github.com/99designs/gqlgen/tree/master/example) here or visit [godoc](https://godoc.org/github.com/99designs/gqlgen).
|
||||
mkdir example
|
||||
cd example
|
||||
go mod init example
|
||||
|
||||
2. Add `github.com/99designs/gqlgen` to your [project's tools.go](https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module)
|
||||
|
||||
printf '// +build tools\npackage tools\nimport _ "github.com/99designs/gqlgen"' | gofmt > tools.go
|
||||
go mod tidy
|
||||
|
||||
3. Initialise gqlgen config and generate models
|
||||
|
||||
go run github.com/99designs/gqlgen init
|
||||
|
||||
4. Start the graphql server
|
||||
|
||||
go run server.go
|
||||
|
||||
More help to get started:
|
||||
- [Getting started tutorial](https://gqlgen.com/getting-started/) - a comprehensive guide to help you get started
|
||||
- [Real-world examples](https://github.com/99designs/gqlgen/tree/master/_examples) show how to create GraphQL applications
|
||||
- [Reference docs](https://pkg.go.dev/github.com/99designs/gqlgen) for the APIs
|
||||
|
||||
## Reporting Issues
|
||||
|
||||
@@ -85,6 +103,25 @@ func (r *userResolver) Friends(ctx context.Context, obj *User) ([]*User, error)
|
||||
}
|
||||
```
|
||||
|
||||
You can also use inline config with directives to achieve the same result
|
||||
|
||||
```graphql
|
||||
directive @goModel(model: String, models: [String!]) on OBJECT
|
||||
| INPUT_OBJECT
|
||||
| SCALAR
|
||||
| ENUM
|
||||
| INTERFACE
|
||||
| UNION
|
||||
|
||||
directive @goField(forceResolver: Boolean, name: String) on INPUT_FIELD_DEFINITION
|
||||
| FIELD_DEFINITION
|
||||
|
||||
type User @goModel(model: "github.com/you/pkg/model.User") {
|
||||
id: ID! @goField(name: "todoId")
|
||||
friends: [User!]! @goField(forceResolver: true)
|
||||
}
|
||||
```
|
||||
|
||||
### Can I change the type of the ID from type String to Type Int?
|
||||
|
||||
Yes! You can by remapping it in config as seen below:
|
||||
@@ -93,7 +130,7 @@ Yes! You can by remapping it in config as seen below:
|
||||
models:
|
||||
ID: # The GraphQL type ID is backed by
|
||||
model:
|
||||
- github.com/99designs/gqlgen/graphql.IntID # An go integer
|
||||
- github.com/99designs/gqlgen/graphql.IntID # a go integer
|
||||
- github.com/99designs/gqlgen/graphql.ID # or a go string
|
||||
```
|
||||
|
||||
@@ -103,7 +140,7 @@ first model in this list is used as the default type and it will always be used
|
||||
- Generating models based on schema
|
||||
- As arguments in resolvers
|
||||
|
||||
There isnt any way around this, gqlgen has no way to know what you want in a given context.
|
||||
There isn't any way around this, gqlgen has no way to know what you want in a given context.
|
||||
|
||||
## Other Resources
|
||||
|
||||
|
||||
14
vendor/github.com/99designs/gqlgen/RELEASE-CHECKLIST.md
generated
vendored
Normal file
14
vendor/github.com/99designs/gqlgen/RELEASE-CHECKLIST.md
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# When gqlgen gets released, the following things need to happen
|
||||
Assuming the next version is $NEW_VERSION=v0.16.0 or something like that.
|
||||
|
||||
1. Run the https://github.com/99designs/gqlgen/blob/master/bin/release:
|
||||
```
|
||||
./bin/release $NEW_VERSION
|
||||
```
|
||||
2. git-chglog -o CHANGELOG.md
|
||||
3. git commit and push the CHANGELOG.md
|
||||
4. Go to https://github.com/99designs/gqlgen/releases and draft new release, autogenerate the release notes, and Create a discussion for this release
|
||||
5. Comment on the release discussion with any really important notes (breaking changes)
|
||||
|
||||
I used https://github.com/git-chglog/git-chglog to automate the changelog maintenance process for now. We could just as easily use go releaser to make the whole thing automated.
|
||||
|
||||
6
vendor/github.com/99designs/gqlgen/TESTING.md
generated
vendored
6
vendor/github.com/99designs/gqlgen/TESTING.md
generated
vendored
@@ -5,7 +5,7 @@ Testing generated code is a little tricky, heres how its currently set up.
|
||||
|
||||
### Testing responses from a server
|
||||
|
||||
There is a server in `codegen/testserver` that is generated as part
|
||||
There is a server in `codegen/testserver` that is generated as part
|
||||
of `go generate ./...`, and tests written against it.
|
||||
|
||||
There are also a bunch of tests in against the examples, feel free to take examples from there.
|
||||
@@ -15,7 +15,7 @@ There are also a bunch of tests in against the examples, feel free to take examp
|
||||
|
||||
These tests are **really** slow, because they need to run the whole codegen step. Use them very sparingly. If you can, find a way to unit test it instead.
|
||||
|
||||
Take a look at `codegen/input_test.go` for an example.
|
||||
Take a look at `codegen/testserver/input_test.go` for an example.
|
||||
|
||||
### Testing introspection
|
||||
|
||||
@@ -31,7 +31,7 @@ in another terminal
|
||||
```bash
|
||||
cd integration
|
||||
npm install
|
||||
SERVER_URL=http://localhost:8080/query ./node_modules/.bin/graphql get-schema
|
||||
./node_modules/.bin/graphql-codegen
|
||||
```
|
||||
|
||||
will write the schema to `integration/schema-fetched.graphql`, compare that with `schema-expected.graphql`
|
||||
|
||||
26
vendor/github.com/99designs/gqlgen/api/generate.go
generated
vendored
26
vendor/github.com/99designs/gqlgen/api/generate.go
generated
vendored
@@ -1,6 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
|
||||
"github.com/99designs/gqlgen/codegen"
|
||||
@@ -9,7 +10,6 @@ import (
|
||||
"github.com/99designs/gqlgen/plugin/federation"
|
||||
"github.com/99designs/gqlgen/plugin/modelgen"
|
||||
"github.com/99designs/gqlgen/plugin/resolvergen"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func Generate(cfg *config.Config, option ...Option) error {
|
||||
@@ -40,7 +40,7 @@ func Generate(cfg *config.Config, option ...Option) error {
|
||||
}
|
||||
|
||||
if err := cfg.LoadSchema(); err != nil {
|
||||
return errors.Wrap(err, "failed to load schema")
|
||||
return fmt.Errorf("failed to load schema: %w", err)
|
||||
}
|
||||
|
||||
for _, p := range plugins {
|
||||
@@ -53,47 +53,53 @@ func Generate(cfg *config.Config, option ...Option) error {
|
||||
|
||||
// LoadSchema again now we have everything
|
||||
if err := cfg.LoadSchema(); err != nil {
|
||||
return errors.Wrap(err, "failed to load schema")
|
||||
return fmt.Errorf("failed to load schema: %w", err)
|
||||
}
|
||||
|
||||
if err := cfg.Init(); err != nil {
|
||||
return errors.Wrap(err, "generating core failed")
|
||||
return fmt.Errorf("generating core failed: %w", err)
|
||||
}
|
||||
|
||||
for _, p := range plugins {
|
||||
if mut, ok := p.(plugin.ConfigMutator); ok {
|
||||
err := mut.MutateConfig(cfg)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, p.Name())
|
||||
return fmt.Errorf("%s: %w", p.Name(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Merge again now that the generated models have been injected into the typemap
|
||||
data, err := codegen.BuildData(cfg)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "merging type systems failed")
|
||||
return fmt.Errorf("merging type systems failed: %w", err)
|
||||
}
|
||||
|
||||
if err = codegen.GenerateCode(data); err != nil {
|
||||
return errors.Wrap(err, "generating core failed")
|
||||
return fmt.Errorf("generating core failed: %w", err)
|
||||
}
|
||||
|
||||
if !cfg.SkipModTidy {
|
||||
if err = cfg.Packages.ModTidy(); err != nil {
|
||||
return fmt.Errorf("tidy failed: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, p := range plugins {
|
||||
if mut, ok := p.(plugin.CodeGenerator); ok {
|
||||
err := mut.GenerateCode(data)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, p.Name())
|
||||
return fmt.Errorf("%s: %w", p.Name(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err = codegen.GenerateCode(data); err != nil {
|
||||
return errors.Wrap(err, "generating core failed")
|
||||
return fmt.Errorf("generating core failed: %w", err)
|
||||
}
|
||||
|
||||
if !cfg.SkipValidation {
|
||||
if err := validate(cfg); err != nil {
|
||||
return errors.Wrap(err, "validation failed")
|
||||
return fmt.Errorf("validation failed: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
27
vendor/github.com/99designs/gqlgen/api/option.go
generated
vendored
27
vendor/github.com/99designs/gqlgen/api/option.go
generated
vendored
@@ -18,3 +18,30 @@ func AddPlugin(p plugin.Plugin) Option {
|
||||
*plugins = append(*plugins, p)
|
||||
}
|
||||
}
|
||||
|
||||
// PrependPlugin prepends plugin any existing plugins
|
||||
func PrependPlugin(p plugin.Plugin) Option {
|
||||
return func(cfg *config.Config, plugins *[]plugin.Plugin) {
|
||||
*plugins = append([]plugin.Plugin{p}, *plugins...)
|
||||
}
|
||||
}
|
||||
|
||||
// ReplacePlugin replaces any existing plugin with a matching plugin name
|
||||
func ReplacePlugin(p plugin.Plugin) Option {
|
||||
return func(cfg *config.Config, plugins *[]plugin.Plugin) {
|
||||
if plugins != nil {
|
||||
found := false
|
||||
ps := *plugins
|
||||
for i, o := range ps {
|
||||
if p.Name() == o.Name() {
|
||||
ps[i] = p
|
||||
found = true
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
ps = append(ps, p)
|
||||
}
|
||||
*plugins = ps
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
10
vendor/github.com/99designs/gqlgen/cmd/ambient.go
generated
vendored
10
vendor/github.com/99designs/gqlgen/cmd/ambient.go
generated
vendored
@@ -1,10 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
// 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/vektah/gqlparser/v2"
|
||||
_ "github.com/vektah/gqlparser/v2/ast"
|
||||
)
|
||||
43
vendor/github.com/99designs/gqlgen/cmd/gen.go
generated
vendored
43
vendor/github.com/99designs/gqlgen/cmd/gen.go
generated
vendored
@@ -1,43 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/99designs/gqlgen/api"
|
||||
"github.com/99designs/gqlgen/codegen/config"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var genCmd = &cli.Command{
|
||||
Name: "generate",
|
||||
Usage: "generate a graphql server based on schema",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{Name: "verbose, v", Usage: "show logs"},
|
||||
&cli.StringFlag{Name: "config, c", Usage: "the config filename"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) error {
|
||||
var cfg *config.Config
|
||||
var err error
|
||||
if configFilename := ctx.String("config"); configFilename != "" {
|
||||
cfg, err = config.LoadConfig(configFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
cfg, err = config.LoadConfigFromDefaultLocations()
|
||||
if os.IsNotExist(errors.Cause(err)) {
|
||||
cfg, err = config.LoadDefaultConfig()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err = api.Generate(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
199
vendor/github.com/99designs/gqlgen/cmd/init.go
generated
vendored
199
vendor/github.com/99designs/gqlgen/cmd/init.go
generated
vendored
@@ -1,199 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/99designs/gqlgen/api"
|
||||
"github.com/99designs/gqlgen/codegen/config"
|
||||
"github.com/99designs/gqlgen/internal/code"
|
||||
"github.com/99designs/gqlgen/plugin/servergen"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var configTemplate = template.Must(template.New("name").Parse(
|
||||
`# Where are all the schema files located? globs are supported eg src/**/*.graphqls
|
||||
schema:
|
||||
- graph/*.graphqls
|
||||
|
||||
# Where should the generated server code go?
|
||||
exec:
|
||||
filename: graph/generated/generated.go
|
||||
package: generated
|
||||
|
||||
# Uncomment to enable federation
|
||||
# federation:
|
||||
# filename: graph/generated/federation.go
|
||||
# package: generated
|
||||
|
||||
# Where should any generated models go?
|
||||
model:
|
||||
filename: graph/model/models_gen.go
|
||||
package: model
|
||||
|
||||
# Where should the resolver implementations go?
|
||||
resolver:
|
||||
layout: follow-schema
|
||||
dir: graph
|
||||
package: graph
|
||||
|
||||
# Optional: turn on use ` + "`" + `gqlgen:"fieldName"` + "`" + ` tags in your models
|
||||
# struct_tag: json
|
||||
|
||||
# Optional: turn on to use []Thing instead of []*Thing
|
||||
# omit_slice_element_pointers: false
|
||||
|
||||
# Optional: set to speed up generation time by not performing a final validation pass.
|
||||
# skip_validation: true
|
||||
|
||||
# gqlgen will search for any type names in the schema in these go packages
|
||||
# if they match it will use them, otherwise it will generate them.
|
||||
autobind:
|
||||
- "{{.}}/graph/model"
|
||||
|
||||
# This section declares type mapping between the GraphQL and go type systems
|
||||
#
|
||||
# The first line in each type will be used as defaults for resolver arguments and
|
||||
# modelgen, the others will be allowed when binding to fields. Configure them to
|
||||
# your liking
|
||||
models:
|
||||
ID:
|
||||
model:
|
||||
- github.com/99designs/gqlgen/graphql.ID
|
||||
- github.com/99designs/gqlgen/graphql.Int
|
||||
- github.com/99designs/gqlgen/graphql.Int64
|
||||
- github.com/99designs/gqlgen/graphql.Int32
|
||||
Int:
|
||||
model:
|
||||
- github.com/99designs/gqlgen/graphql.Int
|
||||
- github.com/99designs/gqlgen/graphql.Int64
|
||||
- github.com/99designs/gqlgen/graphql.Int32
|
||||
`))
|
||||
|
||||
var schemaDefault = `# GraphQL schema example
|
||||
#
|
||||
# https://gqlgen.com/getting-started/
|
||||
|
||||
type Todo {
|
||||
id: ID!
|
||||
text: String!
|
||||
done: Boolean!
|
||||
user: User!
|
||||
}
|
||||
|
||||
type User {
|
||||
id: ID!
|
||||
name: String!
|
||||
}
|
||||
|
||||
type Query {
|
||||
todos: [Todo!]!
|
||||
}
|
||||
|
||||
input NewTodo {
|
||||
text: String!
|
||||
userId: String!
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
createTodo(input: NewTodo!): Todo!
|
||||
}
|
||||
`
|
||||
|
||||
var initCmd = &cli.Command{
|
||||
Name: "init",
|
||||
Usage: "create a new gqlgen project",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{Name: "verbose, v", Usage: "show logs"},
|
||||
&cli.StringFlag{Name: "config, c", Usage: "the config filename"},
|
||||
&cli.StringFlag{Name: "server", Usage: "where to write the server stub to", Value: "server.go"},
|
||||
&cli.StringFlag{Name: "schema", Usage: "where to write the schema stub to", Value: "graph/schema.graphqls"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) error {
|
||||
configFilename := ctx.String("config")
|
||||
serverFilename := ctx.String("server")
|
||||
|
||||
pkgName := code.ImportPathForDir(".")
|
||||
if pkgName == "" {
|
||||
return fmt.Errorf("unable to determine import path for current directory, you probably need to run go mod init first")
|
||||
}
|
||||
|
||||
if err := initSchema(ctx.String("schema")); err != nil {
|
||||
return err
|
||||
}
|
||||
if !configExists(configFilename) {
|
||||
if err := initConfig(configFilename, pkgName); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
GenerateGraphServer(serverFilename)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func GenerateGraphServer(serverFilename string) {
|
||||
cfg, err := config.LoadConfigFromDefaultLocations()
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err.Error())
|
||||
}
|
||||
|
||||
if err := api.Generate(cfg, api.AddPlugin(servergen.New(serverFilename))); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err.Error())
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stdout, "Exec \"go run ./%s\" to start GraphQL server\n", serverFilename)
|
||||
}
|
||||
|
||||
func configExists(configFilename string) bool {
|
||||
var cfg *config.Config
|
||||
|
||||
if configFilename != "" {
|
||||
cfg, _ = config.LoadConfig(configFilename)
|
||||
} else {
|
||||
cfg, _ = config.LoadConfigFromDefaultLocations()
|
||||
}
|
||||
return cfg != nil
|
||||
}
|
||||
|
||||
func initConfig(configFilename string, pkgName string) error {
|
||||
if configFilename == "" {
|
||||
configFilename = "gqlgen.yml"
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(configFilename), 0755); err != nil {
|
||||
return fmt.Errorf("unable to create config dir: " + err.Error())
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := configTemplate.Execute(&buf, pkgName); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(configFilename, buf.Bytes(), 0644); err != nil {
|
||||
return fmt.Errorf("unable to write cfg file: " + err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func initSchema(schemaFilename string) error {
|
||||
_, err := os.Stat(schemaFilename)
|
||||
if !os.IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(schemaFilename), 0755); err != nil {
|
||||
return fmt.Errorf("unable to create schema dir: " + err.Error())
|
||||
}
|
||||
|
||||
if err = ioutil.WriteFile(schemaFilename, []byte(strings.TrimSpace(schemaDefault)), 0644); err != nil {
|
||||
return fmt.Errorf("unable to write schema file: " + err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
45
vendor/github.com/99designs/gqlgen/cmd/root.go
generated
vendored
45
vendor/github.com/99designs/gqlgen/cmd/root.go
generated
vendored
@@ -1,45 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
// Required since otherwise dep will prune away these unused packages before codegen has a chance to run
|
||||
_ "github.com/99designs/gqlgen/graphql/handler"
|
||||
_ "github.com/99designs/gqlgen/handler"
|
||||
)
|
||||
|
||||
func Execute() {
|
||||
app := cli.NewApp()
|
||||
app.Name = "gqlgen"
|
||||
app.Usage = genCmd.Usage
|
||||
app.Description = "This is a library for quickly creating strictly typed graphql servers in golang. See https://gqlgen.com/ for a getting started guide."
|
||||
app.HideVersion = true
|
||||
app.Flags = genCmd.Flags
|
||||
app.Version = graphql.Version
|
||||
app.Before = func(context *cli.Context) error {
|
||||
if context.Bool("verbose") {
|
||||
log.SetFlags(0)
|
||||
} else {
|
||||
log.SetOutput(ioutil.Discard)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
app.Action = genCmd.Action
|
||||
app.Commands = []*cli.Command{
|
||||
genCmd,
|
||||
initCmd,
|
||||
versionCmd,
|
||||
}
|
||||
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
fmt.Fprint(os.Stderr, err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
17
vendor/github.com/99designs/gqlgen/cmd/version.go
generated
vendored
17
vendor/github.com/99designs/gqlgen/cmd/version.go
generated
vendored
@@ -1,17 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var versionCmd = &cli.Command{
|
||||
Name: "version",
|
||||
Usage: "print the version string",
|
||||
Action: func(ctx *cli.Context) error {
|
||||
fmt.Println(graphql.Version)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
16
vendor/github.com/99designs/gqlgen/codegen/args.go
generated
vendored
16
vendor/github.com/99designs/gqlgen/codegen/args.go
generated
vendored
@@ -7,7 +7,6 @@ import (
|
||||
|
||||
"github.com/99designs/gqlgen/codegen/config"
|
||||
"github.com/99designs/gqlgen/codegen/templates"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
)
|
||||
|
||||
@@ -26,7 +25,7 @@ type FieldArgument struct {
|
||||
Value interface{} // value set in Data
|
||||
}
|
||||
|
||||
//ImplDirectives get not Builtin and location ARGUMENT_DEFINITION directive
|
||||
// ImplDirectives get not Builtin and location ARGUMENT_DEFINITION directive
|
||||
func (f *FieldArgument) ImplDirectives() []*Directive {
|
||||
d := make([]*Directive, 0)
|
||||
for i := range f.Directives {
|
||||
@@ -67,14 +66,14 @@ func (b *builder) buildArg(obj *Object, arg *ast.ArgumentDefinition) (*FieldArgu
|
||||
if arg.DefaultValue != nil {
|
||||
newArg.Default, err = arg.DefaultValue.Value(nil)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("default value is not valid: %s", err.Error())
|
||||
return nil, fmt.Errorf("default value is not valid: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return &newArg, nil
|
||||
}
|
||||
|
||||
func (b *builder) bindArgs(field *Field, params *types.Tuple) error {
|
||||
func (b *builder) bindArgs(field *Field, params *types.Tuple) ([]*FieldArgument, error) {
|
||||
var newArgs []*FieldArgument
|
||||
|
||||
nextArg:
|
||||
@@ -84,7 +83,7 @@ nextArg:
|
||||
if strings.EqualFold(oldArg.Name, param.Name()) {
|
||||
tr, err := b.Binder.TypeReference(oldArg.Type, param.Type())
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
oldArg.TypeReference = tr
|
||||
|
||||
@@ -94,11 +93,10 @@ nextArg:
|
||||
}
|
||||
|
||||
// no matching arg found, abort
|
||||
return fmt.Errorf("arg %s not in schema", param.Name())
|
||||
return nil, fmt.Errorf("arg %s not in schema", param.Name())
|
||||
}
|
||||
|
||||
field.Args = newArgs
|
||||
return nil
|
||||
return newArgs, nil
|
||||
}
|
||||
|
||||
func (a *Data) Args() map[string][]*FieldArgument {
|
||||
@@ -111,7 +109,7 @@ func (a *Data) Args() map[string][]*FieldArgument {
|
||||
}
|
||||
}
|
||||
|
||||
for _, d := range a.Directives {
|
||||
for _, d := range a.Directives() {
|
||||
if len(d.Args) > 0 {
|
||||
ret[d.ArgsFunc()] = d.Args
|
||||
}
|
||||
|
||||
6
vendor/github.com/99designs/gqlgen/codegen/args.gotpl
generated
vendored
6
vendor/github.com/99designs/gqlgen/codegen/args.gotpl
generated
vendored
@@ -5,13 +5,13 @@ func (ec *executionContext) {{ $name }}(ctx context.Context, rawArgs map[string]
|
||||
{{- range $i, $arg := . }}
|
||||
var arg{{$i}} {{ $arg.TypeReference.GO | ref}}
|
||||
if tmp, ok := rawArgs[{{$arg.Name|quote}}]; ok {
|
||||
ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField({{$arg.Name|quote}}))
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField({{$arg.Name|quote}}))
|
||||
{{- if $arg.ImplDirectives }}
|
||||
directive0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, tmp) }
|
||||
{{ template "implDirectives" $arg }}
|
||||
tmp, err = directive{{$arg.ImplDirectives|len}}(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
if data, ok := tmp.({{ $arg.TypeReference.GO | ref }}) ; ok {
|
||||
arg{{$i}} = data
|
||||
@@ -20,7 +20,7 @@ func (ec *executionContext) {{ $name }}(ctx context.Context, rawArgs map[string]
|
||||
arg{{$i}} = nil
|
||||
{{- end }}
|
||||
} else {
|
||||
return nil, fmt.Errorf(`unexpected type %T from directive, should be {{ $arg.TypeReference.GO }}`, tmp)
|
||||
return nil, graphql.ErrorOnPath(ctx, fmt.Errorf(`unexpected type %T from directive, should be {{ $arg.TypeReference.GO }}`, tmp))
|
||||
}
|
||||
{{- else }}
|
||||
arg{{$i}}, err = ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, tmp)
|
||||
|
||||
156
vendor/github.com/99designs/gqlgen/codegen/config/binder.go
generated
vendored
156
vendor/github.com/99designs/gqlgen/codegen/config/binder.go
generated
vendored
@@ -1,23 +1,28 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/token"
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/go/packages"
|
||||
|
||||
"github.com/99designs/gqlgen/codegen/templates"
|
||||
"github.com/99designs/gqlgen/internal/code"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
)
|
||||
|
||||
var ErrTypeNotFound = errors.New("unable to find type")
|
||||
|
||||
// Binder connects graphql types to golang types using static analysis
|
||||
type Binder struct {
|
||||
pkgs *code.Packages
|
||||
schema *ast.Schema
|
||||
cfg *Config
|
||||
References []*TypeReference
|
||||
SawInvalid bool
|
||||
pkgs *code.Packages
|
||||
schema *ast.Schema
|
||||
cfg *Config
|
||||
References []*TypeReference
|
||||
SawInvalid bool
|
||||
objectCache map[string]map[string]types.Object
|
||||
}
|
||||
|
||||
func (c *Config) NewBinder() *Binder {
|
||||
@@ -76,8 +81,10 @@ func (b *Binder) FindType(pkgName string, typeName string) (types.Type, error) {
|
||||
return obj.Type(), nil
|
||||
}
|
||||
|
||||
var MapType = types.NewMap(types.Typ[types.String], types.NewInterfaceType(nil, nil).Complete())
|
||||
var InterfaceType = types.NewInterfaceType(nil, nil)
|
||||
var (
|
||||
MapType = types.NewMap(types.Typ[types.String], types.NewInterfaceType(nil, nil).Complete())
|
||||
InterfaceType = types.NewInterfaceType(nil, nil)
|
||||
)
|
||||
|
||||
func (b *Binder) DefaultUserObject(name string) (types.Type, error) {
|
||||
models := b.cfg.Models[name].Model
|
||||
@@ -110,56 +117,68 @@ func (b *Binder) FindObject(pkgName string, typeName string) (types.Object, erro
|
||||
if pkgName == "" {
|
||||
return nil, fmt.Errorf("package cannot be nil")
|
||||
}
|
||||
fullName := typeName
|
||||
if pkgName != "" {
|
||||
fullName = pkgName + "." + typeName
|
||||
}
|
||||
|
||||
pkg := b.pkgs.LoadWithTypes(pkgName)
|
||||
if pkg == nil {
|
||||
return nil, errors.Errorf("required package was not loaded: %s", fullName)
|
||||
err := b.pkgs.Errors()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("package could not be loaded: %s.%s: %w", pkgName, typeName, err)
|
||||
}
|
||||
return nil, fmt.Errorf("required package was not loaded: %s.%s", pkgName, typeName)
|
||||
}
|
||||
|
||||
if b.objectCache == nil {
|
||||
b.objectCache = make(map[string]map[string]types.Object, b.pkgs.Count())
|
||||
}
|
||||
|
||||
defsIndex, ok := b.objectCache[pkgName]
|
||||
if !ok {
|
||||
defsIndex = indexDefs(pkg)
|
||||
b.objectCache[pkgName] = defsIndex
|
||||
}
|
||||
|
||||
// function based marshalers take precedence
|
||||
if val, ok := defsIndex["Marshal"+typeName]; ok {
|
||||
return val, nil
|
||||
}
|
||||
|
||||
if val, ok := defsIndex[typeName]; ok {
|
||||
return val, nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("%w: %s.%s", ErrTypeNotFound, pkgName, typeName)
|
||||
}
|
||||
|
||||
func indexDefs(pkg *packages.Package) map[string]types.Object {
|
||||
res := make(map[string]types.Object)
|
||||
|
||||
scope := pkg.Types.Scope()
|
||||
for astNode, def := range pkg.TypesInfo.Defs {
|
||||
// only look at defs in the top scope
|
||||
if def == nil || def.Parent() == nil || def.Parent() != pkg.Types.Scope() {
|
||||
if def == nil {
|
||||
continue
|
||||
}
|
||||
parent := def.Parent()
|
||||
if parent == nil || parent != scope {
|
||||
continue
|
||||
}
|
||||
|
||||
if astNode.Name == "Marshal"+typeName {
|
||||
return def, nil
|
||||
if _, ok := res[astNode.Name]; !ok {
|
||||
// The above check may not be really needed, it is only here to have a consistent behavior with
|
||||
// previous implementation of FindObject() function which only honored the first inclusion of a def.
|
||||
// If this is still needed, we can consider something like sync.Map.LoadOrStore() to avoid two lookups.
|
||||
res[astNode.Name] = def
|
||||
}
|
||||
}
|
||||
|
||||
// then look for types directly
|
||||
for astNode, def := range pkg.TypesInfo.Defs {
|
||||
// only look at defs in the top scope
|
||||
if def == nil || def.Parent() == nil || def.Parent() != pkg.Types.Scope() {
|
||||
continue
|
||||
}
|
||||
|
||||
if astNode.Name == typeName {
|
||||
return def, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.Errorf("unable to find type %s\n", fullName)
|
||||
return res
|
||||
}
|
||||
|
||||
func (b *Binder) PointerTo(ref *TypeReference) *TypeReference {
|
||||
newRef := &TypeReference{
|
||||
GO: types.NewPointer(ref.GO),
|
||||
GQL: ref.GQL,
|
||||
CastType: ref.CastType,
|
||||
Definition: ref.Definition,
|
||||
Unmarshaler: ref.Unmarshaler,
|
||||
Marshaler: ref.Marshaler,
|
||||
IsMarshaler: ref.IsMarshaler,
|
||||
}
|
||||
|
||||
b.References = append(b.References, newRef)
|
||||
return newRef
|
||||
newRef := *ref
|
||||
newRef.GO = types.NewPointer(ref.GO)
|
||||
b.References = append(b.References, &newRef)
|
||||
return &newRef
|
||||
}
|
||||
|
||||
// TypeReference is used by args and field types. The Definition can refer to both input and output types.
|
||||
@@ -172,33 +191,21 @@ type TypeReference struct {
|
||||
Marshaler *types.Func // When using external marshalling functions this will point to the Marshal function
|
||||
Unmarshaler *types.Func // When using external marshalling functions this will point to the Unmarshal function
|
||||
IsMarshaler bool // Does the type implement graphql.Marshaler and graphql.Unmarshaler
|
||||
IsContext bool // Is the Marshaler/Unmarshaller the context version; applies to either the method or interface variety.
|
||||
}
|
||||
|
||||
func (ref *TypeReference) Elem() *TypeReference {
|
||||
if p, isPtr := ref.GO.(*types.Pointer); isPtr {
|
||||
return &TypeReference{
|
||||
GO: p.Elem(),
|
||||
Target: ref.Target,
|
||||
GQL: ref.GQL,
|
||||
CastType: ref.CastType,
|
||||
Definition: ref.Definition,
|
||||
Unmarshaler: ref.Unmarshaler,
|
||||
Marshaler: ref.Marshaler,
|
||||
IsMarshaler: ref.IsMarshaler,
|
||||
}
|
||||
newRef := *ref
|
||||
newRef.GO = p.Elem()
|
||||
return &newRef
|
||||
}
|
||||
|
||||
if ref.IsSlice() {
|
||||
return &TypeReference{
|
||||
GO: ref.GO.(*types.Slice).Elem(),
|
||||
Target: ref.Target,
|
||||
GQL: ref.GQL.Elem,
|
||||
CastType: ref.CastType,
|
||||
Definition: ref.Definition,
|
||||
Unmarshaler: ref.Unmarshaler,
|
||||
Marshaler: ref.Marshaler,
|
||||
IsMarshaler: ref.IsMarshaler,
|
||||
}
|
||||
newRef := *ref
|
||||
newRef.GO = ref.GO.(*types.Slice).Elem()
|
||||
newRef.GQL = ref.GQL.Elem
|
||||
return &newRef
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -208,6 +215,16 @@ func (t *TypeReference) IsPtr() bool {
|
||||
return isPtr
|
||||
}
|
||||
|
||||
// fix for https://github.com/golang/go/issues/31103 may make it possible to remove this (may still be useful)
|
||||
//
|
||||
func (t *TypeReference) IsPtrToPtr() bool {
|
||||
if p, isPtr := t.GO.(*types.Pointer); isPtr {
|
||||
_, isPtr := p.Elem().(*types.Pointer)
|
||||
return isPtr
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *TypeReference) IsNilable() bool {
|
||||
return IsNilable(t.GO)
|
||||
}
|
||||
@@ -217,6 +234,14 @@ func (t *TypeReference) IsSlice() bool {
|
||||
return t.GQL.Elem != nil && isSlice
|
||||
}
|
||||
|
||||
func (t *TypeReference) IsPtrToSlice() bool {
|
||||
if t.IsPtr() {
|
||||
_, isPointerToSlice := t.GO.(*types.Pointer).Elem().(*types.Slice)
|
||||
return isPointerToSlice
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *TypeReference) IsNamed() bool {
|
||||
_, isSlice := t.GO.(*types.Named)
|
||||
return isSlice
|
||||
@@ -232,12 +257,12 @@ func (t *TypeReference) IsScalar() bool {
|
||||
}
|
||||
|
||||
func (t *TypeReference) UniquenessKey() string {
|
||||
var nullability = "O"
|
||||
nullability := "O"
|
||||
if t.GQL.NonNull {
|
||||
nullability = "N"
|
||||
}
|
||||
|
||||
var elemNullability = ""
|
||||
elemNullability := ""
|
||||
if t.GQL.Elem != nil && t.GQL.Elem.NonNull {
|
||||
// Fix for #896
|
||||
elemNullability = "ᚄ"
|
||||
@@ -351,8 +376,13 @@ func (b *Binder) TypeReference(schemaType *ast.Type, bindTarget types.Type) (ret
|
||||
|
||||
if fun, isFunc := obj.(*types.Func); isFunc {
|
||||
ref.GO = fun.Type().(*types.Signature).Params().At(0).Type()
|
||||
ref.IsContext = fun.Type().(*types.Signature).Results().At(0).Type().String() == "github.com/99designs/gqlgen/graphql.ContextMarshaler"
|
||||
ref.Marshaler = fun
|
||||
ref.Unmarshaler = types.NewFunc(0, fun.Pkg(), "Unmarshal"+typeName, nil)
|
||||
} else if hasMethod(obj.Type(), "MarshalGQLContext") && hasMethod(obj.Type(), "UnmarshalGQLContext") {
|
||||
ref.GO = obj.Type()
|
||||
ref.IsContext = true
|
||||
ref.IsMarshaler = true
|
||||
} else if hasMethod(obj.Type(), "MarshalGQL") && hasMethod(obj.Type(), "UnmarshalGQL") {
|
||||
ref.GO = obj.Type()
|
||||
ref.IsMarshaler = true
|
||||
|
||||
86
vendor/github.com/99designs/gqlgen/codegen/config/config.go
generated
vendored
86
vendor/github.com/99designs/gqlgen/codegen/config/config.go
generated
vendored
@@ -10,7 +10,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/99designs/gqlgen/internal/code"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/vektah/gqlparser/v2"
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
"gopkg.in/yaml.v2"
|
||||
@@ -18,7 +17,7 @@ import (
|
||||
|
||||
type Config struct {
|
||||
SchemaFilename StringList `yaml:"schema,omitempty"`
|
||||
Exec PackageConfig `yaml:"exec"`
|
||||
Exec ExecConfig `yaml:"exec"`
|
||||
Model PackageConfig `yaml:"model,omitempty"`
|
||||
Federation PackageConfig `yaml:"federation,omitempty"`
|
||||
Resolver ResolverConfig `yaml:"resolver,omitempty"`
|
||||
@@ -28,11 +27,12 @@ type Config struct {
|
||||
Directives map[string]DirectiveConfig `yaml:"directives,omitempty"`
|
||||
OmitSliceElementPointers bool `yaml:"omit_slice_element_pointers,omitempty"`
|
||||
SkipValidation bool `yaml:"skip_validation,omitempty"`
|
||||
SkipModTidy bool `yaml:"skip_mod_tidy,omitempty"`
|
||||
Sources []*ast.Source `yaml:"-"`
|
||||
Packages *code.Packages `yaml:"-"`
|
||||
Schema *ast.Schema `yaml:"-"`
|
||||
|
||||
// Deprecated use Federation instead. Will be removed next release
|
||||
// Deprecated: use Federation instead. Will be removed next release
|
||||
Federated bool `yaml:"federated,omitempty"`
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ func DefaultConfig() *Config {
|
||||
return &Config{
|
||||
SchemaFilename: StringList{"schema.graphql"},
|
||||
Model: PackageConfig{Filename: "models_gen.go"},
|
||||
Exec: PackageConfig{Filename: "generated.go"},
|
||||
Exec: ExecConfig{Filename: "generated.go"},
|
||||
Directives: map[string]DirectiveConfig{},
|
||||
Models: TypeMap{},
|
||||
}
|
||||
@@ -59,7 +59,7 @@ func LoadDefaultConfig() (*Config, error) {
|
||||
var schemaRaw []byte
|
||||
schemaRaw, err = ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to open schema")
|
||||
return nil, fmt.Errorf("unable to open schema: %w", err)
|
||||
}
|
||||
|
||||
config.Sources = append(config.Sources, &ast.Source{Name: filename, Input: string(schemaRaw)})
|
||||
@@ -78,7 +78,7 @@ func LoadConfigFromDefaultLocations() (*Config, error) {
|
||||
|
||||
err = os.Chdir(filepath.Dir(cfgFile))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to enter config dir")
|
||||
return nil, fmt.Errorf("unable to enter config dir: %w", err)
|
||||
}
|
||||
return LoadConfig(cfgFile)
|
||||
}
|
||||
@@ -96,17 +96,28 @@ func LoadConfig(filename string) (*Config, error) {
|
||||
|
||||
b, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to read config")
|
||||
return nil, fmt.Errorf("unable to read config: %w", err)
|
||||
}
|
||||
|
||||
if err := yaml.UnmarshalStrict(b, config); err != nil {
|
||||
return nil, errors.Wrap(err, "unable to parse config")
|
||||
return nil, fmt.Errorf("unable to parse config: %w", err)
|
||||
}
|
||||
|
||||
if err := CompleteConfig(config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// CompleteConfig fills in the schema and other values to a config loaded from
|
||||
// YAML.
|
||||
func CompleteConfig(config *Config) error {
|
||||
defaultDirectives := map[string]DirectiveConfig{
|
||||
"skip": {SkipRuntime: true},
|
||||
"include": {SkipRuntime: true},
|
||||
"deprecated": {SkipRuntime: true},
|
||||
"skip": {SkipRuntime: true},
|
||||
"include": {SkipRuntime: true},
|
||||
"deprecated": {SkipRuntime: true},
|
||||
"specifiedBy": {SkipRuntime: true},
|
||||
}
|
||||
|
||||
for key, value := range defaultDirectives {
|
||||
@@ -140,12 +151,13 @@ func LoadConfig(filename string) (*Config, error) {
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to walk schema at root %s", pathParts[0])
|
||||
return fmt.Errorf("failed to walk schema at root %s: %w", pathParts[0], err)
|
||||
}
|
||||
} else {
|
||||
var err error
|
||||
matches, err = filepath.Glob(f)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to glob schema filename %s", f)
|
||||
return fmt.Errorf("failed to glob schema filename %s: %w", f, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,13 +175,12 @@ func LoadConfig(filename string) (*Config, error) {
|
||||
var schemaRaw []byte
|
||||
schemaRaw, err = ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to open schema")
|
||||
return fmt.Errorf("unable to open schema: %w", err)
|
||||
}
|
||||
|
||||
config.Sources = append(config.Sources, &ast.Source{Name: filename, Input: string(schemaRaw)})
|
||||
}
|
||||
|
||||
return config, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) Init() error {
|
||||
@@ -194,15 +205,8 @@ func (c *Config) Init() error {
|
||||
}
|
||||
|
||||
c.injectBuiltins()
|
||||
|
||||
// prefetch all packages in one big packages.Load call
|
||||
pkgs := []string{
|
||||
"github.com/99designs/gqlgen/graphql",
|
||||
"github.com/99designs/gqlgen/graphql/introspection",
|
||||
}
|
||||
pkgs = append(pkgs, c.Models.ReferencedPackages()...)
|
||||
pkgs = append(pkgs, c.AutoBind...)
|
||||
c.Packages.LoadAll(pkgs...)
|
||||
c.Packages.LoadAll(c.packageList()...)
|
||||
|
||||
// check everything is valid on the way out
|
||||
err = c.check()
|
||||
@@ -213,6 +217,20 @@ func (c *Config) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) packageList() []string {
|
||||
pkgs := []string{
|
||||
"github.com/99designs/gqlgen/graphql",
|
||||
"github.com/99designs/gqlgen/graphql/introspection",
|
||||
}
|
||||
pkgs = append(pkgs, c.Models.ReferencedPackages()...)
|
||||
pkgs = append(pkgs, c.AutoBind...)
|
||||
return pkgs
|
||||
}
|
||||
|
||||
func (c *Config) ReloadAllPackages() {
|
||||
c.Packages.ReloadAll(c.packageList()...)
|
||||
}
|
||||
|
||||
func (c *Config) injectTypesFromSchema() error {
|
||||
c.Directives["goModel"] = DirectiveConfig{
|
||||
SkipRuntime: true,
|
||||
@@ -222,6 +240,10 @@ func (c *Config) injectTypesFromSchema() error {
|
||||
SkipRuntime: true,
|
||||
}
|
||||
|
||||
c.Directives["goTag"] = DirectiveConfig{
|
||||
SkipRuntime: true,
|
||||
}
|
||||
|
||||
for _, schemaType := range c.Schema.Types {
|
||||
if schemaType == c.Schema.Query || schemaType == c.Schema.Mutation || schemaType == c.Schema.Subscription {
|
||||
continue
|
||||
@@ -333,10 +355,10 @@ func (c *Config) check() error {
|
||||
fileList := map[string][]FilenamePackage{}
|
||||
|
||||
if err := c.Models.Check(); err != nil {
|
||||
return errors.Wrap(err, "config.models")
|
||||
return fmt.Errorf("config.models: %w", err)
|
||||
}
|
||||
if err := c.Exec.Check(); err != nil {
|
||||
return errors.Wrap(err, "config.exec")
|
||||
return fmt.Errorf("config.exec: %w", err)
|
||||
}
|
||||
fileList[c.Exec.ImportPath()] = append(fileList[c.Exec.ImportPath()], FilenamePackage{
|
||||
Filename: c.Exec.Filename,
|
||||
@@ -346,7 +368,7 @@ func (c *Config) check() error {
|
||||
|
||||
if c.Model.IsDefined() {
|
||||
if err := c.Model.Check(); err != nil {
|
||||
return errors.Wrap(err, "config.model")
|
||||
return fmt.Errorf("config.model: %w", err)
|
||||
}
|
||||
fileList[c.Model.ImportPath()] = append(fileList[c.Model.ImportPath()], FilenamePackage{
|
||||
Filename: c.Model.Filename,
|
||||
@@ -356,7 +378,7 @@ func (c *Config) check() error {
|
||||
}
|
||||
if c.Resolver.IsDefined() {
|
||||
if err := c.Resolver.Check(); err != nil {
|
||||
return errors.Wrap(err, "config.resolver")
|
||||
return fmt.Errorf("config.resolver: %w", err)
|
||||
}
|
||||
fileList[c.Resolver.ImportPath()] = append(fileList[c.Resolver.ImportPath()], FilenamePackage{
|
||||
Filename: c.Resolver.Filename,
|
||||
@@ -366,7 +388,7 @@ func (c *Config) check() error {
|
||||
}
|
||||
if c.Federation.IsDefined() {
|
||||
if err := c.Federation.Check(); err != nil {
|
||||
return errors.Wrap(err, "config.federation")
|
||||
return fmt.Errorf("config.federation: %w", err)
|
||||
}
|
||||
fileList[c.Federation.ImportPath()] = append(fileList[c.Federation.ImportPath()], FilenamePackage{
|
||||
Filename: c.Federation.Filename,
|
||||
@@ -470,7 +492,7 @@ func inStrSlice(haystack []string, needle string) bool {
|
||||
func findCfg() (string, error) {
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "unable to get working dir to findCfg")
|
||||
return "", fmt.Errorf("unable to get working dir to findCfg: %w", err)
|
||||
}
|
||||
|
||||
cfg := findCfgInDir(dir)
|
||||
@@ -510,7 +532,7 @@ func (c *Config) autobind() error {
|
||||
}
|
||||
|
||||
for i, p := range ps {
|
||||
if p == nil {
|
||||
if p == nil || p.Module == nil {
|
||||
return fmt.Errorf("unable to load %s - make sure you're using an import path to a package that exists", c.AutoBind[i])
|
||||
}
|
||||
if t := p.Types.Scope().Lookup(t.Name); t != nil {
|
||||
@@ -554,7 +576,7 @@ func (c *Config) injectBuiltins() {
|
||||
"__EnumValue": {Model: StringList{"github.com/99designs/gqlgen/graphql/introspection.EnumValue"}},
|
||||
"__InputValue": {Model: StringList{"github.com/99designs/gqlgen/graphql/introspection.InputValue"}},
|
||||
"__Schema": {Model: StringList{"github.com/99designs/gqlgen/graphql/introspection.Schema"}},
|
||||
"Float": {Model: StringList{"github.com/99designs/gqlgen/graphql.Float"}},
|
||||
"Float": {Model: StringList{"github.com/99designs/gqlgen/graphql.FloatContext"}},
|
||||
"String": {Model: StringList{"github.com/99designs/gqlgen/graphql.String"}},
|
||||
"Boolean": {Model: StringList{"github.com/99designs/gqlgen/graphql.Boolean"}},
|
||||
"Int": {Model: StringList{
|
||||
|
||||
97
vendor/github.com/99designs/gqlgen/codegen/config/exec.go
generated
vendored
Normal file
97
vendor/github.com/99designs/gqlgen/codegen/config/exec.go
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/types"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/99designs/gqlgen/internal/code"
|
||||
)
|
||||
|
||||
type ExecConfig struct {
|
||||
Package string `yaml:"package,omitempty"`
|
||||
Layout ExecLayout `yaml:"layout,omitempty"` // Default: single-file
|
||||
|
||||
// Only for single-file layout:
|
||||
Filename string `yaml:"filename,omitempty"`
|
||||
|
||||
// Only for follow-schema layout:
|
||||
FilenameTemplate string `yaml:"filename_template,omitempty"` // String template with {name} as placeholder for base name.
|
||||
DirName string `yaml:"dir"`
|
||||
}
|
||||
|
||||
type ExecLayout string
|
||||
|
||||
var (
|
||||
// Write all generated code to a single file.
|
||||
ExecLayoutSingleFile ExecLayout = "single-file"
|
||||
// Write generated code to a directory, generating one Go source file for each GraphQL schema file.
|
||||
ExecLayoutFollowSchema ExecLayout = "follow-schema"
|
||||
)
|
||||
|
||||
func (r *ExecConfig) Check() error {
|
||||
if r.Layout == "" {
|
||||
r.Layout = ExecLayoutSingleFile
|
||||
}
|
||||
|
||||
switch r.Layout {
|
||||
case ExecLayoutSingleFile:
|
||||
if r.Filename == "" {
|
||||
return fmt.Errorf("filename must be specified when using single-file layout")
|
||||
}
|
||||
if !strings.HasSuffix(r.Filename, ".go") {
|
||||
return fmt.Errorf("filename should be path to a go source file when using single-file layout")
|
||||
}
|
||||
r.Filename = abs(r.Filename)
|
||||
case ExecLayoutFollowSchema:
|
||||
if r.DirName == "" {
|
||||
return fmt.Errorf("dir must be specified when using follow-schema layout")
|
||||
}
|
||||
r.DirName = abs(r.DirName)
|
||||
default:
|
||||
return fmt.Errorf("invalid layout %s", r.Layout)
|
||||
}
|
||||
|
||||
if strings.ContainsAny(r.Package, "./\\") {
|
||||
return fmt.Errorf("package should be the output package name only, do not include the output filename")
|
||||
}
|
||||
|
||||
if r.Package == "" && r.Dir() != "" {
|
||||
r.Package = code.NameForDir(r.Dir())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ExecConfig) ImportPath() string {
|
||||
if r.Dir() == "" {
|
||||
return ""
|
||||
}
|
||||
return code.ImportPathForDir(r.Dir())
|
||||
}
|
||||
|
||||
func (r *ExecConfig) Dir() string {
|
||||
switch r.Layout {
|
||||
case ExecLayoutSingleFile:
|
||||
if r.Filename == "" {
|
||||
return ""
|
||||
}
|
||||
return filepath.Dir(r.Filename)
|
||||
case ExecLayoutFollowSchema:
|
||||
return abs(r.DirName)
|
||||
default:
|
||||
panic("invalid layout " + r.Layout)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ExecConfig) Pkg() *types.Package {
|
||||
if r.Dir() == "" {
|
||||
return nil
|
||||
}
|
||||
return types.NewPackage(r.ImportPath(), r.Package)
|
||||
}
|
||||
|
||||
func (r *ExecConfig) IsDefined() bool {
|
||||
return r.Filename != "" || r.DirName != ""
|
||||
}
|
||||
44
vendor/github.com/99designs/gqlgen/codegen/data.go
generated
vendored
44
vendor/github.com/99designs/gqlgen/codegen/data.go
generated
vendored
@@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
"github.com/99designs/gqlgen/codegen/config"
|
||||
@@ -13,9 +12,15 @@ import (
|
||||
// Data is a unified model of the code to be generated. Plugins may modify this structure to do things like implement
|
||||
// resolvers or directives automatically (eg grpc, validation)
|
||||
type Data struct {
|
||||
Config *config.Config
|
||||
Schema *ast.Schema
|
||||
Directives DirectiveList
|
||||
Config *config.Config
|
||||
Schema *ast.Schema
|
||||
// If a schema is broken up into multiple Data instance, each representing part of the schema,
|
||||
// AllDirectives should contain the directives for the entire schema. Directives() can
|
||||
// then be used to get the directives that were defined in this Data instance's sources.
|
||||
// If a single Data instance is used for the entire schema, AllDirectives and Directives()
|
||||
// will be identical.
|
||||
// AllDirectives should rarely be used directly.
|
||||
AllDirectives DirectiveList
|
||||
Objects Objects
|
||||
Inputs Objects
|
||||
Interfaces map[string]*Interface
|
||||
@@ -34,7 +39,24 @@ type builder struct {
|
||||
Directives map[string]*Directive
|
||||
}
|
||||
|
||||
// Get only the directives which are defined in the config's sources.
|
||||
func (d *Data) Directives() DirectiveList {
|
||||
res := DirectiveList{}
|
||||
for k, directive := range d.AllDirectives {
|
||||
for _, s := range d.Config.Sources {
|
||||
if directive.Position.Src.Name == s.Name {
|
||||
res[k] = directive
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func BuildData(cfg *config.Config) (*Data, error) {
|
||||
// We reload all packages to allow packages to be compared correctly.
|
||||
cfg.ReloadAllPackages()
|
||||
|
||||
b := builder{
|
||||
Config: cfg,
|
||||
Schema: cfg.Schema,
|
||||
@@ -56,10 +78,10 @@ func BuildData(cfg *config.Config) (*Data, error) {
|
||||
}
|
||||
|
||||
s := Data{
|
||||
Config: cfg,
|
||||
Directives: dataDirectives,
|
||||
Schema: b.Schema,
|
||||
Interfaces: map[string]*Interface{},
|
||||
Config: cfg,
|
||||
AllDirectives: dataDirectives,
|
||||
Schema: b.Schema,
|
||||
Interfaces: map[string]*Interface{},
|
||||
}
|
||||
|
||||
for _, schemaType := range b.Schema.Types {
|
||||
@@ -67,14 +89,14 @@ func BuildData(cfg *config.Config) (*Data, error) {
|
||||
case ast.Object:
|
||||
obj, err := b.buildObject(schemaType)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to build object definition")
|
||||
return nil, fmt.Errorf("unable to build object definition: %w", err)
|
||||
}
|
||||
|
||||
s.Objects = append(s.Objects, obj)
|
||||
case ast.InputObject:
|
||||
input, err := b.buildObject(schemaType)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to build input definition")
|
||||
return nil, fmt.Errorf("unable to build input definition: %w", err)
|
||||
}
|
||||
|
||||
s.Inputs = append(s.Inputs, input)
|
||||
@@ -82,7 +104,7 @@ func BuildData(cfg *config.Config) (*Data, error) {
|
||||
case ast.Union, ast.Interface:
|
||||
s.Interfaces[schemaType.Name], err = b.buildInterface(schemaType)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to bind to interface")
|
||||
return nil, fmt.Errorf("unable to bind to interface: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
9
vendor/github.com/99designs/gqlgen/codegen/directive.go
generated
vendored
9
vendor/github.com/99designs/gqlgen/codegen/directive.go
generated
vendored
@@ -6,13 +6,12 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/99designs/gqlgen/codegen/templates"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
)
|
||||
|
||||
type DirectiveList map[string]*Directive
|
||||
|
||||
//LocationDirectives filter directives by location
|
||||
// LocationDirectives filter directives by location
|
||||
func (dl DirectiveList) LocationDirectives(location string) DirectiveList {
|
||||
return locationDirectives(dl, ast.DirectiveLocation(location))
|
||||
}
|
||||
@@ -24,7 +23,7 @@ type Directive struct {
|
||||
Builtin bool
|
||||
}
|
||||
|
||||
//IsLocation check location directive
|
||||
// IsLocation check location directive
|
||||
func (d *Directive) IsLocation(location ...ast.DirectiveLocation) bool {
|
||||
for _, l := range d.Locations {
|
||||
for _, a := range location {
|
||||
@@ -52,7 +51,7 @@ func (b *builder) buildDirectives() (map[string]*Directive, error) {
|
||||
|
||||
for name, dir := range b.Schema.Directives {
|
||||
if _, ok := directives[name]; ok {
|
||||
return nil, errors.Errorf("directive with name %s already exists", name)
|
||||
return nil, fmt.Errorf("directive with name %s already exists", name)
|
||||
}
|
||||
|
||||
var args []*FieldArgument
|
||||
@@ -72,7 +71,7 @@ func (b *builder) buildDirectives() (map[string]*Directive, error) {
|
||||
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())
|
||||
return nil, fmt.Errorf("default value for directive argument %s(%s) is not valid: %w", dir.Name, arg.Name, err)
|
||||
}
|
||||
}
|
||||
args = append(args, newArg)
|
||||
|
||||
51
vendor/github.com/99designs/gqlgen/codegen/field.go
generated
vendored
51
vendor/github.com/99designs/gqlgen/codegen/field.go
generated
vendored
@@ -1,6 +1,7 @@
|
||||
package codegen
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/types"
|
||||
"log"
|
||||
@@ -10,7 +11,6 @@ import (
|
||||
|
||||
"github.com/99designs/gqlgen/codegen/config"
|
||||
"github.com/99designs/gqlgen/codegen/templates"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
)
|
||||
|
||||
@@ -25,6 +25,7 @@ type Field struct {
|
||||
Args []*FieldArgument // A list of arguments to be passed to this field
|
||||
MethodHasContext bool // If this is bound to a go method, does the method also take a context
|
||||
NoErr bool // If this is bound to a go method, does that method have an error as the second argument
|
||||
VOkFunc bool // If this is bound to a go method, is it of shape (interface{}, bool)
|
||||
Object *Object // A link back to the parent object
|
||||
Default interface{} // The default value
|
||||
Stream bool // does this field return a channel?
|
||||
@@ -50,7 +51,7 @@ func (b *builder) buildField(obj *Object, field *ast.FieldDefinition) (*Field, e
|
||||
var err error
|
||||
f.Default, err = field.DefaultValue.Value(nil)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("default value %s is not valid: %s", field.Name, err.Error())
|
||||
return nil, fmt.Errorf("default value %s is not valid: %w", field.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +65,9 @@ func (b *builder) buildField(obj *Object, field *ast.FieldDefinition) (*Field, e
|
||||
|
||||
if err = b.bindField(obj, &f); err != nil {
|
||||
f.IsResolver = true
|
||||
if errors.Is(err, config.ErrTypeNotFound) {
|
||||
return nil, err
|
||||
}
|
||||
log.Println(err.Error())
|
||||
}
|
||||
|
||||
@@ -88,6 +92,11 @@ func (b *builder) bindField(obj *Object, f *Field) (errret error) {
|
||||
if err != nil {
|
||||
errret = err
|
||||
}
|
||||
for _, dir := range obj.Directives {
|
||||
if dir.IsLocation(ast.LocationInputObject) {
|
||||
dirs = append(dirs, dir)
|
||||
}
|
||||
}
|
||||
f.Directives = append(dirs, f.Directives...)
|
||||
}
|
||||
}()
|
||||
@@ -110,6 +119,7 @@ func (b *builder) bindField(obj *Object, f *Field) (errret error) {
|
||||
f.GoReceiverName = "ec"
|
||||
f.GoFieldName = "__resolve_entities"
|
||||
f.MethodHasContext = true
|
||||
f.NoErr = true
|
||||
return nil
|
||||
case f.Name == "_service":
|
||||
f.GoFieldType = GoFieldMethod
|
||||
@@ -152,6 +162,8 @@ func (b *builder) bindField(obj *Object, f *Field) (errret error) {
|
||||
sig := target.Type().(*types.Signature)
|
||||
if sig.Results().Len() == 1 {
|
||||
f.NoErr = true
|
||||
} else if s := sig.Results(); s.Len() == 2 && s.At(1).Type().String() == "bool" {
|
||||
f.VOkFunc = true
|
||||
} else if sig.Results().Len() != 2 {
|
||||
return fmt.Errorf("method has wrong number of args")
|
||||
}
|
||||
@@ -167,10 +179,13 @@ func (b *builder) bindField(obj *Object, f *Field) (errret error) {
|
||||
params = types.NewTuple(vars...)
|
||||
}
|
||||
|
||||
if err = b.bindArgs(f, params); err != nil {
|
||||
return errors.Wrapf(err, "%s:%d", pos.Filename, pos.Line)
|
||||
// Try to match target function's arguments with GraphQL field arguments
|
||||
newArgs, err := b.bindArgs(f, params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s:%d: %w", pos.Filename, pos.Line, err)
|
||||
}
|
||||
|
||||
// Try to match target function's return types with GraphQL field return type
|
||||
result := sig.Results().At(0)
|
||||
tr, err := b.Binder.TypeReference(f.Type, result.Type())
|
||||
if err != nil {
|
||||
@@ -181,6 +196,7 @@ func (b *builder) bindField(obj *Object, f *Field) (errret error) {
|
||||
f.GoFieldType = GoFieldMethod
|
||||
f.GoReceiverName = "obj"
|
||||
f.GoFieldName = target.Name()
|
||||
f.Args = newArgs
|
||||
f.TypeReference = tr
|
||||
|
||||
return nil
|
||||
@@ -237,7 +253,7 @@ func (b *builder) findBindTarget(t types.Type, name string) (types.Object, error
|
||||
return foundField, nil
|
||||
case foundField != nil && foundMethod != nil:
|
||||
// Error
|
||||
return nil, errors.Errorf("found more than one way to bind for %s", name)
|
||||
return nil, fmt.Errorf("found more than one way to bind for %s", name)
|
||||
}
|
||||
|
||||
// Search embeds
|
||||
@@ -262,7 +278,7 @@ func (b *builder) findBindStructTagTarget(in types.Type, name string) (types.Obj
|
||||
tags := reflect.StructTag(t.Tag(i))
|
||||
if val, ok := tags.Lookup(b.Config.StructTag); ok && equalFieldName(val, name) {
|
||||
if found != nil {
|
||||
return nil, errors.Errorf("tag %s is ambigious; multiple fields have the same tag value of %s", b.Config.StructTag, val)
|
||||
return nil, fmt.Errorf("tag %s is ambigious; multiple fields have the same tag value of %s", b.Config.StructTag, val)
|
||||
}
|
||||
|
||||
found = field
|
||||
@@ -300,7 +316,7 @@ func (b *builder) findBindMethoderTarget(methodFunc func(i int) *types.Func, met
|
||||
}
|
||||
|
||||
if found != nil {
|
||||
return nil, errors.Errorf("found more than one matching method to bind for %s", name)
|
||||
return nil, fmt.Errorf("found more than one matching method to bind for %s", name)
|
||||
}
|
||||
|
||||
found = method
|
||||
@@ -322,7 +338,7 @@ func (b *builder) findBindFieldTarget(in types.Type, name string) (types.Object,
|
||||
}
|
||||
|
||||
if found != nil {
|
||||
return nil, errors.Errorf("found more than one matching field to bind for %s", name)
|
||||
return nil, fmt.Errorf("found more than one matching field to bind for %s", name)
|
||||
}
|
||||
|
||||
found = field
|
||||
@@ -366,7 +382,7 @@ func (b *builder) findBindStructEmbedsTarget(strukt *types.Struct, name string)
|
||||
}
|
||||
|
||||
if f != nil && found != nil {
|
||||
return nil, errors.Errorf("found more than one way to bind for %s", name)
|
||||
return nil, fmt.Errorf("found more than one way to bind for %s", name)
|
||||
}
|
||||
|
||||
if f != nil {
|
||||
@@ -388,7 +404,7 @@ func (b *builder) findBindInterfaceEmbedsTarget(iface *types.Interface, name str
|
||||
}
|
||||
|
||||
if f != nil && found != nil {
|
||||
return nil, errors.Errorf("found more than one way to bind for %s", name)
|
||||
return nil, fmt.Errorf("found more than one way to bind for %s", name)
|
||||
}
|
||||
|
||||
if f != nil {
|
||||
@@ -417,7 +433,8 @@ func (f *Field) ImplDirectives() []*Directive {
|
||||
loc = ast.LocationInputFieldDefinition
|
||||
}
|
||||
for i := range f.Directives {
|
||||
if !f.Directives[i].Builtin && f.Directives[i].IsLocation(loc, ast.LocationObject) {
|
||||
if !f.Directives[i].Builtin &&
|
||||
(f.Directives[i].IsLocation(loc, ast.LocationObject) || f.Directives[i].IsLocation(loc, ast.LocationInputObject)) {
|
||||
d = append(d, f.Directives[i])
|
||||
}
|
||||
}
|
||||
@@ -452,7 +469,10 @@ func (f *Field) GoNameUnexported() string {
|
||||
}
|
||||
|
||||
func (f *Field) ShortInvocation() string {
|
||||
return fmt.Sprintf("%s().%s(%s)", f.Object.Definition.Name, f.GoFieldName, f.CallArgs())
|
||||
if f.Object.Kind == ast.InputObject {
|
||||
return fmt.Sprintf("%s().%s(ctx, &it, data)", strings.Title(f.Object.Definition.Name), f.GoFieldName)
|
||||
}
|
||||
return fmt.Sprintf("%s().%s(%s)", strings.Title(f.Object.Definition.Name), f.GoFieldName, f.CallArgs())
|
||||
}
|
||||
|
||||
func (f *Field) ArgsFunc() string {
|
||||
@@ -472,6 +492,13 @@ func (f *Field) ResolverType() string {
|
||||
}
|
||||
|
||||
func (f *Field) ShortResolverDeclaration() string {
|
||||
if f.Object.Kind == ast.InputObject {
|
||||
return fmt.Sprintf("(ctx context.Context, obj %s, data %s) error",
|
||||
templates.CurrentImports.LookupType(f.Object.Reference()),
|
||||
templates.CurrentImports.LookupType(f.TypeReference.GO),
|
||||
)
|
||||
}
|
||||
|
||||
res := "(ctx context.Context"
|
||||
|
||||
if !f.Object.Root {
|
||||
|
||||
13
vendor/github.com/99designs/gqlgen/codegen/field.gotpl
generated
vendored
13
vendor/github.com/99designs/gqlgen/codegen/field.gotpl
generated
vendored
@@ -16,6 +16,7 @@ func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Contex
|
||||
Field: field,
|
||||
Args: nil,
|
||||
IsMethod: {{or $field.IsMethod $field.IsResolver}},
|
||||
IsResolver: {{ $field.IsResolver }},
|
||||
}
|
||||
|
||||
ctx = graphql.WithFieldContext(ctx, fc)
|
||||
@@ -28,7 +29,7 @@ func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Contex
|
||||
}
|
||||
fc.Args = args
|
||||
{{- end }}
|
||||
{{- if $.Directives.LocationDirectives "FIELD" }}
|
||||
{{- if $.AllDirectives.LocationDirectives "FIELD" }}
|
||||
resTmp := ec._fieldMiddleware(ctx, {{if $object.Root}}nil{{else}}obj{{end}}, func(rctx context.Context) (interface{}, error) {
|
||||
{{ template "field" $field }}
|
||||
})
|
||||
@@ -81,7 +82,7 @@ func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Contex
|
||||
{{ template "implDirectives" . }}
|
||||
tmp, err := directive{{.ImplDirectives|len}}(rctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
if tmp == nil {
|
||||
return nil, nil
|
||||
@@ -111,7 +112,13 @@ func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Contex
|
||||
return nil, fmt.Errorf("unexpected type %T for field %s", v, {{ .Name | quote}})
|
||||
}
|
||||
{{- else if .IsMethod -}}
|
||||
{{- if .NoErr -}}
|
||||
{{- if .VOkFunc -}}
|
||||
v, ok := {{.GoReceiverName}}.{{.GoFieldName}}({{ .CallArgs }})
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
return v, nil
|
||||
{{- else if .NoErr -}}
|
||||
return {{.GoReceiverName}}.{{.GoFieldName}}({{ .CallArgs }}), nil
|
||||
{{- else -}}
|
||||
return {{.GoReceiverName}}.{{.GoFieldName}}({{ .CallArgs }})
|
||||
|
||||
197
vendor/github.com/99designs/gqlgen/codegen/generate.go
generated
vendored
197
vendor/github.com/99designs/gqlgen/codegen/generate.go
generated
vendored
@@ -1,10 +1,34 @@
|
||||
package codegen
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/99designs/gqlgen/codegen/config"
|
||||
"github.com/99designs/gqlgen/codegen/templates"
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
)
|
||||
|
||||
func GenerateCode(data *Data) error {
|
||||
if !data.Config.Exec.IsDefined() {
|
||||
return fmt.Errorf("missing exec config")
|
||||
}
|
||||
|
||||
switch data.Config.Exec.Layout {
|
||||
case config.ExecLayoutSingleFile:
|
||||
return generateSingleFile(data)
|
||||
case config.ExecLayoutFollowSchema:
|
||||
return generatePerSchema(data)
|
||||
}
|
||||
|
||||
return fmt.Errorf("unrecognized exec layout %s", data.Config.Exec.Layout)
|
||||
}
|
||||
|
||||
func generateSingleFile(data *Data) error {
|
||||
return templates.Render(templates.Options{
|
||||
PackageName: data.Config.Exec.Package,
|
||||
Filename: data.Config.Exec.Filename,
|
||||
@@ -14,3 +38,176 @@ func GenerateCode(data *Data) error {
|
||||
Packages: data.Config.Packages,
|
||||
})
|
||||
}
|
||||
|
||||
func generatePerSchema(data *Data) error {
|
||||
err := generateRootFile(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
builds := map[string]*Data{}
|
||||
|
||||
err = addObjects(data, &builds)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = addInputs(data, &builds)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = addInterfaces(data, &builds)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = addReferencedTypes(data, &builds)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for filename, build := range builds {
|
||||
if filename == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
dir := data.Config.Exec.DirName
|
||||
path := filepath.Join(dir, filename)
|
||||
|
||||
err = templates.Render(templates.Options{
|
||||
PackageName: data.Config.Exec.Package,
|
||||
Filename: path,
|
||||
Data: build,
|
||||
RegionTags: true,
|
||||
GeneratedHeader: true,
|
||||
Packages: data.Config.Packages,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func filename(p *ast.Position, config *config.Config) string {
|
||||
name := "common!"
|
||||
if p != nil && p.Src != nil {
|
||||
gqlname := filepath.Base(p.Src.Name)
|
||||
ext := filepath.Ext(p.Src.Name)
|
||||
name = strings.TrimSuffix(gqlname, ext)
|
||||
}
|
||||
|
||||
filenameTempl := config.Exec.FilenameTemplate
|
||||
if filenameTempl == "" {
|
||||
filenameTempl = "{name}.generated.go"
|
||||
}
|
||||
|
||||
return strings.ReplaceAll(filenameTempl, "{name}", name)
|
||||
}
|
||||
|
||||
func addBuild(filename string, p *ast.Position, data *Data, builds *map[string]*Data) {
|
||||
buildConfig := *data.Config
|
||||
if p != nil {
|
||||
buildConfig.Sources = []*ast.Source{p.Src}
|
||||
}
|
||||
|
||||
(*builds)[filename] = &Data{
|
||||
Config: &buildConfig,
|
||||
QueryRoot: data.QueryRoot,
|
||||
MutationRoot: data.MutationRoot,
|
||||
SubscriptionRoot: data.SubscriptionRoot,
|
||||
AllDirectives: data.AllDirectives,
|
||||
}
|
||||
}
|
||||
|
||||
// Root file contains top-level definitions that should not be duplicated across the generated
|
||||
// files for each schema file.
|
||||
func generateRootFile(data *Data) error {
|
||||
dir := data.Config.Exec.DirName
|
||||
path := filepath.Join(dir, "root_.generated.go")
|
||||
|
||||
_, thisFile, _, _ := runtime.Caller(0)
|
||||
rootDir := filepath.Dir(thisFile)
|
||||
templatePath := filepath.Join(rootDir, "root_.gotpl")
|
||||
templateBytes, err := ioutil.ReadFile(templatePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
template := string(templateBytes)
|
||||
|
||||
return templates.Render(templates.Options{
|
||||
PackageName: data.Config.Exec.Package,
|
||||
Template: template,
|
||||
Filename: path,
|
||||
Data: data,
|
||||
RegionTags: false,
|
||||
GeneratedHeader: true,
|
||||
Packages: data.Config.Packages,
|
||||
})
|
||||
}
|
||||
|
||||
func addObjects(data *Data, builds *map[string]*Data) error {
|
||||
for _, o := range data.Objects {
|
||||
filename := filename(o.Position, data.Config)
|
||||
if (*builds)[filename] == nil {
|
||||
addBuild(filename, o.Position, data, builds)
|
||||
}
|
||||
|
||||
(*builds)[filename].Objects = append((*builds)[filename].Objects, o)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func addInputs(data *Data, builds *map[string]*Data) error {
|
||||
for _, in := range data.Inputs {
|
||||
filename := filename(in.Position, data.Config)
|
||||
if (*builds)[filename] == nil {
|
||||
addBuild(filename, in.Position, data, builds)
|
||||
}
|
||||
|
||||
(*builds)[filename].Inputs = append((*builds)[filename].Inputs, in)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func addInterfaces(data *Data, builds *map[string]*Data) error {
|
||||
for k, inf := range data.Interfaces {
|
||||
filename := filename(inf.Position, data.Config)
|
||||
if (*builds)[filename] == nil {
|
||||
addBuild(filename, inf.Position, data, builds)
|
||||
}
|
||||
build := (*builds)[filename]
|
||||
|
||||
if build.Interfaces == nil {
|
||||
build.Interfaces = map[string]*Interface{}
|
||||
}
|
||||
if build.Interfaces[k] != nil {
|
||||
return errors.New("conflicting interface keys")
|
||||
}
|
||||
|
||||
build.Interfaces[k] = inf
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func addReferencedTypes(data *Data, builds *map[string]*Data) error {
|
||||
for k, rt := range data.ReferencedTypes {
|
||||
filename := filename(rt.Definition.Position, data.Config)
|
||||
if (*builds)[filename] == nil {
|
||||
addBuild(filename, rt.Definition.Position, data, builds)
|
||||
}
|
||||
build := (*builds)[filename]
|
||||
|
||||
if build.ReferencedTypes == nil {
|
||||
build.ReferencedTypes = map[string]*config.TypeReference{}
|
||||
}
|
||||
if build.ReferencedTypes[k] != nil {
|
||||
return errors.New("conflicting referenced type keys")
|
||||
}
|
||||
|
||||
build.ReferencedTypes[k] = rt
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
319
vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl
generated
vendored
319
vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl
generated
vendored
@@ -14,51 +14,70 @@
|
||||
{{ reserveImport "github.com/99designs/gqlgen/graphql/introspection" }}
|
||||
|
||||
|
||||
// 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,
|
||||
{{ if eq .Config.Exec.Layout "single-file" }}
|
||||
// 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 Config struct {
|
||||
Resolvers ResolverRoot
|
||||
Directives DirectiveRoot
|
||||
Complexity ComplexityRoot
|
||||
}
|
||||
|
||||
type ResolverRoot interface {
|
||||
{{- range $object := .Objects -}}
|
||||
type ResolverRoot interface {
|
||||
{{- range $object := .Objects -}}
|
||||
{{ if $object.HasResolvers -}}
|
||||
{{ucFirst $object.Name}}() {{ucFirst $object.Name}}Resolver
|
||||
{{ end }}
|
||||
{{- end }}
|
||||
{{- range $object := .Inputs -}}
|
||||
{{ if $object.HasResolvers -}}
|
||||
{{$object.Name}}() {{$object.Name}}Resolver
|
||||
{{ucFirst $object.Name}}() {{ucFirst $object.Name}}Resolver
|
||||
{{ end }}
|
||||
{{- end }}
|
||||
}
|
||||
|
||||
type DirectiveRoot struct {
|
||||
{{ range $directive := .Directives }}
|
||||
{{- $directive.Declaration }}
|
||||
{{ end }}
|
||||
}
|
||||
type DirectiveRoot struct {
|
||||
{{ range $directive := .Directives }}
|
||||
{{- $directive.Declaration }}
|
||||
{{ end }}
|
||||
}
|
||||
|
||||
type ComplexityRoot struct {
|
||||
{{ range $object := .Objects }}
|
||||
{{ if not $object.IsReserved -}}
|
||||
{{ $object.Name|go }} struct {
|
||||
{{ range $_, $fields := $object.UniqueFields }}
|
||||
{{- $field := index $fields 0 -}}
|
||||
{{ if not $field.IsReserved -}}
|
||||
{{ $field.GoFieldName }} {{ $field.ComplexitySignature }}
|
||||
{{ end }}
|
||||
type ComplexityRoot struct {
|
||||
{{ range $object := .Objects }}
|
||||
{{ if not $object.IsReserved -}}
|
||||
{{ ucFirst $object.Name }} struct {
|
||||
{{ range $_, $fields := $object.UniqueFields }}
|
||||
{{- $field := index $fields 0 -}}
|
||||
{{ if not $field.IsReserved -}}
|
||||
{{ $field.GoFieldName }} {{ $field.ComplexitySignature }}
|
||||
{{ end }}
|
||||
{{- end }}
|
||||
}
|
||||
{{- end }}
|
||||
}
|
||||
{{- end }}
|
||||
{{ end }}
|
||||
}
|
||||
{{ end }}
|
||||
}
|
||||
|
||||
{{ range $object := .Objects -}}
|
||||
{{ if $object.HasResolvers }}
|
||||
type {{ucFirst $object.Name}}Resolver interface {
|
||||
{{ range $field := $object.Fields -}}
|
||||
{{- if $field.IsResolver }}
|
||||
{{- $field.GoFieldName}}{{ $field.ShortResolverDeclaration }}
|
||||
{{- end }}
|
||||
{{ end }}
|
||||
}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{ range $object := .Inputs -}}
|
||||
{{ if $object.HasResolvers }}
|
||||
type {{$object.Name}}Resolver interface {
|
||||
{{ range $field := $object.Fields -}}
|
||||
@@ -70,145 +89,147 @@ type ComplexityRoot struct {
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
type executableSchema struct {
|
||||
resolvers ResolverRoot
|
||||
directives DirectiveRoot
|
||||
complexity ComplexityRoot
|
||||
}
|
||||
{{ if eq .Config.Exec.Layout "single-file" }}
|
||||
type executableSchema struct {
|
||||
resolvers ResolverRoot
|
||||
directives DirectiveRoot
|
||||
complexity ComplexityRoot
|
||||
}
|
||||
|
||||
func (e *executableSchema) Schema() *ast.Schema {
|
||||
return parsedSchema
|
||||
}
|
||||
func (e *executableSchema) Schema() *ast.Schema {
|
||||
return parsedSchema
|
||||
}
|
||||
|
||||
func (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) {
|
||||
ec := executionContext{nil, e}
|
||||
_ = ec
|
||||
switch typeName + "." + field {
|
||||
{{ range $object := .Objects }}
|
||||
{{ if not $object.IsReserved }}
|
||||
{{ range $_, $fields := $object.UniqueFields }}
|
||||
{{- $len := len $fields }}
|
||||
{{- range $i, $field := $fields }}
|
||||
{{- $last := eq (add $i 1) $len }}
|
||||
{{- if not $field.IsReserved }}
|
||||
{{- if eq $i 0 }}case {{ end }}"{{$object.Name}}.{{$field.Name}}"{{ if not $last }},{{ else }}:
|
||||
if e.complexity.{{$object.Name|go}}.{{$field.GoFieldName}} == nil {
|
||||
break
|
||||
}
|
||||
{{ if $field.Args }}
|
||||
args, err := ec.{{ $field.ArgsFunc }}(context.TODO(),rawArgs)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
func (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) {
|
||||
ec := executionContext{nil, e}
|
||||
_ = ec
|
||||
switch typeName + "." + field {
|
||||
{{ range $object := .Objects }}
|
||||
{{ if not $object.IsReserved }}
|
||||
{{ range $_, $fields := $object.UniqueFields }}
|
||||
{{- $len := len $fields }}
|
||||
{{- range $i, $field := $fields }}
|
||||
{{- $last := eq (add $i 1) $len }}
|
||||
{{- if not $field.IsReserved }}
|
||||
{{- if eq $i 0 }}case {{ end }}"{{$object.Name}}.{{$field.Name}}"{{ if not $last }},{{ else }}:
|
||||
if e.complexity.{{ucFirst $object.Name}}.{{$field.GoFieldName}} == nil {
|
||||
break
|
||||
}
|
||||
{{ if $field.Args }}
|
||||
args, err := ec.{{ $field.ArgsFunc }}(context.TODO(),rawArgs)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
{{ end }}
|
||||
return e.complexity.{{ucFirst $object.Name}}.{{$field.GoFieldName}}(childComplexity{{if $field.Args}}, {{$field.ComplexityArgs}} {{ end }}), true
|
||||
{{ end }}
|
||||
return e.complexity.{{$object.Name|go}}.{{$field.GoFieldName}}(childComplexity{{if $field.Args}}, {{$field.ComplexityArgs}} {{ end }}), true
|
||||
{{ end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
|
||||
rc := graphql.GetOperationContext(ctx)
|
||||
ec := executionContext{rc, e}
|
||||
first := true
|
||||
func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
|
||||
rc := graphql.GetOperationContext(ctx)
|
||||
ec := executionContext{rc, e}
|
||||
first := true
|
||||
|
||||
switch rc.Operation.Operation {
|
||||
{{- if .QueryRoot }} case ast.Query:
|
||||
return func(ctx context.Context) *graphql.Response {
|
||||
if !first { return nil }
|
||||
first = false
|
||||
{{ if .Directives.LocationDirectives "QUERY" -}}
|
||||
data := ec._queryMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error){
|
||||
return ec._{{.QueryRoot.Name}}(ctx, rc.Operation.SelectionSet), nil
|
||||
switch rc.Operation.Operation {
|
||||
{{- if .QueryRoot }} case ast.Query:
|
||||
return func(ctx context.Context) *graphql.Response {
|
||||
if !first { return nil }
|
||||
first = false
|
||||
{{ if .Directives.LocationDirectives "QUERY" -}}
|
||||
data := ec._queryMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error){
|
||||
return ec._{{.QueryRoot.Name}}(ctx, rc.Operation.SelectionSet), nil
|
||||
})
|
||||
{{- else -}}
|
||||
data := ec._{{.QueryRoot.Name}}(ctx, rc.Operation.SelectionSet)
|
||||
{{- end }}
|
||||
var buf bytes.Buffer
|
||||
data.MarshalGQL(&buf)
|
||||
|
||||
return &graphql.Response{
|
||||
Data: buf.Bytes(),
|
||||
}
|
||||
}
|
||||
{{ end }}
|
||||
|
||||
{{- if .MutationRoot }} case ast.Mutation:
|
||||
return func(ctx context.Context) *graphql.Response {
|
||||
if !first { return nil }
|
||||
first = false
|
||||
{{ if .Directives.LocationDirectives "MUTATION" -}}
|
||||
data := ec._mutationMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error){
|
||||
return ec._{{.MutationRoot.Name}}(ctx, rc.Operation.SelectionSet), nil
|
||||
})
|
||||
{{- else -}}
|
||||
data := ec._{{.MutationRoot.Name}}(ctx, rc.Operation.SelectionSet)
|
||||
{{- end }}
|
||||
var buf bytes.Buffer
|
||||
data.MarshalGQL(&buf)
|
||||
|
||||
return &graphql.Response{
|
||||
Data: buf.Bytes(),
|
||||
}
|
||||
}
|
||||
{{ end }}
|
||||
|
||||
{{- if .SubscriptionRoot }} case ast.Subscription:
|
||||
{{ if .Directives.LocationDirectives "SUBSCRIPTION" -}}
|
||||
next := ec._subscriptionMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error){
|
||||
return ec._{{.SubscriptionRoot.Name}}(ctx, rc.Operation.SelectionSet),nil
|
||||
})
|
||||
{{- else -}}
|
||||
data := ec._{{.QueryRoot.Name}}(ctx, rc.Operation.SelectionSet)
|
||||
next := ec._{{.SubscriptionRoot.Name}}(ctx, rc.Operation.SelectionSet)
|
||||
{{- end }}
|
||||
|
||||
var buf bytes.Buffer
|
||||
data.MarshalGQL(&buf)
|
||||
return func(ctx context.Context) *graphql.Response {
|
||||
buf.Reset()
|
||||
data := next()
|
||||
|
||||
return &graphql.Response{
|
||||
Data: buf.Bytes(),
|
||||
if data == nil {
|
||||
return nil
|
||||
}
|
||||
data.MarshalGQL(&buf)
|
||||
|
||||
return &graphql.Response{
|
||||
Data: buf.Bytes(),
|
||||
}
|
||||
}
|
||||
{{ end }}
|
||||
default:
|
||||
return graphql.OneShot(graphql.ErrorResponse(ctx, "unsupported GraphQL operation"))
|
||||
}
|
||||
{{ end }}
|
||||
}
|
||||
|
||||
{{- if .MutationRoot }} case ast.Mutation:
|
||||
return func(ctx context.Context) *graphql.Response {
|
||||
if !first { return nil }
|
||||
first = false
|
||||
{{ if .Directives.LocationDirectives "MUTATION" -}}
|
||||
data := ec._mutationMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error){
|
||||
return ec._{{.MutationRoot.Name}}(ctx, rc.Operation.SelectionSet), nil
|
||||
})
|
||||
{{- else -}}
|
||||
data := ec._{{.MutationRoot.Name}}(ctx, rc.Operation.SelectionSet)
|
||||
{{- end }}
|
||||
var buf bytes.Buffer
|
||||
data.MarshalGQL(&buf)
|
||||
type executionContext struct {
|
||||
*graphql.OperationContext
|
||||
*executableSchema
|
||||
}
|
||||
|
||||
return &graphql.Response{
|
||||
Data: buf.Bytes(),
|
||||
}
|
||||
func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
|
||||
if ec.DisableIntrospection {
|
||||
return nil, errors.New("introspection disabled")
|
||||
}
|
||||
{{ end }}
|
||||
return introspection.WrapSchema(parsedSchema), nil
|
||||
}
|
||||
|
||||
{{- if .SubscriptionRoot }} case ast.Subscription:
|
||||
{{ if .Directives.LocationDirectives "SUBSCRIPTION" -}}
|
||||
next := ec._subscriptionMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error){
|
||||
return ec._{{.SubscriptionRoot.Name}}(ctx, rc.Operation.SelectionSet),nil
|
||||
})
|
||||
{{- else -}}
|
||||
next := ec._{{.SubscriptionRoot.Name}}(ctx, rc.Operation.SelectionSet)
|
||||
{{- end }}
|
||||
|
||||
var buf bytes.Buffer
|
||||
return func(ctx context.Context) *graphql.Response {
|
||||
buf.Reset()
|
||||
data := next()
|
||||
|
||||
if data == nil {
|
||||
return nil
|
||||
}
|
||||
data.MarshalGQL(&buf)
|
||||
|
||||
return &graphql.Response{
|
||||
Data: buf.Bytes(),
|
||||
}
|
||||
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
|
||||
if ec.DisableIntrospection {
|
||||
return nil, errors.New("introspection disabled")
|
||||
}
|
||||
{{ end }}
|
||||
default:
|
||||
return graphql.OneShot(graphql.ErrorResponse(ctx, "unsupported GraphQL operation"))
|
||||
return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
|
||||
}
|
||||
}
|
||||
|
||||
type executionContext struct {
|
||||
*graphql.OperationContext
|
||||
*executableSchema
|
||||
}
|
||||
|
||||
func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
|
||||
if ec.DisableIntrospection {
|
||||
return nil, errors.New("introspection disabled")
|
||||
var sources = []*ast.Source{
|
||||
{{- range $source := .Config.Sources }}
|
||||
{Name: {{$source.Name|quote}}, Input: {{$source.Input|rawQuote}}, BuiltIn: {{$source.BuiltIn}}},
|
||||
{{- end }}
|
||||
}
|
||||
return introspection.WrapSchema(parsedSchema), nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
|
||||
if ec.DisableIntrospection {
|
||||
return nil, errors.New("introspection disabled")
|
||||
}
|
||||
return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
|
||||
}
|
||||
|
||||
var sources = []*ast.Source{
|
||||
{{- range $source := .Config.Sources }}
|
||||
{Name: {{$source.Name|quote}}, Input: {{$source.Input|rawQuote}}, BuiltIn: {{$source.BuiltIn}}},
|
||||
{{- end }}
|
||||
}
|
||||
var parsedSchema = gqlparser.MustLoadSchema(sources...)
|
||||
var parsedSchema = gqlparser.MustLoadSchema(sources...)
|
||||
{{ end }}
|
||||
|
||||
42
vendor/github.com/99designs/gqlgen/codegen/input.gotpl
generated
vendored
42
vendor/github.com/99designs/gqlgen/codegen/input.gotpl
generated
vendored
@@ -2,9 +2,12 @@
|
||||
{{- if not .HasUnmarshal }}
|
||||
func (ec *executionContext) unmarshalInput{{ .Name }}(ctx context.Context, obj interface{}) ({{.Type | ref}}, error) {
|
||||
var it {{.Type | ref}}
|
||||
var asMap = obj.(map[string]interface{})
|
||||
asMap := map[string]interface{}{}
|
||||
for k, v := range obj.(map[string]interface{}) {
|
||||
asMap[k] = v
|
||||
}
|
||||
{{ range $field := .Fields}}
|
||||
{{- if $field.Default}}
|
||||
{{- if notNil "Default" $field }}
|
||||
if _, present := asMap[{{$field.Name|quote}}] ; !present {
|
||||
asMap[{{$field.Name|quote}}] = {{ $field.Default | dump }}
|
||||
}
|
||||
@@ -17,28 +20,47 @@
|
||||
case {{$field.Name|quote}}:
|
||||
var err error
|
||||
|
||||
ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField({{$field.Name|quote}}))
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField({{$field.Name|quote}}))
|
||||
{{- if $field.ImplDirectives }}
|
||||
directive0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $field.TypeReference.UnmarshalFunc }}(ctx, v) }
|
||||
{{ template "implDirectives" $field }}
|
||||
tmp, err := directive{{$field.ImplDirectives|len}}(ctx)
|
||||
if err != nil {
|
||||
return it, err
|
||||
return it, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
if data, ok := tmp.({{ $field.TypeReference.GO | ref }}) ; ok {
|
||||
it.{{$field.GoFieldName}} = data
|
||||
{{- if $field.IsResolver }}
|
||||
if err = ec.resolvers.{{ $field.ShortInvocation }}; err != nil {
|
||||
return it, err
|
||||
}
|
||||
{{- else }}
|
||||
it.{{$field.GoFieldName}} = data
|
||||
{{- end }}
|
||||
{{- if $field.TypeReference.IsNilable }}
|
||||
{{- if not $field.IsResolver }}
|
||||
} else if tmp == nil {
|
||||
it.{{$field.GoFieldName}} = nil
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
} else {
|
||||
return it, fmt.Errorf(`unexpected type %T from directive, should be {{ $field.TypeReference.GO }}`, tmp)
|
||||
err := fmt.Errorf(`unexpected type %T from directive, should be {{ $field.TypeReference.GO }}`, tmp)
|
||||
return it, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
{{- else }}
|
||||
it.{{$field.GoFieldName}}, err = ec.{{ $field.TypeReference.UnmarshalFunc }}(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
{{- if $field.IsResolver }}
|
||||
data, err := ec.{{ $field.TypeReference.UnmarshalFunc }}(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
if err = ec.resolvers.{{ $field.ShortInvocation }}; err != nil {
|
||||
return it, err
|
||||
}
|
||||
{{- else }}
|
||||
it.{{$field.GoFieldName}}, err = ec.{{ $field.TypeReference.UnmarshalFunc }}(ctx, v)
|
||||
if err != nil {
|
||||
return it, err
|
||||
}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
}
|
||||
|
||||
3
vendor/github.com/99designs/gqlgen/codegen/interface.go
generated
vendored
3
vendor/github.com/99designs/gqlgen/codegen/interface.go
generated
vendored
@@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
"go/types"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
"github.com/99designs/gqlgen/codegen/config"
|
||||
@@ -49,7 +48,7 @@ func (b *builder) buildInterface(typ *ast.Definition) (*Interface, error) {
|
||||
|
||||
implementorType, err := findGoNamedType(obj)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "can not find backing go type %s", obj.String())
|
||||
return nil, fmt.Errorf("can not find backing go type %s: %w", obj.String(), err)
|
||||
} else if implementorType == nil {
|
||||
return nil, fmt.Errorf("can not find backing go type %s", obj.String())
|
||||
}
|
||||
|
||||
6
vendor/github.com/99designs/gqlgen/codegen/object.go
generated
vendored
6
vendor/github.com/99designs/gqlgen/codegen/object.go
generated
vendored
@@ -1,13 +1,13 @@
|
||||
package codegen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/types"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/99designs/gqlgen/codegen/config"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
)
|
||||
|
||||
@@ -36,7 +36,7 @@ type Object struct {
|
||||
func (b *builder) buildObject(typ *ast.Definition) (*Object, error) {
|
||||
dirs, err := b.getDirectives(typ.Directives)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, typ.Name)
|
||||
return nil, fmt.Errorf("%s: %w", typ.Name, err)
|
||||
}
|
||||
|
||||
obj := &Object{
|
||||
@@ -46,7 +46,7 @@ func (b *builder) buildObject(typ *ast.Definition) (*Object, error) {
|
||||
Stream: typ == b.Schema.Subscription,
|
||||
Directives: dirs,
|
||||
ResolverInterface: types.NewNamed(
|
||||
types.NewTypeName(0, b.Config.Exec.Pkg(), typ.Name+"Resolver", nil),
|
||||
types.NewTypeName(0, b.Config.Exec.Pkg(), strings.Title(typ.Name)+"Resolver", nil),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
|
||||
122
vendor/github.com/99designs/gqlgen/codegen/object.gotpl
generated
vendored
122
vendor/github.com/99designs/gqlgen/codegen/object.gotpl
generated
vendored
@@ -25,56 +25,84 @@ func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.Selec
|
||||
{{- else }}
|
||||
func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.SelectionSet{{ if not $object.Root }},obj {{$object.Reference | ref }}{{ end }}) graphql.Marshaler {
|
||||
fields := graphql.CollectFields(ec.OperationContext, sel, {{$object.Name|lcFirst}}Implementors)
|
||||
{{if $object.Root}}
|
||||
ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{
|
||||
Object: {{$object.Name|quote}},
|
||||
})
|
||||
{{end}}
|
||||
|
||||
{{- if $object.Root }}
|
||||
ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{
|
||||
Object: {{$object.Name|quote}},
|
||||
})
|
||||
{{end}}
|
||||
out := graphql.NewFieldSet(fields)
|
||||
var invalids uint32
|
||||
for i, field := range fields {
|
||||
switch field.Name {
|
||||
case "__typename":
|
||||
out.Values[i] = graphql.MarshalString({{$object.Name|quote}})
|
||||
{{- range $field := $object.Fields }}
|
||||
case "{{$field.Name}}":
|
||||
{{- if $field.IsConcurrent }}
|
||||
field := field
|
||||
out.Concurrently(i, func() (res graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
}
|
||||
}()
|
||||
res = ec._{{$object.Name}}_{{$field.Name}}(ctx, field{{if not $object.Root}}, obj{{end}})
|
||||
{{- if $field.TypeReference.GQL.NonNull }}
|
||||
if res == graphql.Null {
|
||||
{{- if $object.IsConcurrent }}
|
||||
atomic.AddUint32(&invalids, 1)
|
||||
{{- else }}
|
||||
invalids++
|
||||
{{- end }}
|
||||
}
|
||||
{{- end }}
|
||||
return res
|
||||
})
|
||||
{{- else }}
|
||||
out.Values[i] = ec._{{$object.Name}}_{{$field.Name}}(ctx, field{{if not $object.Root}}, obj{{end}})
|
||||
{{- if $field.TypeReference.GQL.NonNull }}
|
||||
if out.Values[i] == graphql.Null {
|
||||
{{- if $object.IsConcurrent }}
|
||||
atomic.AddUint32(&invalids, 1)
|
||||
{{- else }}
|
||||
invalids++
|
||||
{{- end }}
|
||||
}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
default:
|
||||
panic("unknown field " + strconv.Quote(field.Name))
|
||||
}
|
||||
{{- if $object.Root }}
|
||||
innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{
|
||||
Object: field.Name,
|
||||
Field: field,
|
||||
})
|
||||
{{end}}
|
||||
switch field.Name {
|
||||
case "__typename":
|
||||
out.Values[i] = graphql.MarshalString({{$object.Name|quote}})
|
||||
{{- range $field := $object.Fields }}
|
||||
case "{{$field.Name}}":
|
||||
{{- if $field.IsConcurrent }}
|
||||
field := field
|
||||
|
||||
innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
}
|
||||
}()
|
||||
res = ec._{{$object.Name}}_{{$field.Name}}(ctx, field{{if not $object.Root}}, obj{{end}})
|
||||
{{- if $field.TypeReference.GQL.NonNull }}
|
||||
if res == graphql.Null {
|
||||
{{- if $object.IsConcurrent }}
|
||||
atomic.AddUint32(&invalids, 1)
|
||||
{{- else }}
|
||||
invalids++
|
||||
{{- end }}
|
||||
}
|
||||
{{- end }}
|
||||
return res
|
||||
}
|
||||
|
||||
{{if $object.Root}}
|
||||
rrm := func(ctx context.Context) graphql.Marshaler {
|
||||
return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc)
|
||||
}
|
||||
{{end}}
|
||||
|
||||
out.Concurrently(i, func() graphql.Marshaler {
|
||||
{{- if $object.Root -}}
|
||||
return rrm(innerCtx)
|
||||
{{- else -}}
|
||||
return innerFunc(ctx)
|
||||
{{end}}
|
||||
})
|
||||
{{- else }}
|
||||
innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
|
||||
return ec._{{$object.Name}}_{{$field.Name}}(ctx, field{{if not $object.Root}}, obj{{end}})
|
||||
}
|
||||
{{if $object.Root}}
|
||||
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, innerFunc)
|
||||
{{else}}
|
||||
out.Values[i] = innerFunc(ctx)
|
||||
{{end}}
|
||||
|
||||
{{- if $field.TypeReference.GQL.NonNull }}
|
||||
if out.Values[i] == graphql.Null {
|
||||
{{- if $object.IsConcurrent }}
|
||||
atomic.AddUint32(&invalids, 1)
|
||||
{{- else }}
|
||||
invalids++
|
||||
{{- end }}
|
||||
}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
default:
|
||||
panic("unknown field " + strconv.Quote(field.Name))
|
||||
}
|
||||
}
|
||||
out.Dispatch()
|
||||
if invalids > 0 { return graphql.Null }
|
||||
|
||||
201
vendor/github.com/99designs/gqlgen/codegen/root_.gotpl
generated
vendored
Normal file
201
vendor/github.com/99designs/gqlgen/codegen/root_.gotpl
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
{{ reserveImport "context" }}
|
||||
{{ reserveImport "fmt" }}
|
||||
{{ reserveImport "io" }}
|
||||
{{ reserveImport "strconv" }}
|
||||
{{ reserveImport "time" }}
|
||||
{{ reserveImport "sync" }}
|
||||
{{ reserveImport "sync/atomic" }}
|
||||
{{ reserveImport "errors" }}
|
||||
{{ reserveImport "bytes" }}
|
||||
|
||||
{{ reserveImport "github.com/vektah/gqlparser/v2" "gqlparser" }}
|
||||
{{ reserveImport "github.com/vektah/gqlparser/v2/ast" }}
|
||||
{{ reserveImport "github.com/99designs/gqlgen/graphql" }}
|
||||
{{ reserveImport "github.com/99designs/gqlgen/graphql/introspection" }}
|
||||
|
||||
// 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 -}}
|
||||
{{ucFirst $object.Name}}() {{ucFirst $object.Name}}Resolver
|
||||
{{ end }}
|
||||
{{- end }}
|
||||
}
|
||||
|
||||
type DirectiveRoot struct {
|
||||
{{ range $directive := .Directives }}
|
||||
{{- $directive.Declaration }}
|
||||
{{ end }}
|
||||
}
|
||||
|
||||
type ComplexityRoot struct {
|
||||
{{ range $object := .Objects }}
|
||||
{{ if not $object.IsReserved -}}
|
||||
{{ ucFirst $object.Name }} struct {
|
||||
{{ range $_, $fields := $object.UniqueFields }}
|
||||
{{- $field := index $fields 0 -}}
|
||||
{{ if not $field.IsReserved -}}
|
||||
{{ $field.GoFieldName }} {{ $field.ComplexitySignature }}
|
||||
{{ end }}
|
||||
{{- end }}
|
||||
}
|
||||
{{- 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) {
|
||||
ec := executionContext{nil, e}
|
||||
_ = ec
|
||||
switch typeName + "." + field {
|
||||
{{ range $object := .Objects }}
|
||||
{{ if not $object.IsReserved }}
|
||||
{{ range $_, $fields := $object.UniqueFields }}
|
||||
{{- $len := len $fields }}
|
||||
{{- range $i, $field := $fields }}
|
||||
{{- $last := eq (add $i 1) $len }}
|
||||
{{- if not $field.IsReserved }}
|
||||
{{- if eq $i 0 }}case {{ end }}"{{$object.Name}}.{{$field.Name}}"{{ if not $last }},{{ else }}:
|
||||
if e.complexity.{{ucFirst $object.Name }}.{{$field.GoFieldName}} == nil {
|
||||
break
|
||||
}
|
||||
{{ if $field.Args }}
|
||||
args, err := ec.{{ $field.ArgsFunc }}(context.TODO(),rawArgs)
|
||||
if err != nil {
|
||||
return 0, false
|
||||
}
|
||||
{{ end }}
|
||||
return e.complexity.{{ucFirst $object.Name}}.{{$field.GoFieldName}}(childComplexity{{if $field.Args}}, {{$field.ComplexityArgs}} {{ end }}), true
|
||||
{{ end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
|
||||
rc := graphql.GetOperationContext(ctx)
|
||||
ec := executionContext{rc, e}
|
||||
first := true
|
||||
|
||||
switch rc.Operation.Operation {
|
||||
{{- if .QueryRoot }} case ast.Query:
|
||||
return func(ctx context.Context) *graphql.Response {
|
||||
if !first { return nil }
|
||||
first = false
|
||||
{{ if .Directives.LocationDirectives "QUERY" -}}
|
||||
data := ec._queryMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error){
|
||||
return ec._{{.QueryRoot.Name}}(ctx, rc.Operation.SelectionSet), nil
|
||||
})
|
||||
{{- else -}}
|
||||
data := ec._{{.QueryRoot.Name}}(ctx, rc.Operation.SelectionSet)
|
||||
{{- end }}
|
||||
var buf bytes.Buffer
|
||||
data.MarshalGQL(&buf)
|
||||
|
||||
return &graphql.Response{
|
||||
Data: buf.Bytes(),
|
||||
}
|
||||
}
|
||||
{{ end }}
|
||||
|
||||
{{- if .MutationRoot }} case ast.Mutation:
|
||||
return func(ctx context.Context) *graphql.Response {
|
||||
if !first { return nil }
|
||||
first = false
|
||||
{{ if .Directives.LocationDirectives "MUTATION" -}}
|
||||
data := ec._mutationMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error){
|
||||
return ec._{{.MutationRoot.Name}}(ctx, rc.Operation.SelectionSet), nil
|
||||
})
|
||||
{{- else -}}
|
||||
data := ec._{{.MutationRoot.Name}}(ctx, rc.Operation.SelectionSet)
|
||||
{{- end }}
|
||||
var buf bytes.Buffer
|
||||
data.MarshalGQL(&buf)
|
||||
|
||||
return &graphql.Response{
|
||||
Data: buf.Bytes(),
|
||||
}
|
||||
}
|
||||
{{ end }}
|
||||
|
||||
{{- if .SubscriptionRoot }} case ast.Subscription:
|
||||
{{ if .Directives.LocationDirectives "SUBSCRIPTION" -}}
|
||||
next := ec._subscriptionMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error){
|
||||
return ec._{{.SubscriptionRoot.Name}}(ctx, rc.Operation.SelectionSet),nil
|
||||
})
|
||||
{{- else -}}
|
||||
next := ec._{{.SubscriptionRoot.Name}}(ctx, rc.Operation.SelectionSet)
|
||||
{{- end }}
|
||||
|
||||
var buf bytes.Buffer
|
||||
return func(ctx context.Context) *graphql.Response {
|
||||
buf.Reset()
|
||||
data := next()
|
||||
|
||||
if data == nil {
|
||||
return nil
|
||||
}
|
||||
data.MarshalGQL(&buf)
|
||||
|
||||
return &graphql.Response{
|
||||
Data: buf.Bytes(),
|
||||
}
|
||||
}
|
||||
{{ end }}
|
||||
default:
|
||||
return graphql.OneShot(graphql.ErrorResponse(ctx, "unsupported GraphQL operation"))
|
||||
}
|
||||
}
|
||||
|
||||
type executionContext struct {
|
||||
*graphql.OperationContext
|
||||
*executableSchema
|
||||
}
|
||||
|
||||
func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
|
||||
if ec.DisableIntrospection {
|
||||
return nil, errors.New("introspection disabled")
|
||||
}
|
||||
return introspection.WrapSchema(parsedSchema), nil
|
||||
}
|
||||
|
||||
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
|
||||
if ec.DisableIntrospection {
|
||||
return nil, errors.New("introspection disabled")
|
||||
}
|
||||
return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
|
||||
}
|
||||
|
||||
var sources = []*ast.Source{
|
||||
{{- range $source := .Config.Sources }}
|
||||
{Name: {{$source.Name|quote}}, Input: {{$source.Input|rawQuote}}, BuiltIn: {{$source.BuiltIn}}},
|
||||
{{- end }}
|
||||
}
|
||||
var parsedSchema = gqlparser.MustLoadSchema(sources...)
|
||||
2
vendor/github.com/99designs/gqlgen/codegen/templates/import.go
generated
vendored
2
vendor/github.com/99designs/gqlgen/codegen/templates/import.go
generated
vendored
@@ -105,7 +105,7 @@ func (s *Imports) Lookup(path string) string {
|
||||
for s.findByAlias(alias) != nil {
|
||||
alias = imp.Name + strconv.Itoa(i)
|
||||
i++
|
||||
if i > 10 {
|
||||
if i > 1000 {
|
||||
panic(fmt.Errorf("too many collisions, last attempt was %s", alias))
|
||||
}
|
||||
}
|
||||
|
||||
33
vendor/github.com/99designs/gqlgen/codegen/templates/templates.go
generated
vendored
33
vendor/github.com/99designs/gqlgen/codegen/templates/templates.go
generated
vendored
@@ -18,7 +18,6 @@ import (
|
||||
"github.com/99designs/gqlgen/internal/code"
|
||||
|
||||
"github.com/99designs/gqlgen/internal/imports"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// CurrentImports keeps track of all the import declarations that are needed during the execution of a plugin.
|
||||
@@ -79,7 +78,7 @@ func Render(cfg Options) error {
|
||||
var err error
|
||||
t, err = t.New("template.gotpl").Parse(cfg.Template)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error with provided template")
|
||||
return fmt.Errorf("error with provided template: %w", err)
|
||||
}
|
||||
roots = append(roots, "template.gotpl")
|
||||
} else {
|
||||
@@ -92,6 +91,10 @@ func Render(cfg Options) error {
|
||||
if !strings.HasSuffix(info.Name(), ".gotpl") {
|
||||
return nil
|
||||
}
|
||||
// omit any templates with "_" at the end of their name, which are meant for specific contexts only
|
||||
if strings.HasSuffix(info.Name(), "_.gotpl") {
|
||||
return nil
|
||||
}
|
||||
b, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -99,7 +102,7 @@ func Render(cfg Options) error {
|
||||
|
||||
t, err = t.New(name).Parse(string(b))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, cfg.Filename)
|
||||
return fmt.Errorf("%s: %w", cfg.Filename, err)
|
||||
}
|
||||
|
||||
roots = append(roots, name)
|
||||
@@ -107,7 +110,7 @@ func Render(cfg Options) error {
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "locating templates")
|
||||
return fmt.Errorf("locating templates: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +132,7 @@ func Render(cfg Options) error {
|
||||
}
|
||||
err := t.Lookup(root).Execute(&buf, cfg.Data)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, root)
|
||||
return fmt.Errorf("%s: %w", root, err)
|
||||
}
|
||||
if cfg.RegionTags {
|
||||
buf.WriteString("\n// endregion " + center(70, "*", " "+root+" ") + "\n")
|
||||
@@ -450,18 +453,23 @@ var commonInitialisms = map[string]bool{
|
||||
"ASCII": true,
|
||||
"CPU": true,
|
||||
"CSS": true,
|
||||
"CSV": true,
|
||||
"DNS": true,
|
||||
"EOF": true,
|
||||
"GUID": true,
|
||||
"HTML": true,
|
||||
"HTTP": true,
|
||||
"HTTPS": true,
|
||||
"ICMP": true,
|
||||
"ID": true,
|
||||
"IP": true,
|
||||
"JSON": true,
|
||||
"KVK": true,
|
||||
"LHS": true,
|
||||
"PDF": true,
|
||||
"PGP": true,
|
||||
"QPS": true,
|
||||
"QR": true,
|
||||
"RAM": true,
|
||||
"RHS": true,
|
||||
"RPC": true,
|
||||
@@ -469,16 +477,17 @@ var commonInitialisms = map[string]bool{
|
||||
"SMTP": true,
|
||||
"SQL": true,
|
||||
"SSH": true,
|
||||
"SVG": true,
|
||||
"TCP": true,
|
||||
"TLS": true,
|
||||
"TTL": true,
|
||||
"UDP": true,
|
||||
"UI": true,
|
||||
"UID": true,
|
||||
"UUID": true,
|
||||
"URI": true,
|
||||
"URL": true,
|
||||
"UTF8": true,
|
||||
"UUID": true,
|
||||
"VM": true,
|
||||
"XML": true,
|
||||
"XMPP": true,
|
||||
@@ -487,7 +496,7 @@ var commonInitialisms = map[string]bool{
|
||||
}
|
||||
|
||||
func rawQuote(s string) string {
|
||||
return "`" + strings.Replace(s, "`", "`+\"`\"+`", -1) + "`"
|
||||
return "`" + strings.ReplaceAll(s, "`", "`+\"`\"+`") + "`"
|
||||
}
|
||||
|
||||
func notNil(field string, data interface{}) bool {
|
||||
@@ -549,7 +558,7 @@ func Dump(val interface{}) string {
|
||||
}
|
||||
|
||||
func prefixLines(prefix, s string) string {
|
||||
return prefix + strings.Replace(s, "\n", "\n"+prefix, -1)
|
||||
return prefix + strings.ReplaceAll(s, "\n", "\n"+prefix)
|
||||
}
|
||||
|
||||
func resolveName(name string, skip int) string {
|
||||
@@ -582,9 +591,9 @@ func render(filename string, tpldata interface{}) (*bytes.Buffer, error) {
|
||||
}
|
||||
|
||||
func write(filename string, b []byte, packages *code.Packages) error {
|
||||
err := os.MkdirAll(filepath.Dir(filename), 0755)
|
||||
err := os.MkdirAll(filepath.Dir(filename), 0o755)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create directory")
|
||||
return fmt.Errorf("failed to create directory: %w", err)
|
||||
}
|
||||
|
||||
formatted, err := imports.Prune(filename, b, packages)
|
||||
@@ -593,9 +602,9 @@ func write(filename string, b []byte, packages *code.Packages) error {
|
||||
formatted = b
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(filename, formatted, 0644)
|
||||
err = ioutil.WriteFile(filename, formatted, 0o644)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to write %s", filename)
|
||||
return fmt.Errorf("failed to write %s: %w", filename, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
2
vendor/github.com/99designs/gqlgen/codegen/type.go
generated
vendored
2
vendor/github.com/99designs/gqlgen/codegen/type.go
generated
vendored
@@ -26,7 +26,7 @@ func processType(ret map[string]*config.TypeReference, ref *config.TypeReference
|
||||
}
|
||||
ret[key] = ref
|
||||
|
||||
if ref.IsSlice() {
|
||||
if ref.IsSlice() || ref.IsPtrToSlice() || ref.IsPtrToPtr() {
|
||||
processType(ret, ref.Elem())
|
||||
}
|
||||
}
|
||||
|
||||
111
vendor/github.com/99designs/gqlgen/codegen/type.gotpl
generated
vendored
111
vendor/github.com/99designs/gqlgen/codegen/type.gotpl
generated
vendored
@@ -1,63 +1,84 @@
|
||||
{{- range $type := .ReferencedTypes }}
|
||||
{{ with $type.UnmarshalFunc }}
|
||||
func (ec *executionContext) {{ . }}(ctx context.Context, v interface{}) ({{ $type.GO | ref }}, error) {
|
||||
{{- if and $type.IsNilable (not $type.GQL.NonNull) }}
|
||||
{{- if and $type.IsNilable (not $type.GQL.NonNull) (not $type.IsPtrToPtr) }}
|
||||
if v == nil { return nil, nil }
|
||||
{{- end }}
|
||||
{{- if $type.IsSlice }}
|
||||
{{- if $type.IsPtrToSlice }}
|
||||
res, err := ec.{{ $type.Elem.UnmarshalFunc }}(ctx, v)
|
||||
return &res, graphql.ErrorOnPath(ctx, err)
|
||||
{{- else if $type.IsSlice }}
|
||||
var vSlice []interface{}
|
||||
if v != nil {
|
||||
if tmp1, ok := v.([]interface{}); ok {
|
||||
vSlice = tmp1
|
||||
} else {
|
||||
vSlice = []interface{}{ v }
|
||||
}
|
||||
vSlice = graphql.CoerceList(v)
|
||||
}
|
||||
var err error
|
||||
res := make([]{{$type.GO.Elem | ref}}, len(vSlice))
|
||||
for i := range vSlice {
|
||||
ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithIndex(i))
|
||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i))
|
||||
res[i], err = ec.{{ $type.Elem.UnmarshalFunc }}(ctx, vSlice[i])
|
||||
if err != nil {
|
||||
return nil, graphql.WrapErrorWithInputPath(ctx, err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
{{- else if and $type.IsPtrToPtr (not $type.Unmarshaler) (not $type.IsMarshaler) }}
|
||||
var pres {{ $type.Elem.GO | ref }}
|
||||
if v != nil {
|
||||
res, err := ec.{{ $type.Elem.UnmarshalFunc }}(ctx, v)
|
||||
if err != nil {
|
||||
return nil, graphql.ErrorOnPath(ctx, err)
|
||||
}
|
||||
pres = res
|
||||
}
|
||||
return &pres, nil
|
||||
{{- else }}
|
||||
{{- if $type.Unmarshaler }}
|
||||
{{- if $type.CastType }}
|
||||
tmp, err := {{ $type.Unmarshaler | call }}(v)
|
||||
{{- if $type.IsNilable }}
|
||||
{{- if $type.IsContext }}
|
||||
tmp, err := {{ $type.Unmarshaler | call }}(ctx, v)
|
||||
{{- else }}
|
||||
tmp, err := {{ $type.Unmarshaler | call }}(v)
|
||||
{{- end }}
|
||||
{{- if and $type.IsNilable $type.Elem }}
|
||||
res := {{ $type.Elem.GO | ref }}(tmp)
|
||||
{{- else}}
|
||||
res := {{ $type.GO | ref }}(tmp)
|
||||
{{- end }}
|
||||
{{- else}}
|
||||
res, err := {{ $type.Unmarshaler | call }}(v)
|
||||
{{- if $type.IsContext }}
|
||||
res, err := {{ $type.Unmarshaler | call }}(ctx, v)
|
||||
{{- else }}
|
||||
res, err := {{ $type.Unmarshaler | call }}(v)
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if and $type.IsTargetNilable (not $type.IsNilable) }}
|
||||
return *res, graphql.WrapErrorWithInputPath(ctx, err)
|
||||
return *res, graphql.ErrorOnPath(ctx, err)
|
||||
{{- else if and (not $type.IsTargetNilable) $type.IsNilable }}
|
||||
return &res, graphql.WrapErrorWithInputPath(ctx, err)
|
||||
return &res, graphql.ErrorOnPath(ctx, err)
|
||||
{{- else}}
|
||||
return res, graphql.WrapErrorWithInputPath(ctx, err)
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
{{- end }}
|
||||
{{- else if eq ($type.GO | ref) "map[string]interface{}" }}
|
||||
return v.(map[string]interface{}), nil
|
||||
{{- else if $type.IsMarshaler }}
|
||||
{{- if $type.IsNilable }}
|
||||
{{- if and $type.IsNilable $type.Elem }}
|
||||
var res = new({{ $type.Elem.GO | ref }})
|
||||
{{- else}}
|
||||
var res {{ $type.GO | ref }}
|
||||
{{- end }}
|
||||
err := res.UnmarshalGQL(v)
|
||||
return res, graphql.WrapErrorWithInputPath(ctx, err)
|
||||
{{- if $type.IsContext }}
|
||||
err := res.UnmarshalGQLContext(ctx, v)
|
||||
{{- else }}
|
||||
err := res.UnmarshalGQL(v)
|
||||
{{- end }}
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
{{- else }}
|
||||
res, err := ec.unmarshalInput{{ $type.GQL.Name }}(ctx, v)
|
||||
{{- if $type.IsNilable }}
|
||||
return &res, graphql.WrapErrorWithInputPath(ctx, err)
|
||||
return &res, graphql.ErrorOnPath(ctx, err)
|
||||
{{- else}}
|
||||
return res, graphql.WrapErrorWithInputPath(ctx, err)
|
||||
return res, graphql.ErrorOnPath(ctx, err)
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -66,7 +87,9 @@
|
||||
|
||||
{{ with $type.MarshalFunc }}
|
||||
func (ec *executionContext) {{ . }}(ctx context.Context, sel ast.SelectionSet, v {{ $type.GO | ref }}) graphql.Marshaler {
|
||||
{{- if $type.IsSlice }}
|
||||
{{- if $type.IsPtrToSlice }}
|
||||
return ec.{{ $type.Elem.MarshalFunc }}(ctx, sel, *v)
|
||||
{{- else if $type.IsSlice }}
|
||||
{{- if not $type.GQL.NonNull }}
|
||||
if v == nil {
|
||||
return graphql.Null
|
||||
@@ -90,11 +113,11 @@
|
||||
ctx := graphql.WithFieldContext(ctx, fc)
|
||||
f := func(i int) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = nil
|
||||
}
|
||||
}()
|
||||
if r := recover(); r != nil {
|
||||
ec.Error(ctx, ec.Recover(ctx, r))
|
||||
ret = nil
|
||||
}
|
||||
}()
|
||||
if !isLen1 {
|
||||
defer wg.Done()
|
||||
}
|
||||
@@ -107,10 +130,22 @@
|
||||
}
|
||||
{{ else }}
|
||||
ret[i] = ec.{{ $type.Elem.MarshalFunc }}(ctx, sel, v[i])
|
||||
{{- end}}
|
||||
{{- end }}
|
||||
}
|
||||
{{ if not $type.IsScalar }} wg.Wait() {{ end }}
|
||||
{{ if $type.Elem.GQL.NonNull }}
|
||||
for _, e := range ret {
|
||||
if e == graphql.Null {
|
||||
return graphql.Null
|
||||
}
|
||||
}
|
||||
{{ end }}
|
||||
return ret
|
||||
{{- else if and $type.IsPtrToPtr (not $type.Unmarshaler) (not $type.IsMarshaler) }}
|
||||
if v == nil {
|
||||
return graphql.Null
|
||||
}
|
||||
return ec.{{ $type.Elem.MarshalFunc }}(ctx, sel, *v)
|
||||
{{- else }}
|
||||
{{- if $type.IsNilable }}
|
||||
if v == nil {
|
||||
@@ -123,7 +158,11 @@
|
||||
}
|
||||
{{- end }}
|
||||
{{- if $type.IsMarshaler }}
|
||||
return v
|
||||
{{- if $type.IsContext }}
|
||||
return graphql.WrapContextMarshaler(ctx, v)
|
||||
{{- else }}
|
||||
return v
|
||||
{{- end }}
|
||||
{{- else if $type.Marshaler }}
|
||||
{{- $v := "v" }}
|
||||
{{- if and $type.IsTargetNilable (not $type.IsNilable) }}
|
||||
@@ -131,16 +170,18 @@
|
||||
{{- else if and (not $type.IsTargetNilable) $type.IsNilable }}
|
||||
{{- $v = "*v" }}
|
||||
{{- end }}
|
||||
res := {{ $type.Marshaler | call }}({{- if $type.CastType }}{{ $type.CastType | ref }}({{ $v }}){{else}}{{ $v }}{{- end }})
|
||||
{{- if $type.GQL.NonNull }}
|
||||
res := {{ $type.Marshaler | call }}({{- if $type.CastType }}{{ $type.CastType | ref }}({{ $v }}){{else}}{{ $v }}{{- end }})
|
||||
if res == graphql.Null {
|
||||
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
if res == graphql.Null {
|
||||
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
||||
ec.Errorf(ctx, "must not be null")
|
||||
}
|
||||
return res
|
||||
}
|
||||
{{- end }}
|
||||
{{- if $type.IsContext }}
|
||||
return graphql.WrapContextMarshaler(ctx, res)
|
||||
{{- else }}
|
||||
return {{ $type.Marshaler | call }}({{- if $type.CastType }}{{ $type.CastType | ref }}({{ $v }}){{else}}{{ $v }}{{- end }})
|
||||
return res
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
return ec._{{$type.Definition.Name}}(ctx, sel, {{ if not $type.IsNilable}}&{{end}} v)
|
||||
|
||||
11
vendor/github.com/99designs/gqlgen/codegen/util.go
generated
vendored
11
vendor/github.com/99designs/gqlgen/codegen/util.go
generated
vendored
@@ -1,10 +1,9 @@
|
||||
package codegen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/types"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func findGoNamedType(def types.Type) (*types.Named, error) {
|
||||
@@ -14,7 +13,7 @@ func findGoNamedType(def types.Type) (*types.Named, error) {
|
||||
|
||||
namedType, ok := def.(*types.Named)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("expected %s to be a named type, instead found %T\n", def.String(), def)
|
||||
return nil, fmt.Errorf("expected %s to be a named type, instead found %T\n", def.String(), def)
|
||||
}
|
||||
|
||||
return namedType, nil
|
||||
@@ -34,14 +33,14 @@ func findGoInterface(def types.Type) (*types.Interface, error) {
|
||||
|
||||
underlying, ok := namedType.Underlying().(*types.Interface)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("expected %s to be a named interface, instead found %s", def.String(), namedType.String())
|
||||
return nil, fmt.Errorf("expected %s to be a named interface, instead found %s", def.String(), namedType.String())
|
||||
}
|
||||
|
||||
return underlying, nil
|
||||
}
|
||||
|
||||
func equalFieldName(source, target string) bool {
|
||||
source = strings.Replace(source, "_", "", -1)
|
||||
target = strings.Replace(target, "_", "", -1)
|
||||
source = strings.ReplaceAll(source, "_", "")
|
||||
target = strings.ReplaceAll(target, "_", "")
|
||||
return strings.EqualFold(source, target)
|
||||
}
|
||||
|
||||
5
vendor/github.com/99designs/gqlgen/complexity/complexity.go
generated
vendored
5
vendor/github.com/99designs/gqlgen/complexity/complexity.go
generated
vendored
@@ -26,6 +26,11 @@ func (cw complexityWalker) selectionSetComplexity(selectionSet ast.SelectionSet)
|
||||
switch s := selection.(type) {
|
||||
case *ast.Field:
|
||||
fieldDefinition := cw.schema.Types[s.Definition.Type.Name()]
|
||||
|
||||
if fieldDefinition.Name == "__Schema" {
|
||||
continue
|
||||
}
|
||||
|
||||
var childComplexity int
|
||||
switch fieldDefinition.Kind {
|
||||
case ast.Object, ast.Interface, ast.Union:
|
||||
|
||||
11
vendor/github.com/99designs/gqlgen/graphql/bool.go
generated
vendored
11
vendor/github.com/99designs/gqlgen/graphql/bool.go
generated
vendored
@@ -7,13 +7,10 @@ import (
|
||||
)
|
||||
|
||||
func MarshalBoolean(b bool) Marshaler {
|
||||
return WriterFunc(func(w io.Writer) {
|
||||
if b {
|
||||
w.Write(trueLit)
|
||||
} else {
|
||||
w.Write(falseLit)
|
||||
}
|
||||
})
|
||||
if b {
|
||||
return WriterFunc(func(w io.Writer) { w.Write(trueLit) })
|
||||
}
|
||||
return WriterFunc(func(w io.Writer) { w.Write(falseLit) })
|
||||
}
|
||||
|
||||
func UnmarshalBoolean(v interface{}) (bool, error) {
|
||||
|
||||
56
vendor/github.com/99designs/gqlgen/graphql/coercion.go
generated
vendored
Normal file
56
vendor/github.com/99designs/gqlgen/graphql/coercion.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
package graphql
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// CoerceList applies coercion from a single value to a list.
|
||||
func CoerceList(v interface{}) []interface{} {
|
||||
var vSlice []interface{}
|
||||
if v != nil {
|
||||
switch v := v.(type) {
|
||||
case []interface{}:
|
||||
// already a slice no coercion required
|
||||
vSlice = v
|
||||
case []string:
|
||||
if len(v) > 0 {
|
||||
vSlice = []interface{}{v[0]}
|
||||
}
|
||||
case []json.Number:
|
||||
if len(v) > 0 {
|
||||
vSlice = []interface{}{v[0]}
|
||||
}
|
||||
case []bool:
|
||||
if len(v) > 0 {
|
||||
vSlice = []interface{}{v[0]}
|
||||
}
|
||||
case []map[string]interface{}:
|
||||
if len(v) > 0 {
|
||||
vSlice = []interface{}{v[0]}
|
||||
}
|
||||
case []float64:
|
||||
if len(v) > 0 {
|
||||
vSlice = []interface{}{v[0]}
|
||||
}
|
||||
case []float32:
|
||||
if len(v) > 0 {
|
||||
vSlice = []interface{}{v[0]}
|
||||
}
|
||||
case []int:
|
||||
if len(v) > 0 {
|
||||
vSlice = []interface{}{v[0]}
|
||||
}
|
||||
case []int32:
|
||||
if len(v) > 0 {
|
||||
vSlice = []interface{}{v[0]}
|
||||
}
|
||||
case []int64:
|
||||
if len(v) > 0 {
|
||||
vSlice = []interface{}{v[0]}
|
||||
}
|
||||
default:
|
||||
vSlice = []interface{}{v}
|
||||
}
|
||||
}
|
||||
return vSlice
|
||||
}
|
||||
2
vendor/github.com/99designs/gqlgen/graphql/context_field.go
generated
vendored
2
vendor/github.com/99designs/gqlgen/graphql/context_field.go
generated
vendored
@@ -28,6 +28,8 @@ type FieldContext struct {
|
||||
Result interface{}
|
||||
// IsMethod indicates if the resolver is a method
|
||||
IsMethod bool
|
||||
// IsResolver indicates if the field has a user-specified resolver
|
||||
IsResolver bool
|
||||
}
|
||||
|
||||
type FieldStats struct {
|
||||
|
||||
85
vendor/github.com/99designs/gqlgen/graphql/context_field_input.go
generated
vendored
85
vendor/github.com/99designs/gqlgen/graphql/context_field_input.go
generated
vendored
@@ -1,85 +0,0 @@
|
||||
package graphql
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
const fieldInputCtx key = "field_input_context"
|
||||
|
||||
type FieldInputContext struct {
|
||||
ParentField *FieldContext
|
||||
ParentInput *FieldInputContext
|
||||
Field *string
|
||||
Index *int
|
||||
}
|
||||
|
||||
func (fic *FieldInputContext) Path() ast.Path {
|
||||
var inputPath ast.Path
|
||||
for it := fic; it != nil; it = it.ParentInput {
|
||||
if it.Index != nil {
|
||||
inputPath = append(inputPath, ast.PathIndex(*it.Index))
|
||||
} else if it.Field != nil {
|
||||
inputPath = append(inputPath, ast.PathName(*it.Field))
|
||||
}
|
||||
}
|
||||
|
||||
// because we are walking up the chain, all the elements are backwards, do an inplace flip.
|
||||
for i := len(inputPath)/2 - 1; i >= 0; i-- {
|
||||
opp := len(inputPath) - 1 - i
|
||||
inputPath[i], inputPath[opp] = inputPath[opp], inputPath[i]
|
||||
}
|
||||
|
||||
if fic.ParentField != nil {
|
||||
fieldPath := fic.ParentField.Path()
|
||||
return append(fieldPath, inputPath...)
|
||||
|
||||
}
|
||||
|
||||
return inputPath
|
||||
}
|
||||
|
||||
func NewFieldInputWithField(field string) *FieldInputContext {
|
||||
return &FieldInputContext{Field: &field}
|
||||
}
|
||||
|
||||
func NewFieldInputWithIndex(index int) *FieldInputContext {
|
||||
return &FieldInputContext{Index: &index}
|
||||
}
|
||||
|
||||
func WithFieldInputContext(ctx context.Context, fic *FieldInputContext) context.Context {
|
||||
if fieldContext := GetFieldContext(ctx); fieldContext != nil {
|
||||
fic.ParentField = fieldContext
|
||||
}
|
||||
if fieldInputContext := GetFieldInputContext(ctx); fieldInputContext != nil {
|
||||
fic.ParentInput = fieldInputContext
|
||||
}
|
||||
|
||||
return context.WithValue(ctx, fieldInputCtx, fic)
|
||||
}
|
||||
|
||||
func GetFieldInputContext(ctx context.Context) *FieldInputContext {
|
||||
if val, ok := ctx.Value(fieldInputCtx).(*FieldInputContext); ok {
|
||||
return val
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func WrapErrorWithInputPath(ctx context.Context, err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
inputContext := GetFieldInputContext(ctx)
|
||||
path := inputContext.Path()
|
||||
if gerr, ok := err.(*gqlerror.Error); ok {
|
||||
if gerr.Path == nil {
|
||||
gerr.Path = path
|
||||
}
|
||||
return gerr
|
||||
} else {
|
||||
return gqlerror.WrapPath(path, err)
|
||||
}
|
||||
}
|
||||
20
vendor/github.com/99designs/gqlgen/graphql/context_operation.go
generated
vendored
20
vendor/github.com/99designs/gqlgen/graphql/context_operation.go
generated
vendored
@@ -16,10 +16,11 @@ type OperationContext struct {
|
||||
OperationName string
|
||||
Doc *ast.QueryDocument
|
||||
|
||||
Operation *ast.OperationDefinition
|
||||
DisableIntrospection bool
|
||||
Recover RecoverFunc
|
||||
ResolverMiddleware FieldMiddleware
|
||||
Operation *ast.OperationDefinition
|
||||
DisableIntrospection bool
|
||||
RecoverFunc RecoverFunc
|
||||
ResolverMiddleware FieldMiddleware
|
||||
RootResolverMiddleware RootFieldMiddleware
|
||||
|
||||
Stats Stats
|
||||
}
|
||||
@@ -37,8 +38,11 @@ func (c *OperationContext) Validate(ctx context.Context) error {
|
||||
if c.ResolverMiddleware == nil {
|
||||
return errors.New("field 'ResolverMiddleware' is required")
|
||||
}
|
||||
if c.Recover == nil {
|
||||
c.Recover = DefaultRecover
|
||||
if c.RootResolverMiddleware == nil {
|
||||
return errors.New("field 'RootResolverMiddleware' is required")
|
||||
}
|
||||
if c.RecoverFunc == nil {
|
||||
c.RecoverFunc = DefaultRecover
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -105,3 +109,7 @@ func (c *OperationContext) Errorf(ctx context.Context, format string, args ...in
|
||||
func (c *OperationContext) Error(ctx context.Context, err error) {
|
||||
AddError(ctx, err)
|
||||
}
|
||||
|
||||
func (c *OperationContext) Recover(ctx context.Context, err interface{}) error {
|
||||
return ErrorOnPath(ctx, c.RecoverFunc(ctx, err))
|
||||
}
|
||||
|
||||
77
vendor/github.com/99designs/gqlgen/graphql/context_path.go
generated
vendored
Normal file
77
vendor/github.com/99designs/gqlgen/graphql/context_path.go
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
package graphql
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
)
|
||||
|
||||
const fieldInputCtx key = "path_context"
|
||||
|
||||
type PathContext struct {
|
||||
ParentField *FieldContext
|
||||
Parent *PathContext
|
||||
Field *string
|
||||
Index *int
|
||||
}
|
||||
|
||||
func (fic *PathContext) Path() ast.Path {
|
||||
var path ast.Path
|
||||
for it := fic; it != nil; it = it.Parent {
|
||||
if it.Index != nil {
|
||||
path = append(path, ast.PathIndex(*it.Index))
|
||||
} else if it.Field != nil {
|
||||
path = append(path, ast.PathName(*it.Field))
|
||||
}
|
||||
}
|
||||
|
||||
// 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]
|
||||
}
|
||||
|
||||
if fic.ParentField != nil {
|
||||
fieldPath := fic.ParentField.Path()
|
||||
return append(fieldPath, path...)
|
||||
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
func NewPathWithField(field string) *PathContext {
|
||||
return &PathContext{Field: &field}
|
||||
}
|
||||
|
||||
func NewPathWithIndex(index int) *PathContext {
|
||||
return &PathContext{Index: &index}
|
||||
}
|
||||
|
||||
func WithPathContext(ctx context.Context, fic *PathContext) context.Context {
|
||||
if fieldContext := GetFieldContext(ctx); fieldContext != nil {
|
||||
fic.ParentField = fieldContext
|
||||
}
|
||||
if fieldInputContext := GetPathContext(ctx); fieldInputContext != nil {
|
||||
fic.Parent = fieldInputContext
|
||||
}
|
||||
|
||||
return context.WithValue(ctx, fieldInputCtx, fic)
|
||||
}
|
||||
|
||||
func GetPathContext(ctx context.Context) *PathContext {
|
||||
if val, ok := ctx.Value(fieldInputCtx).(*PathContext); ok {
|
||||
return val
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetPath(ctx context.Context) ast.Path {
|
||||
if pc := GetPathContext(ctx); pc != nil {
|
||||
return pc.Path()
|
||||
}
|
||||
if fc := GetFieldContext(ctx); fc != nil {
|
||||
return fc.Path()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
14
vendor/github.com/99designs/gqlgen/graphql/context_response.go
generated
vendored
14
vendor/github.com/99designs/gqlgen/graphql/context_response.go
generated
vendored
@@ -38,27 +38,23 @@ func WithResponseContext(ctx context.Context, presenterFunc ErrorPresenterFunc,
|
||||
|
||||
// AddErrorf writes a formatted error to the client, first passing it through the error presenter.
|
||||
func AddErrorf(ctx context.Context, format string, args ...interface{}) {
|
||||
c := getResponseContext(ctx)
|
||||
|
||||
c.errorsMu.Lock()
|
||||
defer c.errorsMu.Unlock()
|
||||
|
||||
c.errors = append(c.errors, c.errorPresenter(ctx, fmt.Errorf(format, args...)))
|
||||
AddError(ctx, fmt.Errorf(format, args...))
|
||||
}
|
||||
|
||||
// AddError sends an error to the client, first passing it through the error presenter.
|
||||
func AddError(ctx context.Context, err error) {
|
||||
c := getResponseContext(ctx)
|
||||
|
||||
presentedError := c.errorPresenter(ctx, ErrorOnPath(ctx, err))
|
||||
|
||||
c.errorsMu.Lock()
|
||||
defer c.errorsMu.Unlock()
|
||||
|
||||
c.errors = append(c.errors, c.errorPresenter(ctx, err))
|
||||
c.errors = append(c.errors, presentedError)
|
||||
}
|
||||
|
||||
func Recover(ctx context.Context, err interface{}) (userMessage error) {
|
||||
c := getResponseContext(ctx)
|
||||
return c.recover(ctx, err)
|
||||
return ErrorOnPath(ctx, c.recover(ctx, err))
|
||||
}
|
||||
|
||||
// HasFieldError returns true if the given field has already errored
|
||||
|
||||
25
vendor/github.com/99designs/gqlgen/graphql/context_root_field.go
generated
vendored
Normal file
25
vendor/github.com/99designs/gqlgen/graphql/context_root_field.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
package graphql
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
const rootResolverCtx key = "root_resolver_context"
|
||||
|
||||
type RootFieldContext struct {
|
||||
// The name of the type this field belongs to
|
||||
Object string
|
||||
// The raw field
|
||||
Field CollectedField
|
||||
}
|
||||
|
||||
func GetRootFieldContext(ctx context.Context) *RootFieldContext {
|
||||
if val, ok := ctx.Value(rootResolverCtx).(*RootFieldContext); ok {
|
||||
return val
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func WithRootFieldContext(ctx context.Context, rc *RootFieldContext) context.Context {
|
||||
return context.WithValue(ctx, rootResolverCtx, rc)
|
||||
}
|
||||
6
vendor/github.com/99designs/gqlgen/graphql/errcode/codes.go
generated
vendored
6
vendor/github.com/99designs/gqlgen/graphql/errcode/codes.go
generated
vendored
@@ -4,8 +4,10 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
const ValidationFailed = "GRAPHQL_VALIDATION_FAILED"
|
||||
const ParseFailed = "GRAPHQL_PARSE_FAILED"
|
||||
const (
|
||||
ValidationFailed = "GRAPHQL_VALIDATION_FAILED"
|
||||
ParseFailed = "GRAPHQL_PARSE_FAILED"
|
||||
)
|
||||
|
||||
type ErrorKind int
|
||||
|
||||
|
||||
39
vendor/github.com/99designs/gqlgen/graphql/error.go
generated
vendored
39
vendor/github.com/99designs/gqlgen/graphql/error.go
generated
vendored
@@ -2,32 +2,31 @@ package graphql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
type ErrorPresenterFunc func(ctx context.Context, err 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 {
|
||||
if gqlerr.Path == nil {
|
||||
gqlerr.Path = GetFieldContext(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: GetFieldContext(ctx).Path(),
|
||||
Extensions: extensions,
|
||||
var gqlErr *gqlerror.Error
|
||||
if errors.As(err, &gqlErr) {
|
||||
return gqlErr
|
||||
}
|
||||
return gqlerror.WrapPath(GetPath(ctx), err)
|
||||
}
|
||||
|
||||
func ErrorOnPath(ctx context.Context, err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
var gqlErr *gqlerror.Error
|
||||
if errors.As(err, &gqlErr) {
|
||||
if gqlErr.Path == nil {
|
||||
gqlErr.Path = GetPath(ctx)
|
||||
}
|
||||
return gqlErr
|
||||
}
|
||||
return gqlerror.WrapPath(GetPath(ctx), err)
|
||||
}
|
||||
|
||||
30
vendor/github.com/99designs/gqlgen/graphql/executable_schema.go
generated
vendored
30
vendor/github.com/99designs/gqlgen/graphql/executable_schema.go
generated
vendored
@@ -32,11 +32,12 @@ func collectFields(reqCtx *OperationContext, selSet ast.SelectionSet, satisfies
|
||||
if !shouldIncludeNode(sel.Directives, reqCtx.Variables) {
|
||||
continue
|
||||
}
|
||||
f := getOrCreateAndAppendField(&groupedFields, sel.Alias, sel.ObjectDefinition, func() CollectedField {
|
||||
f := getOrCreateAndAppendField(&groupedFields, sel.Name, sel.Alias, sel.ObjectDefinition, func() CollectedField {
|
||||
return CollectedField{Field: sel}
|
||||
})
|
||||
|
||||
f.Selections = append(f.Selections, sel.SelectionSet...)
|
||||
|
||||
case *ast.InlineFragment:
|
||||
if !shouldIncludeNode(sel.Directives, reqCtx.Variables) {
|
||||
continue
|
||||
@@ -45,7 +46,7 @@ func collectFields(reqCtx *OperationContext, selSet ast.SelectionSet, satisfies
|
||||
continue
|
||||
}
|
||||
for _, childField := range collectFields(reqCtx, sel.SelectionSet, satisfies, visited) {
|
||||
f := getOrCreateAndAppendField(&groupedFields, childField.Name, childField.ObjectDefinition, func() CollectedField { return childField })
|
||||
f := getOrCreateAndAppendField(&groupedFields, childField.Name, childField.Alias, childField.ObjectDefinition, func() CollectedField { return childField })
|
||||
f.Selections = append(f.Selections, childField.Selections...)
|
||||
}
|
||||
|
||||
@@ -70,9 +71,10 @@ func collectFields(reqCtx *OperationContext, selSet ast.SelectionSet, satisfies
|
||||
}
|
||||
|
||||
for _, childField := range collectFields(reqCtx, fragment.SelectionSet, satisfies, visited) {
|
||||
f := getOrCreateAndAppendField(&groupedFields, childField.Name, childField.ObjectDefinition, func() CollectedField { return childField })
|
||||
f := getOrCreateAndAppendField(&groupedFields, childField.Name, childField.Alias, childField.ObjectDefinition, func() CollectedField { return childField })
|
||||
f.Selections = append(f.Selections, childField.Selections...)
|
||||
}
|
||||
|
||||
default:
|
||||
panic(fmt.Errorf("unsupported %T", sel))
|
||||
}
|
||||
@@ -96,10 +98,26 @@ func instanceOf(val string, satisfies []string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func getOrCreateAndAppendField(c *[]CollectedField, name string, objectDefinition *ast.Definition, creator func() CollectedField) *CollectedField {
|
||||
func getOrCreateAndAppendField(c *[]CollectedField, name string, alias string, objectDefinition *ast.Definition, creator func() CollectedField) *CollectedField {
|
||||
for i, cf := range *c {
|
||||
if cf.Alias == name && (cf.ObjectDefinition == objectDefinition || (cf.ObjectDefinition != nil && objectDefinition != nil && cf.ObjectDefinition.Name == objectDefinition.Name)) {
|
||||
return &(*c)[i]
|
||||
if cf.Name == name && cf.Alias == alias {
|
||||
if cf.ObjectDefinition == objectDefinition {
|
||||
return &(*c)[i]
|
||||
}
|
||||
|
||||
if cf.ObjectDefinition == nil || objectDefinition == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if cf.ObjectDefinition.Name == objectDefinition.Name {
|
||||
return &(*c)[i]
|
||||
}
|
||||
|
||||
for _, ifc := range objectDefinition.Interfaces {
|
||||
if ifc == cf.ObjectDefinition.Name {
|
||||
return &(*c)[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
65
vendor/github.com/99designs/gqlgen/graphql/executable_schema_mock.go
generated
vendored
65
vendor/github.com/99designs/gqlgen/graphql/executable_schema_mock.go
generated
vendored
@@ -9,37 +9,31 @@ import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
lockExecutableSchemaMockComplexity sync.RWMutex
|
||||
lockExecutableSchemaMockExec sync.RWMutex
|
||||
lockExecutableSchemaMockSchema sync.RWMutex
|
||||
)
|
||||
|
||||
// Ensure, that ExecutableSchemaMock does implement ExecutableSchema.
|
||||
// If this is not the case, regenerate this file with moq.
|
||||
var _ ExecutableSchema = &ExecutableSchemaMock{}
|
||||
|
||||
// ExecutableSchemaMock is a mock implementation of ExecutableSchema.
|
||||
//
|
||||
// func TestSomethingThatUsesExecutableSchema(t *testing.T) {
|
||||
// func TestSomethingThatUsesExecutableSchema(t *testing.T) {
|
||||
//
|
||||
// // make and configure a mocked ExecutableSchema
|
||||
// mockedExecutableSchema := &ExecutableSchemaMock{
|
||||
// ComplexityFunc: func(typeName string, fieldName string, childComplexity int, args map[string]interface{}) (int, bool) {
|
||||
// panic("mock out the Complexity method")
|
||||
// },
|
||||
// ExecFunc: func(ctx context.Context) ResponseHandler {
|
||||
// panic("mock out the Exec method")
|
||||
// },
|
||||
// SchemaFunc: func() *ast.Schema {
|
||||
// panic("mock out the Schema method")
|
||||
// },
|
||||
// }
|
||||
// // make and configure a mocked ExecutableSchema
|
||||
// mockedExecutableSchema := &ExecutableSchemaMock{
|
||||
// ComplexityFunc: func(typeName string, fieldName string, childComplexity int, args map[string]interface{}) (int, bool) {
|
||||
// panic("mock out the Complexity method")
|
||||
// },
|
||||
// ExecFunc: func(ctx context.Context) ResponseHandler {
|
||||
// panic("mock out the Exec method")
|
||||
// },
|
||||
// SchemaFunc: func() *ast.Schema {
|
||||
// panic("mock out the Schema method")
|
||||
// },
|
||||
// }
|
||||
//
|
||||
// // use mockedExecutableSchema in code that requires ExecutableSchema
|
||||
// // and then make assertions.
|
||||
// // use mockedExecutableSchema in code that requires ExecutableSchema
|
||||
// // and then make assertions.
|
||||
//
|
||||
// }
|
||||
// }
|
||||
type ExecutableSchemaMock struct {
|
||||
// ComplexityFunc mocks the Complexity method.
|
||||
ComplexityFunc func(typeName string, fieldName string, childComplexity int, args map[string]interface{}) (int, bool)
|
||||
@@ -72,6 +66,9 @@ type ExecutableSchemaMock struct {
|
||||
Schema []struct {
|
||||
}
|
||||
}
|
||||
lockComplexity sync.RWMutex
|
||||
lockExec sync.RWMutex
|
||||
lockSchema sync.RWMutex
|
||||
}
|
||||
|
||||
// Complexity calls ComplexityFunc.
|
||||
@@ -90,9 +87,9 @@ func (mock *ExecutableSchemaMock) Complexity(typeName string, fieldName string,
|
||||
ChildComplexity: childComplexity,
|
||||
Args: args,
|
||||
}
|
||||
lockExecutableSchemaMockComplexity.Lock()
|
||||
mock.lockComplexity.Lock()
|
||||
mock.calls.Complexity = append(mock.calls.Complexity, callInfo)
|
||||
lockExecutableSchemaMockComplexity.Unlock()
|
||||
mock.lockComplexity.Unlock()
|
||||
return mock.ComplexityFunc(typeName, fieldName, childComplexity, args)
|
||||
}
|
||||
|
||||
@@ -111,9 +108,9 @@ func (mock *ExecutableSchemaMock) ComplexityCalls() []struct {
|
||||
ChildComplexity int
|
||||
Args map[string]interface{}
|
||||
}
|
||||
lockExecutableSchemaMockComplexity.RLock()
|
||||
mock.lockComplexity.RLock()
|
||||
calls = mock.calls.Complexity
|
||||
lockExecutableSchemaMockComplexity.RUnlock()
|
||||
mock.lockComplexity.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
@@ -127,9 +124,9 @@ func (mock *ExecutableSchemaMock) Exec(ctx context.Context) ResponseHandler {
|
||||
}{
|
||||
Ctx: ctx,
|
||||
}
|
||||
lockExecutableSchemaMockExec.Lock()
|
||||
mock.lockExec.Lock()
|
||||
mock.calls.Exec = append(mock.calls.Exec, callInfo)
|
||||
lockExecutableSchemaMockExec.Unlock()
|
||||
mock.lockExec.Unlock()
|
||||
return mock.ExecFunc(ctx)
|
||||
}
|
||||
|
||||
@@ -142,9 +139,9 @@ func (mock *ExecutableSchemaMock) ExecCalls() []struct {
|
||||
var calls []struct {
|
||||
Ctx context.Context
|
||||
}
|
||||
lockExecutableSchemaMockExec.RLock()
|
||||
mock.lockExec.RLock()
|
||||
calls = mock.calls.Exec
|
||||
lockExecutableSchemaMockExec.RUnlock()
|
||||
mock.lockExec.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
@@ -155,9 +152,9 @@ func (mock *ExecutableSchemaMock) Schema() *ast.Schema {
|
||||
}
|
||||
callInfo := struct {
|
||||
}{}
|
||||
lockExecutableSchemaMockSchema.Lock()
|
||||
mock.lockSchema.Lock()
|
||||
mock.calls.Schema = append(mock.calls.Schema, callInfo)
|
||||
lockExecutableSchemaMockSchema.Unlock()
|
||||
mock.lockSchema.Unlock()
|
||||
return mock.SchemaFunc()
|
||||
}
|
||||
|
||||
@@ -168,8 +165,8 @@ func (mock *ExecutableSchemaMock) SchemaCalls() []struct {
|
||||
} {
|
||||
var calls []struct {
|
||||
}
|
||||
lockExecutableSchemaMockSchema.RLock()
|
||||
mock.lockSchema.RLock()
|
||||
calls = mock.calls.Schema
|
||||
lockExecutableSchemaMockSchema.RUnlock()
|
||||
mock.lockSchema.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
7
vendor/github.com/99designs/gqlgen/graphql/executor/executor.go
generated
vendored
7
vendor/github.com/99designs/gqlgen/graphql/executor/executor.go
generated
vendored
@@ -39,9 +39,10 @@ func New(es graphql.ExecutableSchema) *Executor {
|
||||
|
||||
func (e *Executor) CreateOperationContext(ctx context.Context, params *graphql.RawParams) (*graphql.OperationContext, gqlerror.List) {
|
||||
rc := &graphql.OperationContext{
|
||||
DisableIntrospection: true,
|
||||
Recover: e.recoverFunc,
|
||||
ResolverMiddleware: e.ext.fieldMiddleware,
|
||||
DisableIntrospection: true,
|
||||
RecoverFunc: e.recoverFunc,
|
||||
ResolverMiddleware: e.ext.fieldMiddleware,
|
||||
RootResolverMiddleware: e.ext.rootFieldMiddleware,
|
||||
Stats: graphql.Stats{
|
||||
Read: params.ReadTime,
|
||||
OperationStart: graphql.GetStartTime(ctx),
|
||||
|
||||
36
vendor/github.com/99designs/gqlgen/graphql/executor/extensions.go
generated
vendored
36
vendor/github.com/99designs/gqlgen/graphql/executor/extensions.go
generated
vendored
@@ -17,6 +17,7 @@ func (e *Executor) Use(extension graphql.HandlerExtension) {
|
||||
case graphql.OperationParameterMutator,
|
||||
graphql.OperationContextMutator,
|
||||
graphql.OperationInterceptor,
|
||||
graphql.RootFieldInterceptor,
|
||||
graphql.FieldInterceptor,
|
||||
graphql.ResponseInterceptor:
|
||||
e.extensions = append(e.extensions, extension)
|
||||
@@ -32,6 +33,11 @@ func (e *Executor) AroundFields(f graphql.FieldMiddleware) {
|
||||
e.Use(aroundFieldFunc(f))
|
||||
}
|
||||
|
||||
// AroundRootFields is a convenience method for creating an extension that only implements root field middleware
|
||||
func (e *Executor) AroundRootFields(f graphql.RootFieldMiddleware) {
|
||||
e.Use(aroundRootFieldFunc(f))
|
||||
}
|
||||
|
||||
// AroundOperations is a convenience method for creating an extension that only implements operation middleware
|
||||
func (e *Executor) AroundOperations(f graphql.OperationMiddleware) {
|
||||
e.Use(aroundOpFunc(f))
|
||||
@@ -45,6 +51,7 @@ func (e *Executor) AroundResponses(f graphql.ResponseMiddleware) {
|
||||
type extensions struct {
|
||||
operationMiddleware graphql.OperationMiddleware
|
||||
responseMiddleware graphql.ResponseMiddleware
|
||||
rootFieldMiddleware graphql.RootFieldMiddleware
|
||||
fieldMiddleware graphql.FieldMiddleware
|
||||
operationParameterMutators []graphql.OperationParameterMutator
|
||||
operationContextMutators []graphql.OperationContextMutator
|
||||
@@ -58,6 +65,9 @@ func processExtensions(exts []graphql.HandlerExtension) extensions {
|
||||
responseMiddleware: func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
|
||||
return next(ctx)
|
||||
},
|
||||
rootFieldMiddleware: func(ctx context.Context, next graphql.RootResolver) graphql.Marshaler {
|
||||
return next(ctx)
|
||||
},
|
||||
fieldMiddleware: func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
|
||||
return next(ctx)
|
||||
},
|
||||
@@ -84,6 +94,15 @@ func processExtensions(exts []graphql.HandlerExtension) extensions {
|
||||
}
|
||||
}
|
||||
|
||||
if p, ok := p.(graphql.RootFieldInterceptor); ok {
|
||||
previous := e.rootFieldMiddleware
|
||||
e.rootFieldMiddleware = func(ctx context.Context, next graphql.RootResolver) graphql.Marshaler {
|
||||
return p.InterceptRootField(ctx, func(ctx context.Context) graphql.Marshaler {
|
||||
return previous(ctx, next)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if p, ok := p.(graphql.FieldInterceptor); ok {
|
||||
previous := e.fieldMiddleware
|
||||
e.fieldMiddleware = func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
|
||||
@@ -157,3 +176,20 @@ func (f aroundFieldFunc) Validate(schema graphql.ExecutableSchema) error {
|
||||
func (f aroundFieldFunc) InterceptField(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
|
||||
return f(ctx, next)
|
||||
}
|
||||
|
||||
type aroundRootFieldFunc func(ctx context.Context, next graphql.RootResolver) graphql.Marshaler
|
||||
|
||||
func (f aroundRootFieldFunc) ExtensionName() string {
|
||||
return "InlineRootFieldFunc"
|
||||
}
|
||||
|
||||
func (f aroundRootFieldFunc) Validate(schema graphql.ExecutableSchema) error {
|
||||
if f == nil {
|
||||
return fmt.Errorf("RootFieldFunc can not be nil")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f aroundRootFieldFunc) InterceptRootField(ctx context.Context, next graphql.RootResolver) graphql.Marshaler {
|
||||
return f(ctx, next)
|
||||
}
|
||||
|
||||
16
vendor/github.com/99designs/gqlgen/graphql/float.go
generated
vendored
16
vendor/github.com/99designs/gqlgen/graphql/float.go
generated
vendored
@@ -1,9 +1,11 @@
|
||||
package graphql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
@@ -29,3 +31,17 @@ func UnmarshalFloat(v interface{}) (float64, error) {
|
||||
return 0, fmt.Errorf("%T is not an float", v)
|
||||
}
|
||||
}
|
||||
|
||||
func MarshalFloatContext(f float64) ContextMarshaler {
|
||||
return ContextWriterFunc(func(ctx context.Context, w io.Writer) error {
|
||||
if math.IsInf(f, 0) || math.IsNaN(f) {
|
||||
return fmt.Errorf("cannot marshal infinite no NaN float values")
|
||||
}
|
||||
io.WriteString(w, fmt.Sprintf("%g", f))
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func UnmarshalFloatContext(ctx context.Context, v interface{}) (float64, error) {
|
||||
return UnmarshalFloat(v)
|
||||
}
|
||||
|
||||
7
vendor/github.com/99designs/gqlgen/graphql/handler.go
generated
vendored
7
vendor/github.com/99designs/gqlgen/graphql/handler.go
generated
vendored
@@ -19,6 +19,9 @@ type (
|
||||
Resolver func(ctx context.Context) (res interface{}, err error)
|
||||
FieldMiddleware func(ctx context.Context, next Resolver) (res interface{}, err error)
|
||||
|
||||
RootResolver func(ctx context.Context) Marshaler
|
||||
RootFieldMiddleware func(ctx context.Context, next RootResolver) Marshaler
|
||||
|
||||
RawParams struct {
|
||||
Query string `json:"query"`
|
||||
OperationName string `json:"operationName"`
|
||||
@@ -76,6 +79,10 @@ type (
|
||||
InterceptResponse(ctx context.Context, next ResponseHandler) *Response
|
||||
}
|
||||
|
||||
RootFieldInterceptor interface {
|
||||
InterceptRootField(ctx context.Context, next RootResolver) Marshaler
|
||||
}
|
||||
|
||||
// FieldInterceptor called around each field
|
||||
FieldInterceptor interface {
|
||||
InterceptField(ctx context.Context, next Resolver) (res interface{}, err error)
|
||||
|
||||
6
vendor/github.com/99designs/gqlgen/graphql/handler/extension/apq.go
generated
vendored
6
vendor/github.com/99designs/gqlgen/graphql/handler/extension/apq.go
generated
vendored
@@ -14,8 +14,10 @@ import (
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
const errPersistedQueryNotFound = "PersistedQueryNotFound"
|
||||
const errPersistedQueryNotFoundCode = "PERSISTED_QUERY_NOT_FOUND"
|
||||
const (
|
||||
errPersistedQueryNotFound = "PersistedQueryNotFound"
|
||||
errPersistedQueryNotFoundCode = "PERSISTED_QUERY_NOT_FOUND"
|
||||
)
|
||||
|
||||
// AutomaticPersistedQuery saves client upload by optimistically sending only the hashes of queries, if the server
|
||||
// does not yet know what the query is for the hash it will respond telling the client to send the query along with the
|
||||
|
||||
5
vendor/github.com/99designs/gqlgen/graphql/handler/server.go
generated
vendored
5
vendor/github.com/99designs/gqlgen/graphql/handler/server.go
generated
vendored
@@ -74,6 +74,11 @@ func (s *Server) AroundFields(f graphql.FieldMiddleware) {
|
||||
s.exec.AroundFields(f)
|
||||
}
|
||||
|
||||
// AroundRootFields is a convenience method for creating an extension that only implements field middleware
|
||||
func (s *Server) AroundRootFields(f graphql.RootFieldMiddleware) {
|
||||
s.exec.AroundRootFields(f)
|
||||
}
|
||||
|
||||
// AroundOperations is a convenience method for creating an extension that only implements operation middleware
|
||||
func (s *Server) AroundOperations(f graphql.OperationMiddleware) {
|
||||
s.exec.AroundOperations(f)
|
||||
|
||||
2
vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_form.go
generated
vendored
2
vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_form.go
generated
vendored
@@ -83,7 +83,7 @@ func (f MultipartForm) Do(w http.ResponseWriter, r *http.Request, exec graphql.G
|
||||
return
|
||||
}
|
||||
|
||||
var uploadsMap = map[string][]string{}
|
||||
uploadsMap := map[string][]string{}
|
||||
if err = json.Unmarshal([]byte(r.Form.Get("map")), &uploadsMap); err != nil {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
writeJsonError(w, "map form field could not be decoded")
|
||||
|
||||
3
vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_post.go
generated
vendored
3
vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_post.go
generated
vendored
@@ -48,7 +48,6 @@ func (h POST) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecu
|
||||
writeJson(w, resp)
|
||||
return
|
||||
}
|
||||
ctx := graphql.WithOperationContext(r.Context(), rc)
|
||||
responses, ctx := exec.DispatchOperation(ctx, rc)
|
||||
responses, ctx := exec.DispatchOperation(r.Context(), rc)
|
||||
writeJson(w, responses(ctx))
|
||||
}
|
||||
|
||||
2
vendor/github.com/99designs/gqlgen/graphql/handler/transport/options.go
generated
vendored
2
vendor/github.com/99designs/gqlgen/graphql/handler/transport/options.go
generated
vendored
@@ -18,8 +18,8 @@ func (o Options) Supports(r *http.Request) bool {
|
||||
func (o Options) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) {
|
||||
switch r.Method {
|
||||
case http.MethodOptions:
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Header().Set("Allow", "OPTIONS, GET, POST")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
case http.MethodHead:
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
}
|
||||
|
||||
265
vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket.go
generated
vendored
265
vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket.go
generated
vendored
@@ -4,8 +4,10 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -16,44 +18,37 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
type (
|
||||
Websocket struct {
|
||||
Upgrader websocket.Upgrader
|
||||
InitFunc WebsocketInitFunc
|
||||
InitTimeout time.Duration
|
||||
ErrorFunc WebsocketErrorFunc
|
||||
KeepAlivePingInterval time.Duration
|
||||
PingPongInterval time.Duration
|
||||
|
||||
didInjectSubprotocols bool
|
||||
}
|
||||
wsConnection struct {
|
||||
Websocket
|
||||
ctx context.Context
|
||||
conn *websocket.Conn
|
||||
me messageExchanger
|
||||
active map[string]context.CancelFunc
|
||||
mu sync.Mutex
|
||||
keepAliveTicker *time.Ticker
|
||||
pingPongTicker *time.Ticker
|
||||
exec graphql.GraphExecutor
|
||||
|
||||
initPayload InitPayload
|
||||
}
|
||||
operationMessage struct {
|
||||
Payload json.RawMessage `json:"payload,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
WebsocketInitFunc func(ctx context.Context, initPayload InitPayload) (context.Context, error)
|
||||
|
||||
WebsocketInitFunc func(ctx context.Context, initPayload InitPayload) (context.Context, error)
|
||||
WebsocketErrorFunc func(ctx context.Context, err error)
|
||||
)
|
||||
|
||||
var errReadTimeout = errors.New("read timeout")
|
||||
|
||||
var _ graphql.Transport = Websocket{}
|
||||
|
||||
func (t Websocket) Supports(r *http.Request) bool {
|
||||
@@ -61,20 +56,34 @@ func (t Websocket) Supports(r *http.Request) bool {
|
||||
}
|
||||
|
||||
func (t Websocket) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) {
|
||||
ws, err := t.Upgrader.Upgrade(w, r, http.Header{
|
||||
"Sec-Websocket-Protocol": []string{"graphql-ws"},
|
||||
})
|
||||
t.injectGraphQLWSSubprotocols()
|
||||
ws, err := t.Upgrader.Upgrade(w, r, http.Header{})
|
||||
if err != nil {
|
||||
log.Printf("unable to upgrade %T to websocket %s: ", w, err.Error())
|
||||
SendErrorf(w, http.StatusBadRequest, "unable to upgrade")
|
||||
return
|
||||
}
|
||||
|
||||
var me messageExchanger
|
||||
switch ws.Subprotocol() {
|
||||
default:
|
||||
msg := websocket.FormatCloseMessage(websocket.CloseProtocolError, fmt.Sprintf("unsupported negotiated subprotocol %s", ws.Subprotocol()))
|
||||
ws.WriteMessage(websocket.CloseMessage, msg)
|
||||
return
|
||||
case graphqlwsSubprotocol, "":
|
||||
// clients are required to send a subprotocol, to be backward compatible with the previous implementation we select
|
||||
// "graphql-ws" by default
|
||||
me = graphqlwsMessageExchanger{c: ws}
|
||||
case graphqltransportwsSubprotocol:
|
||||
me = graphqltransportwsMessageExchanger{c: ws}
|
||||
}
|
||||
|
||||
conn := wsConnection{
|
||||
active: map[string]context.CancelFunc{},
|
||||
conn: ws,
|
||||
ctx: r.Context(),
|
||||
exec: exec,
|
||||
me: me,
|
||||
Websocket: t,
|
||||
}
|
||||
|
||||
@@ -85,18 +94,62 @@ func (t Websocket) Do(w http.ResponseWriter, r *http.Request, exec graphql.Graph
|
||||
conn.run()
|
||||
}
|
||||
|
||||
func (c *wsConnection) handlePossibleError(err error) {
|
||||
if c.ErrorFunc != nil && err != nil {
|
||||
c.ErrorFunc(c.ctx, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *wsConnection) nextMessageWithTimeout(timeout time.Duration) (message, error) {
|
||||
messages, errs := make(chan message, 1), make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
if m, err := c.me.NextMessage(); err != nil {
|
||||
errs <- err
|
||||
} else {
|
||||
messages <- m
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case m := <-messages:
|
||||
return m, nil
|
||||
case err := <-errs:
|
||||
return message{}, err
|
||||
case <-time.After(timeout):
|
||||
return message{}, errReadTimeout
|
||||
}
|
||||
}
|
||||
|
||||
func (c *wsConnection) init() bool {
|
||||
message := c.readOp()
|
||||
if message == nil {
|
||||
var m message
|
||||
var err error
|
||||
|
||||
if c.InitTimeout != 0 {
|
||||
m, err = c.nextMessageWithTimeout(c.InitTimeout)
|
||||
} else {
|
||||
m, err = c.me.NextMessage()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if err == errReadTimeout {
|
||||
c.close(websocket.CloseProtocolError, "connection initialisation timeout")
|
||||
return false
|
||||
}
|
||||
|
||||
if err == errInvalidMsg {
|
||||
c.sendConnectionError("invalid json")
|
||||
}
|
||||
|
||||
c.close(websocket.CloseProtocolError, "decoding error")
|
||||
return false
|
||||
}
|
||||
|
||||
switch message.Type {
|
||||
case connectionInitMsg:
|
||||
if len(message.Payload) > 0 {
|
||||
switch m.t {
|
||||
case initMessageType:
|
||||
if len(m.payload) > 0 {
|
||||
c.initPayload = make(InitPayload)
|
||||
err := json.Unmarshal(message.Payload, &c.initPayload)
|
||||
err := json.Unmarshal(m.payload, &c.initPayload)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@@ -112,13 +165,13 @@ func (c *wsConnection) init() bool {
|
||||
c.ctx = ctx
|
||||
}
|
||||
|
||||
c.write(&operationMessage{Type: connectionAckMsg})
|
||||
c.write(&operationMessage{Type: connectionKeepAliveMsg})
|
||||
case connectionTerminateMsg:
|
||||
c.write(&message{t: connectionAckMessageType})
|
||||
c.write(&message{t: keepAliveMessageType})
|
||||
case connectionCloseMessageType:
|
||||
c.close(websocket.CloseNormalClosure, "terminated")
|
||||
return false
|
||||
default:
|
||||
c.sendConnectionError("unexpected message %s", message.Type)
|
||||
c.sendConnectionError("unexpected message %s", m.t)
|
||||
c.close(websocket.CloseProtocolError, "unexpected message")
|
||||
return false
|
||||
}
|
||||
@@ -126,9 +179,9 @@ func (c *wsConnection) init() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *wsConnection) write(msg *operationMessage) {
|
||||
func (c *wsConnection) write(msg *message) {
|
||||
c.mu.Lock()
|
||||
c.conn.WriteJSON(msg)
|
||||
c.handlePossibleError(c.me.Send(msg))
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
@@ -141,8 +194,9 @@ func (c *wsConnection) run() {
|
||||
c.close(websocket.CloseAbnormalClosure, "unexpected closure")
|
||||
}()
|
||||
|
||||
// Create a timer that will fire every interval to keep the connection alive.
|
||||
if c.KeepAlivePingInterval != 0 {
|
||||
// If we're running in graphql-ws mode, create a timer that will trigger a
|
||||
// keep alive message every interval
|
||||
if (c.conn.Subprotocol() == "" || c.conn.Subprotocol() == graphqlwsSubprotocol) && c.KeepAlivePingInterval != 0 {
|
||||
c.mu.Lock()
|
||||
c.keepAliveTicker = time.NewTicker(c.KeepAlivePingInterval)
|
||||
c.mu.Unlock()
|
||||
@@ -150,28 +204,53 @@ func (c *wsConnection) run() {
|
||||
go c.keepAlive(ctx)
|
||||
}
|
||||
|
||||
// If we're running in graphql-transport-ws mode, create a timer that will
|
||||
// trigger a ping message every interval
|
||||
if c.conn.Subprotocol() == graphqltransportwsSubprotocol && c.PingPongInterval != 0 {
|
||||
c.mu.Lock()
|
||||
c.pingPongTicker = time.NewTicker(c.PingPongInterval)
|
||||
c.mu.Unlock()
|
||||
|
||||
// Note: when the connection is closed by this deadline, the client
|
||||
// will receive an "invalid close code"
|
||||
c.conn.SetReadDeadline(time.Now().UTC().Add(2 * c.PingPongInterval))
|
||||
go c.ping(ctx)
|
||||
}
|
||||
|
||||
// Close the connection when the context is cancelled.
|
||||
// Will optionally send a "close reason" that is retrieved from the context.
|
||||
go c.closeOnCancel(ctx)
|
||||
|
||||
for {
|
||||
start := graphql.Now()
|
||||
message := c.readOp()
|
||||
if message == nil {
|
||||
m, err := c.me.NextMessage()
|
||||
if err != nil {
|
||||
// If the connection got closed by us, don't report the error
|
||||
if !errors.Is(err, net.ErrClosed) {
|
||||
c.handlePossibleError(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
switch message.Type {
|
||||
case startMsg:
|
||||
c.subscribe(start, message)
|
||||
case stopMsg:
|
||||
switch m.t {
|
||||
case startMessageType:
|
||||
c.subscribe(start, &m)
|
||||
case stopMessageType:
|
||||
c.mu.Lock()
|
||||
closer := c.active[message.ID]
|
||||
closer := c.active[m.id]
|
||||
c.mu.Unlock()
|
||||
if closer != nil {
|
||||
closer()
|
||||
}
|
||||
case connectionTerminateMsg:
|
||||
case connectionCloseMessageType:
|
||||
c.close(websocket.CloseNormalClosure, "terminated")
|
||||
return
|
||||
case pingMessageType:
|
||||
c.write(&message{t: pongMessageType, payload: m.payload})
|
||||
case pongMessageType:
|
||||
c.conn.SetReadDeadline(time.Now().UTC().Add(2 * c.PingPongInterval))
|
||||
default:
|
||||
c.sendConnectionError("unexpected message %s", message.Type)
|
||||
c.sendConnectionError("unexpected message %s", m.t)
|
||||
c.close(websocket.CloseProtocolError, "unexpected message")
|
||||
return
|
||||
}
|
||||
@@ -185,17 +264,38 @@ func (c *wsConnection) keepAlive(ctx context.Context) {
|
||||
c.keepAliveTicker.Stop()
|
||||
return
|
||||
case <-c.keepAliveTicker.C:
|
||||
c.write(&operationMessage{Type: connectionKeepAliveMsg})
|
||||
c.write(&message{t: keepAliveMessageType})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *wsConnection) subscribe(start time.Time, message *operationMessage) {
|
||||
func (c *wsConnection) ping(ctx context.Context) {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
c.pingPongTicker.Stop()
|
||||
return
|
||||
case <-c.pingPongTicker.C:
|
||||
c.write(&message{t: pingMessageType, payload: json.RawMessage{}})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *wsConnection) closeOnCancel(ctx context.Context) {
|
||||
<-ctx.Done()
|
||||
|
||||
if r := closeReasonForContext(ctx); r != "" {
|
||||
c.sendConnectionError(r)
|
||||
}
|
||||
c.close(websocket.CloseNormalClosure, "terminated")
|
||||
}
|
||||
|
||||
func (c *wsConnection) subscribe(start time.Time, msg *message) {
|
||||
ctx := graphql.StartOperationTrace(c.ctx)
|
||||
var params *graphql.RawParams
|
||||
if err := jsonDecode(bytes.NewReader(message.Payload), ¶ms); err != nil {
|
||||
c.sendError(message.ID, &gqlerror.Error{Message: "invalid json"})
|
||||
c.complete(message.ID)
|
||||
if err := jsonDecode(bytes.NewReader(msg.payload), ¶ms); err != nil {
|
||||
c.sendError(msg.id, &gqlerror.Error{Message: "invalid json"})
|
||||
c.complete(msg.id)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -209,12 +309,12 @@ func (c *wsConnection) subscribe(start time.Time, message *operationMessage) {
|
||||
resp := c.exec.DispatchError(graphql.WithOperationContext(ctx, rc), err)
|
||||
switch errcode.GetErrorKind(err) {
|
||||
case errcode.KindProtocol:
|
||||
c.sendError(message.ID, resp.Errors...)
|
||||
c.sendError(msg.id, resp.Errors...)
|
||||
default:
|
||||
c.sendResponse(message.ID, &graphql.Response{Errors: err})
|
||||
c.sendResponse(msg.id, &graphql.Response{Errors: err})
|
||||
}
|
||||
|
||||
c.complete(message.ID)
|
||||
c.complete(msg.id)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -226,16 +326,29 @@ func (c *wsConnection) subscribe(start time.Time, message *operationMessage) {
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
c.mu.Lock()
|
||||
c.active[message.ID] = cancel
|
||||
c.active[msg.id] = cancel
|
||||
c.mu.Unlock()
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
userErr := rc.Recover(ctx, r)
|
||||
c.sendError(message.ID, &gqlerror.Error{Message: userErr.Error()})
|
||||
err := rc.Recover(ctx, r)
|
||||
var gqlerr *gqlerror.Error
|
||||
if !errors.As(err, &gqlerr) {
|
||||
gqlerr = &gqlerror.Error{}
|
||||
if err != nil {
|
||||
gqlerr.Message = err.Error()
|
||||
}
|
||||
}
|
||||
c.sendError(msg.id, gqlerr)
|
||||
}
|
||||
c.complete(msg.id)
|
||||
c.mu.Lock()
|
||||
delete(c.active, msg.id)
|
||||
c.mu.Unlock()
|
||||
cancel()
|
||||
}()
|
||||
|
||||
responses, ctx := c.exec.DispatchOperation(ctx, rc)
|
||||
for {
|
||||
response := responses(ctx)
|
||||
@@ -243,12 +356,12 @@ func (c *wsConnection) subscribe(start time.Time, message *operationMessage) {
|
||||
break
|
||||
}
|
||||
|
||||
c.sendResponse(message.ID, response)
|
||||
c.sendResponse(msg.id, response)
|
||||
}
|
||||
c.complete(message.ID)
|
||||
c.complete(msg.id)
|
||||
|
||||
c.mu.Lock()
|
||||
delete(c.active, message.ID)
|
||||
delete(c.active, msg.id)
|
||||
c.mu.Unlock()
|
||||
cancel()
|
||||
}()
|
||||
@@ -259,15 +372,15 @@ func (c *wsConnection) sendResponse(id string, response *graphql.Response) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
c.write(&operationMessage{
|
||||
Payload: b,
|
||||
ID: id,
|
||||
Type: dataMsg,
|
||||
c.write(&message{
|
||||
payload: b,
|
||||
id: id,
|
||||
t: dataMessageType,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *wsConnection) complete(id string) {
|
||||
c.write(&operationMessage{ID: id, Type: completeMsg})
|
||||
c.write(&message{id: id, t: completeMessageType})
|
||||
}
|
||||
|
||||
func (c *wsConnection) sendError(id string, errors ...*gqlerror.Error) {
|
||||
@@ -279,7 +392,7 @@ func (c *wsConnection) sendError(id string, errors ...*gqlerror.Error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
c.write(&operationMessage{Type: errorMsg, ID: id, Payload: b})
|
||||
c.write(&message{t: errorMessageType, id: id, payload: b})
|
||||
}
|
||||
|
||||
func (c *wsConnection) sendConnectionError(format string, args ...interface{}) {
|
||||
@@ -288,29 +401,15 @@ func (c *wsConnection) sendConnectionError(format string, args ...interface{}) {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.write(&operationMessage{Type: connectionErrorMsg, Payload: b})
|
||||
}
|
||||
|
||||
func (c *wsConnection) readOp() *operationMessage {
|
||||
_, r, err := c.conn.NextReader()
|
||||
if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) {
|
||||
return nil
|
||||
} else if err != nil {
|
||||
c.sendConnectionError("invalid json: %T %s", err, err.Error())
|
||||
return nil
|
||||
}
|
||||
message := operationMessage{}
|
||||
if err := jsonDecode(r, &message); err != nil {
|
||||
c.sendConnectionError("invalid json")
|
||||
return nil
|
||||
}
|
||||
|
||||
return &message
|
||||
c.write(&message{t: connectionErrorMessageType, payload: b})
|
||||
}
|
||||
|
||||
func (c *wsConnection) close(closeCode int, message string) {
|
||||
c.mu.Lock()
|
||||
_ = c.conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(closeCode, message))
|
||||
for _, closer := range c.active {
|
||||
closer()
|
||||
}
|
||||
c.mu.Unlock()
|
||||
_ = c.conn.Close()
|
||||
}
|
||||
|
||||
22
vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket_close_reason.go
generated
vendored
Normal file
22
vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket_close_reason.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// A private key for context that only this package can access. This is important
|
||||
// to prevent collisions between different context uses
|
||||
var closeReasonCtxKey = &wsCloseReasonContextKey{"close-reason"}
|
||||
|
||||
type wsCloseReasonContextKey struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func AppendCloseReason(ctx context.Context, reason string) context.Context {
|
||||
return context.WithValue(ctx, closeReasonCtxKey, reason)
|
||||
}
|
||||
|
||||
func closeReasonForContext(ctx context.Context) string {
|
||||
reason, _ := ctx.Value(closeReasonCtxKey).(string)
|
||||
return reason
|
||||
}
|
||||
149
vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket_graphql_transport_ws.go
generated
vendored
Normal file
149
vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket_graphql_transport_ws.go
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
// https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md
|
||||
const (
|
||||
graphqltransportwsSubprotocol = "graphql-transport-ws"
|
||||
|
||||
graphqltransportwsConnectionInitMsg = graphqltransportwsMessageType("connection_init")
|
||||
graphqltransportwsConnectionAckMsg = graphqltransportwsMessageType("connection_ack")
|
||||
graphqltransportwsSubscribeMsg = graphqltransportwsMessageType("subscribe")
|
||||
graphqltransportwsNextMsg = graphqltransportwsMessageType("next")
|
||||
graphqltransportwsErrorMsg = graphqltransportwsMessageType("error")
|
||||
graphqltransportwsCompleteMsg = graphqltransportwsMessageType("complete")
|
||||
graphqltransportwsPingMsg = graphqltransportwsMessageType("ping")
|
||||
graphqltransportwsPongMsg = graphqltransportwsMessageType("pong")
|
||||
)
|
||||
|
||||
var allGraphqltransportwsMessageTypes = []graphqltransportwsMessageType{
|
||||
graphqltransportwsConnectionInitMsg,
|
||||
graphqltransportwsConnectionAckMsg,
|
||||
graphqltransportwsSubscribeMsg,
|
||||
graphqltransportwsNextMsg,
|
||||
graphqltransportwsErrorMsg,
|
||||
graphqltransportwsCompleteMsg,
|
||||
graphqltransportwsPingMsg,
|
||||
graphqltransportwsPongMsg,
|
||||
}
|
||||
|
||||
type (
|
||||
graphqltransportwsMessageExchanger struct {
|
||||
c *websocket.Conn
|
||||
}
|
||||
|
||||
graphqltransportwsMessage struct {
|
||||
Payload json.RawMessage `json:"payload,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Type graphqltransportwsMessageType `json:"type"`
|
||||
noOp bool
|
||||
}
|
||||
|
||||
graphqltransportwsMessageType string
|
||||
)
|
||||
|
||||
func (me graphqltransportwsMessageExchanger) NextMessage() (message, error) {
|
||||
_, r, err := me.c.NextReader()
|
||||
if err != nil {
|
||||
return message{}, handleNextReaderError(err)
|
||||
}
|
||||
|
||||
var graphqltransportwsMessage graphqltransportwsMessage
|
||||
if err := jsonDecode(r, &graphqltransportwsMessage); err != nil {
|
||||
return message{}, errInvalidMsg
|
||||
}
|
||||
|
||||
return graphqltransportwsMessage.toMessage()
|
||||
}
|
||||
|
||||
func (me graphqltransportwsMessageExchanger) Send(m *message) error {
|
||||
msg := &graphqltransportwsMessage{}
|
||||
if err := msg.fromMessage(m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if msg.noOp {
|
||||
return nil
|
||||
}
|
||||
|
||||
return me.c.WriteJSON(msg)
|
||||
}
|
||||
|
||||
func (t *graphqltransportwsMessageType) UnmarshalText(text []byte) (err error) {
|
||||
var found bool
|
||||
for _, candidate := range allGraphqltransportwsMessageTypes {
|
||||
if string(candidate) == string(text) {
|
||||
*t = candidate
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
err = fmt.Errorf("invalid message type %s", string(text))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (t graphqltransportwsMessageType) MarshalText() ([]byte, error) {
|
||||
return []byte(string(t)), nil
|
||||
}
|
||||
|
||||
func (m graphqltransportwsMessage) toMessage() (message, error) {
|
||||
var t messageType
|
||||
var err error
|
||||
switch m.Type {
|
||||
default:
|
||||
err = fmt.Errorf("invalid client->server message type %s", m.Type)
|
||||
case graphqltransportwsConnectionInitMsg:
|
||||
t = initMessageType
|
||||
case graphqltransportwsSubscribeMsg:
|
||||
t = startMessageType
|
||||
case graphqltransportwsCompleteMsg:
|
||||
t = stopMessageType
|
||||
case graphqltransportwsPingMsg:
|
||||
t = pingMessageType
|
||||
case graphqltransportwsPongMsg:
|
||||
t = pongMessageType
|
||||
}
|
||||
|
||||
return message{
|
||||
payload: m.Payload,
|
||||
id: m.ID,
|
||||
t: t,
|
||||
}, err
|
||||
}
|
||||
|
||||
func (m *graphqltransportwsMessage) fromMessage(msg *message) (err error) {
|
||||
m.ID = msg.id
|
||||
m.Payload = msg.payload
|
||||
|
||||
switch msg.t {
|
||||
default:
|
||||
err = fmt.Errorf("invalid server->client message type %s", msg.t)
|
||||
case connectionAckMessageType:
|
||||
m.Type = graphqltransportwsConnectionAckMsg
|
||||
case keepAliveMessageType:
|
||||
m.noOp = true
|
||||
case connectionErrorMessageType:
|
||||
m.noOp = true
|
||||
case dataMessageType:
|
||||
m.Type = graphqltransportwsNextMsg
|
||||
case completeMessageType:
|
||||
m.Type = graphqltransportwsCompleteMsg
|
||||
case errorMessageType:
|
||||
m.Type = graphqltransportwsErrorMsg
|
||||
case pingMessageType:
|
||||
m.Type = graphqltransportwsPingMsg
|
||||
case pongMessageType:
|
||||
m.Type = graphqltransportwsPongMsg
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
171
vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket_graphqlws.go
generated
vendored
Normal file
171
vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket_graphqlws.go
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
// https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md
|
||||
const (
|
||||
graphqlwsSubprotocol = "graphql-ws"
|
||||
|
||||
graphqlwsConnectionInitMsg = graphqlwsMessageType("connection_init")
|
||||
graphqlwsConnectionTerminateMsg = graphqlwsMessageType("connection_terminate")
|
||||
graphqlwsStartMsg = graphqlwsMessageType("start")
|
||||
graphqlwsStopMsg = graphqlwsMessageType("stop")
|
||||
graphqlwsConnectionAckMsg = graphqlwsMessageType("connection_ack")
|
||||
graphqlwsConnectionErrorMsg = graphqlwsMessageType("connection_error")
|
||||
graphqlwsDataMsg = graphqlwsMessageType("data")
|
||||
graphqlwsErrorMsg = graphqlwsMessageType("error")
|
||||
graphqlwsCompleteMsg = graphqlwsMessageType("complete")
|
||||
graphqlwsConnectionKeepAliveMsg = graphqlwsMessageType("ka")
|
||||
)
|
||||
|
||||
var allGraphqlwsMessageTypes = []graphqlwsMessageType{
|
||||
graphqlwsConnectionInitMsg,
|
||||
graphqlwsConnectionTerminateMsg,
|
||||
graphqlwsStartMsg,
|
||||
graphqlwsStopMsg,
|
||||
graphqlwsConnectionAckMsg,
|
||||
graphqlwsConnectionErrorMsg,
|
||||
graphqlwsDataMsg,
|
||||
graphqlwsErrorMsg,
|
||||
graphqlwsCompleteMsg,
|
||||
graphqlwsConnectionKeepAliveMsg,
|
||||
}
|
||||
|
||||
type (
|
||||
graphqlwsMessageExchanger struct {
|
||||
c *websocket.Conn
|
||||
}
|
||||
|
||||
graphqlwsMessage struct {
|
||||
Payload json.RawMessage `json:"payload,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Type graphqlwsMessageType `json:"type"`
|
||||
noOp bool
|
||||
}
|
||||
|
||||
graphqlwsMessageType string
|
||||
)
|
||||
|
||||
func (me graphqlwsMessageExchanger) NextMessage() (message, error) {
|
||||
_, r, err := me.c.NextReader()
|
||||
if err != nil {
|
||||
return message{}, handleNextReaderError(err)
|
||||
}
|
||||
|
||||
var graphqlwsMessage graphqlwsMessage
|
||||
if err := jsonDecode(r, &graphqlwsMessage); err != nil {
|
||||
return message{}, errInvalidMsg
|
||||
}
|
||||
|
||||
return graphqlwsMessage.toMessage()
|
||||
}
|
||||
|
||||
func (me graphqlwsMessageExchanger) Send(m *message) error {
|
||||
msg := &graphqlwsMessage{}
|
||||
if err := msg.fromMessage(m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if msg.noOp {
|
||||
return nil
|
||||
}
|
||||
|
||||
return me.c.WriteJSON(msg)
|
||||
}
|
||||
|
||||
func (t *graphqlwsMessageType) UnmarshalText(text []byte) (err error) {
|
||||
var found bool
|
||||
for _, candidate := range allGraphqlwsMessageTypes {
|
||||
if string(candidate) == string(text) {
|
||||
*t = candidate
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
err = fmt.Errorf("invalid message type %s", string(text))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (t graphqlwsMessageType) MarshalText() ([]byte, error) {
|
||||
return []byte(string(t)), nil
|
||||
}
|
||||
|
||||
func (m graphqlwsMessage) toMessage() (message, error) {
|
||||
var t messageType
|
||||
var err error
|
||||
switch m.Type {
|
||||
default:
|
||||
err = fmt.Errorf("invalid client->server message type %s", m.Type)
|
||||
case graphqlwsConnectionInitMsg:
|
||||
t = initMessageType
|
||||
case graphqlwsConnectionTerminateMsg:
|
||||
t = connectionCloseMessageType
|
||||
case graphqlwsStartMsg:
|
||||
t = startMessageType
|
||||
case graphqlwsStopMsg:
|
||||
t = stopMessageType
|
||||
case graphqlwsConnectionAckMsg:
|
||||
t = connectionAckMessageType
|
||||
case graphqlwsConnectionErrorMsg:
|
||||
t = connectionErrorMessageType
|
||||
case graphqlwsDataMsg:
|
||||
t = dataMessageType
|
||||
case graphqlwsErrorMsg:
|
||||
t = errorMessageType
|
||||
case graphqlwsCompleteMsg:
|
||||
t = completeMessageType
|
||||
case graphqlwsConnectionKeepAliveMsg:
|
||||
t = keepAliveMessageType
|
||||
}
|
||||
|
||||
return message{
|
||||
payload: m.Payload,
|
||||
id: m.ID,
|
||||
t: t,
|
||||
}, err
|
||||
}
|
||||
|
||||
func (m *graphqlwsMessage) fromMessage(msg *message) (err error) {
|
||||
m.ID = msg.id
|
||||
m.Payload = msg.payload
|
||||
|
||||
switch msg.t {
|
||||
default:
|
||||
err = fmt.Errorf("invalid server->client message type %s", msg.t)
|
||||
case initMessageType:
|
||||
m.Type = graphqlwsConnectionInitMsg
|
||||
case connectionAckMessageType:
|
||||
m.Type = graphqlwsConnectionAckMsg
|
||||
case keepAliveMessageType:
|
||||
m.Type = graphqlwsConnectionKeepAliveMsg
|
||||
case connectionErrorMessageType:
|
||||
m.Type = graphqlwsConnectionErrorMsg
|
||||
case connectionCloseMessageType:
|
||||
m.Type = graphqlwsConnectionTerminateMsg
|
||||
case startMessageType:
|
||||
m.Type = graphqlwsStartMsg
|
||||
case stopMessageType:
|
||||
m.Type = graphqlwsStopMsg
|
||||
case dataMessageType:
|
||||
m.Type = graphqlwsDataMsg
|
||||
case completeMessageType:
|
||||
m.Type = graphqlwsCompleteMsg
|
||||
case errorMessageType:
|
||||
m.Type = graphqlwsErrorMsg
|
||||
case pingMessageType:
|
||||
m.noOp = true
|
||||
case pongMessageType:
|
||||
m.noOp = true
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
116
vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket_subprotocol.go
generated
vendored
Normal file
116
vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket_subprotocol.go
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
const (
|
||||
initMessageType messageType = iota
|
||||
connectionAckMessageType
|
||||
keepAliveMessageType
|
||||
connectionErrorMessageType
|
||||
connectionCloseMessageType
|
||||
startMessageType
|
||||
stopMessageType
|
||||
dataMessageType
|
||||
completeMessageType
|
||||
errorMessageType
|
||||
pingMessageType
|
||||
pongMessageType
|
||||
)
|
||||
|
||||
var (
|
||||
supportedSubprotocols = []string{
|
||||
graphqlwsSubprotocol,
|
||||
graphqltransportwsSubprotocol,
|
||||
}
|
||||
|
||||
errWsConnClosed = errors.New("websocket connection closed")
|
||||
errInvalidMsg = errors.New("invalid message received")
|
||||
)
|
||||
|
||||
type (
|
||||
messageType int
|
||||
message struct {
|
||||
payload json.RawMessage
|
||||
id string
|
||||
t messageType
|
||||
}
|
||||
messageExchanger interface {
|
||||
NextMessage() (message, error)
|
||||
Send(m *message) error
|
||||
}
|
||||
)
|
||||
|
||||
func (t messageType) String() string {
|
||||
var text string
|
||||
switch t {
|
||||
default:
|
||||
text = "unknown"
|
||||
case initMessageType:
|
||||
text = "init"
|
||||
case connectionAckMessageType:
|
||||
text = "connection ack"
|
||||
case keepAliveMessageType:
|
||||
text = "keep alive"
|
||||
case connectionErrorMessageType:
|
||||
text = "connection error"
|
||||
case connectionCloseMessageType:
|
||||
text = "connection close"
|
||||
case startMessageType:
|
||||
text = "start"
|
||||
case stopMessageType:
|
||||
text = "stop subscription"
|
||||
case dataMessageType:
|
||||
text = "data"
|
||||
case completeMessageType:
|
||||
text = "complete"
|
||||
case errorMessageType:
|
||||
text = "error"
|
||||
case pingMessageType:
|
||||
text = "ping"
|
||||
case pongMessageType:
|
||||
text = "pong"
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
func contains(list []string, elem string) bool {
|
||||
for _, e := range list {
|
||||
if e == elem {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *Websocket) injectGraphQLWSSubprotocols() {
|
||||
// the list of subprotocols is specified by the consumer of the Websocket struct,
|
||||
// in order to preserve backward compatibility, we inject the graphql specific subprotocols
|
||||
// at runtime
|
||||
if !t.didInjectSubprotocols {
|
||||
defer func() {
|
||||
t.didInjectSubprotocols = true
|
||||
}()
|
||||
|
||||
for _, subprotocol := range supportedSubprotocols {
|
||||
if !contains(t.Upgrader.Subprotocols, subprotocol) {
|
||||
t.Upgrader.Subprotocols = append(t.Upgrader.Subprotocols, subprotocol)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleNextReaderError(err error) error {
|
||||
// TODO: should we consider all closure scenarios here for the ws connection?
|
||||
// for now we only list the error codes from the previous implementation
|
||||
if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) {
|
||||
return errWsConnClosed
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
5
vendor/github.com/99designs/gqlgen/graphql/id.go
generated
vendored
5
vendor/github.com/99designs/gqlgen/graphql/id.go
generated
vendored
@@ -8,10 +8,9 @@ import (
|
||||
)
|
||||
|
||||
func MarshalID(s string) Marshaler {
|
||||
return WriterFunc(func(w io.Writer) {
|
||||
io.WriteString(w, strconv.Quote(s))
|
||||
})
|
||||
return MarshalString(s)
|
||||
}
|
||||
|
||||
func UnmarshalID(v interface{}) (string, error) {
|
||||
switch v := v.(type) {
|
||||
case string:
|
||||
|
||||
43
vendor/github.com/99designs/gqlgen/graphql/introspection/introspection.go
generated
vendored
43
vendor/github.com/99designs/gqlgen/graphql/introspection/introspection.go
generated
vendored
@@ -5,21 +5,22 @@ import "github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
type (
|
||||
Directive struct {
|
||||
Name string
|
||||
Description string
|
||||
Locations []string
|
||||
Args []InputValue
|
||||
Name string
|
||||
description string
|
||||
Locations []string
|
||||
Args []InputValue
|
||||
IsRepeatable bool
|
||||
}
|
||||
|
||||
EnumValue struct {
|
||||
Name string
|
||||
Description string
|
||||
description string
|
||||
deprecation *ast.Directive
|
||||
}
|
||||
|
||||
Field struct {
|
||||
Name string
|
||||
Description string
|
||||
description string
|
||||
Type *Type
|
||||
Args []InputValue
|
||||
deprecation *ast.Directive
|
||||
@@ -27,7 +28,7 @@ type (
|
||||
|
||||
InputValue struct {
|
||||
Name string
|
||||
Description string
|
||||
description string
|
||||
DefaultValue *string
|
||||
Type *Type
|
||||
}
|
||||
@@ -37,6 +38,13 @@ func WrapSchema(schema *ast.Schema) *Schema {
|
||||
return &Schema{schema: schema}
|
||||
}
|
||||
|
||||
func (f *EnumValue) Description() *string {
|
||||
if f.description == "" {
|
||||
return nil
|
||||
}
|
||||
return &f.description
|
||||
}
|
||||
|
||||
func (f *EnumValue) IsDeprecated() bool {
|
||||
return f.deprecation != nil
|
||||
}
|
||||
@@ -54,6 +62,13 @@ func (f *EnumValue) DeprecationReason() *string {
|
||||
return &reason.Value.Raw
|
||||
}
|
||||
|
||||
func (f *Field) Description() *string {
|
||||
if f.description == "" {
|
||||
return nil
|
||||
}
|
||||
return &f.description
|
||||
}
|
||||
|
||||
func (f *Field) IsDeprecated() bool {
|
||||
return f.deprecation != nil
|
||||
}
|
||||
@@ -70,3 +85,17 @@ func (f *Field) DeprecationReason() *string {
|
||||
|
||||
return &reason.Value.Raw
|
||||
}
|
||||
|
||||
func (f *InputValue) Description() *string {
|
||||
if f.description == "" {
|
||||
return nil
|
||||
}
|
||||
return &f.description
|
||||
}
|
||||
|
||||
func (f *Directive) Description() *string {
|
||||
if f.description == "" {
|
||||
return nil
|
||||
}
|
||||
return &f.description
|
||||
}
|
||||
|
||||
2
vendor/github.com/99designs/gqlgen/graphql/introspection/query.go
generated
vendored
2
vendor/github.com/99designs/gqlgen/graphql/introspection/query.go
generated
vendored
@@ -4,6 +4,7 @@ package introspection
|
||||
const Query = `
|
||||
query IntrospectionQuery {
|
||||
__schema {
|
||||
description
|
||||
queryType {
|
||||
name
|
||||
}
|
||||
@@ -31,6 +32,7 @@ fragment FullType on __Type {
|
||||
kind
|
||||
name
|
||||
description
|
||||
specifiedByURL
|
||||
fields(includeDeprecated: true) {
|
||||
name
|
||||
description
|
||||
|
||||
43
vendor/github.com/99designs/gqlgen/graphql/introspection/schema.go
generated
vendored
43
vendor/github.com/99designs/gqlgen/graphql/introspection/schema.go
generated
vendored
@@ -1,6 +1,7 @@
|
||||
package introspection
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
@@ -10,13 +11,28 @@ type Schema struct {
|
||||
schema *ast.Schema
|
||||
}
|
||||
|
||||
func (s *Schema) Description() *string {
|
||||
if s.schema.Description == "" {
|
||||
return nil
|
||||
}
|
||||
return &s.schema.Description
|
||||
}
|
||||
|
||||
func (s *Schema) Types() []Type {
|
||||
types := make([]Type, 0, len(s.schema.Types))
|
||||
typeIndex := map[string]Type{}
|
||||
typeNames := make([]string, 0, len(s.schema.Types))
|
||||
for _, typ := range s.schema.Types {
|
||||
if strings.HasPrefix(typ.Name, "__") {
|
||||
continue
|
||||
}
|
||||
types = append(types, *WrapTypeFromDef(s.schema, typ))
|
||||
typeNames = append(typeNames, typ.Name)
|
||||
typeIndex[typ.Name] = *WrapTypeFromDef(s.schema, typ)
|
||||
}
|
||||
sort.Strings(typeNames)
|
||||
|
||||
types := make([]Type, len(typeNames))
|
||||
for i, t := range typeNames {
|
||||
types[i] = typeIndex[t]
|
||||
}
|
||||
return types
|
||||
}
|
||||
@@ -34,10 +50,18 @@ func (s *Schema) SubscriptionType() *Type {
|
||||
}
|
||||
|
||||
func (s *Schema) Directives() []Directive {
|
||||
res := make([]Directive, 0, len(s.schema.Directives))
|
||||
dIndex := map[string]Directive{}
|
||||
dNames := make([]string, 0, len(s.schema.Directives))
|
||||
|
||||
for _, d := range s.schema.Directives {
|
||||
res = append(res, s.directiveFromDef(d))
|
||||
dNames = append(dNames, d.Name)
|
||||
dIndex[d.Name] = s.directiveFromDef(d)
|
||||
}
|
||||
sort.Strings(dNames)
|
||||
|
||||
res := make([]Directive, len(dNames))
|
||||
for i, d := range dNames {
|
||||
res[i] = dIndex[d]
|
||||
}
|
||||
|
||||
return res
|
||||
@@ -53,16 +77,17 @@ func (s *Schema) directiveFromDef(d *ast.DirectiveDefinition) Directive {
|
||||
for i, arg := range d.Arguments {
|
||||
args[i] = InputValue{
|
||||
Name: arg.Name,
|
||||
Description: arg.Description,
|
||||
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,
|
||||
Name: d.Name,
|
||||
description: d.Description,
|
||||
Locations: locs,
|
||||
Args: args,
|
||||
IsRepeatable: d.IsRepeatable,
|
||||
}
|
||||
}
|
||||
|
||||
27
vendor/github.com/99designs/gqlgen/graphql/introspection/type.go
generated
vendored
27
vendor/github.com/99designs/gqlgen/graphql/introspection/type.go
generated
vendored
@@ -53,11 +53,11 @@ func (t *Type) Name() *string {
|
||||
return &t.def.Name
|
||||
}
|
||||
|
||||
func (t *Type) Description() string {
|
||||
if t.def == nil {
|
||||
return ""
|
||||
func (t *Type) Description() *string {
|
||||
if t.def == nil || t.def.Description == "" {
|
||||
return nil
|
||||
}
|
||||
return t.def.Description
|
||||
return &t.def.Description
|
||||
}
|
||||
|
||||
func (t *Type) Fields(includeDeprecated bool) []Field {
|
||||
@@ -79,14 +79,14 @@ func (t *Type) Fields(includeDeprecated bool) []Field {
|
||||
args = append(args, InputValue{
|
||||
Type: WrapTypeFromType(t.schema, arg.Type),
|
||||
Name: arg.Name,
|
||||
Description: arg.Description,
|
||||
description: arg.Description,
|
||||
DefaultValue: defaultValue(arg.DefaultValue),
|
||||
})
|
||||
}
|
||||
|
||||
fields = append(fields, Field{
|
||||
Name: f.Name,
|
||||
Description: f.Description,
|
||||
description: f.Description,
|
||||
Args: args,
|
||||
Type: WrapTypeFromType(t.schema, f.Type),
|
||||
deprecation: f.Directives.ForName("deprecated"),
|
||||
@@ -104,7 +104,7 @@ func (t *Type) InputFields() []InputValue {
|
||||
for _, f := range t.def.Fields {
|
||||
res = append(res, InputValue{
|
||||
Name: f.Name,
|
||||
Description: f.Description,
|
||||
description: f.Description,
|
||||
Type: WrapTypeFromType(t.schema, f.Type),
|
||||
DefaultValue: defaultValue(f.DefaultValue),
|
||||
})
|
||||
@@ -158,7 +158,7 @@ func (t *Type) EnumValues(includeDeprecated bool) []EnumValue {
|
||||
|
||||
res = append(res, EnumValue{
|
||||
Name: val.Name,
|
||||
Description: val.Description,
|
||||
description: val.Description,
|
||||
deprecation: val.Directives.ForName("deprecated"),
|
||||
})
|
||||
}
|
||||
@@ -178,3 +178,14 @@ func (t *Type) OfType() *Type {
|
||||
}
|
||||
return WrapTypeFromType(t.schema, t.typ.Elem)
|
||||
}
|
||||
|
||||
func (t *Type) SpecifiedByURL() *string {
|
||||
directive := t.def.Directives.ForName("specifiedBy")
|
||||
if t.def.Kind != ast.Scalar || directive == nil {
|
||||
return nil
|
||||
}
|
||||
// def: directive @specifiedBy(url: String!) on SCALAR
|
||||
// the argument "url" is required.
|
||||
url := directive.Arguments.ForName("url")
|
||||
return &url.Value.Raw
|
||||
}
|
||||
|
||||
65
vendor/github.com/99designs/gqlgen/graphql/jsonw.go
generated
vendored
65
vendor/github.com/99designs/gqlgen/graphql/jsonw.go
generated
vendored
@@ -1,22 +1,27 @@
|
||||
package graphql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
)
|
||||
|
||||
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 (
|
||||
nullLit = []byte(`null`)
|
||||
trueLit = []byte(`true`)
|
||||
falseLit = []byte(`false`)
|
||||
openBrace = []byte(`{`)
|
||||
closeBrace = []byte(`}`)
|
||||
openBracket = []byte(`[`)
|
||||
closeBracket = []byte(`]`)
|
||||
colon = []byte(`:`)
|
||||
comma = []byte(`,`)
|
||||
)
|
||||
|
||||
var Null = &lit{nullLit}
|
||||
var True = &lit{trueLit}
|
||||
var False = &lit{falseLit}
|
||||
var (
|
||||
Null = &lit{nullLit}
|
||||
True = &lit{trueLit}
|
||||
False = &lit{falseLit}
|
||||
)
|
||||
|
||||
type Marshaler interface {
|
||||
MarshalGQL(w io.Writer)
|
||||
@@ -26,12 +31,43 @@ type Unmarshaler interface {
|
||||
UnmarshalGQL(v interface{}) error
|
||||
}
|
||||
|
||||
type ContextMarshaler interface {
|
||||
MarshalGQLContext(ctx context.Context, w io.Writer) error
|
||||
}
|
||||
|
||||
type ContextUnmarshaler interface {
|
||||
UnmarshalGQLContext(ctx context.Context, v interface{}) error
|
||||
}
|
||||
|
||||
type contextMarshalerAdapter struct {
|
||||
Context context.Context
|
||||
ContextMarshaler
|
||||
}
|
||||
|
||||
func WrapContextMarshaler(ctx context.Context, m ContextMarshaler) Marshaler {
|
||||
return contextMarshalerAdapter{Context: ctx, ContextMarshaler: m}
|
||||
}
|
||||
|
||||
func (a contextMarshalerAdapter) MarshalGQL(w io.Writer) {
|
||||
err := a.MarshalGQLContext(a.Context, w)
|
||||
if err != nil {
|
||||
AddError(a.Context, err)
|
||||
Null.MarshalGQL(w)
|
||||
}
|
||||
}
|
||||
|
||||
type WriterFunc func(writer io.Writer)
|
||||
|
||||
func (f WriterFunc) MarshalGQL(w io.Writer) {
|
||||
f(w)
|
||||
}
|
||||
|
||||
type ContextWriterFunc func(ctx context.Context, writer io.Writer) error
|
||||
|
||||
func (f ContextWriterFunc) MarshalGQLContext(ctx context.Context, w io.Writer) error {
|
||||
return f(ctx, w)
|
||||
}
|
||||
|
||||
type Array []Marshaler
|
||||
|
||||
func (a Array) MarshalGQL(writer io.Writer) {
|
||||
@@ -50,3 +86,8 @@ type lit struct{ b []byte }
|
||||
func (l lit) MarshalGQL(w io.Writer) {
|
||||
w.Write(l.b)
|
||||
}
|
||||
|
||||
func (l lit) MarshalGQLContext(ctx context.Context, w io.Writer) error {
|
||||
w.Write(l.b)
|
||||
return nil
|
||||
}
|
||||
|
||||
91
vendor/github.com/99designs/gqlgen/graphql/playground/playground.go
generated
vendored
91
vendor/github.com/99designs/gqlgen/graphql/playground/playground.go
generated
vendored
@@ -7,40 +7,50 @@ import (
|
||||
|
||||
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="https://cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/static/css/index.css"
|
||||
integrity="{{ .cssSRI }}" crossorigin="anonymous"/>
|
||||
<link rel="shortcut icon" href="https://cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/favicon.png"
|
||||
integrity="{{ .faviconSRI }}" crossorigin="anonymous"/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/static/js/middleware.js"
|
||||
integrity="{{ .jsSRI }}" crossorigin="anonymous"></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 }}',
|
||||
shareEnabled: true,
|
||||
settings: {
|
||||
'request.credentials': 'same-origin'
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
<head>
|
||||
<title>{{.title}}</title>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/graphiql@{{.version}}/graphiql.min.css"
|
||||
integrity="{{.cssSRI}}"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
</head>
|
||||
<body style="margin: 0;">
|
||||
<div id="graphiql" style="height: 100vh;"></div>
|
||||
|
||||
<script
|
||||
src="https://cdn.jsdelivr.net/npm/react@17.0.2/umd/react.production.min.js"
|
||||
integrity="{{.reactSRI}}"
|
||||
crossorigin="anonymous"
|
||||
></script>
|
||||
<script
|
||||
src="https://cdn.jsdelivr.net/npm/react-dom@17.0.2/umd/react-dom.production.min.js"
|
||||
integrity="{{.reactDOMSRI}}"
|
||||
crossorigin="anonymous"
|
||||
></script>
|
||||
<script
|
||||
src="https://cdn.jsdelivr.net/npm/graphiql@{{.version}}/graphiql.min.js"
|
||||
integrity="{{.jsSRI}}"
|
||||
crossorigin="anonymous"
|
||||
></script>
|
||||
|
||||
<script>
|
||||
const url = location.protocol + '//' + location.host + '{{.endpoint}}';
|
||||
const wsProto = location.protocol == 'https:' ? 'wss:' : 'ws:';
|
||||
const subscriptionUrl = wsProto + '//' + location.host + '{{.endpoint}}';
|
||||
|
||||
const fetcher = GraphiQL.createFetcher({ url, subscriptionUrl });
|
||||
ReactDOM.render(
|
||||
React.createElement(GraphiQL, {
|
||||
fetcher: fetcher,
|
||||
headerEditorEnabled: true,
|
||||
shouldPersistHeaders: true
|
||||
}),
|
||||
document.getElementById('graphiql'),
|
||||
);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`))
|
||||
|
||||
@@ -48,12 +58,13 @@ func Handler(title string, endpoint string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("Content-Type", "text/html")
|
||||
err := page.Execute(w, map[string]string{
|
||||
"title": title,
|
||||
"endpoint": endpoint,
|
||||
"version": "1.7.20",
|
||||
"cssSRI": "sha256-cS9Vc2OBt9eUf4sykRWukeFYaInL29+myBmFDSa7F/U=",
|
||||
"faviconSRI": "sha256-GhTyE+McTU79R4+pRO6ih+4TfsTOrpPwD8ReKFzb3PM=",
|
||||
"jsSRI": "sha256-4QG1Uza2GgGdlBL3RCBCGtGeZB6bDbsw8OltCMGeJsA=",
|
||||
"title": title,
|
||||
"endpoint": endpoint,
|
||||
"version": "1.5.16",
|
||||
"cssSRI": "sha256-HADQowUuFum02+Ckkv5Yu5ygRoLllHZqg0TFZXY7NHI=",
|
||||
"jsSRI": "sha256-uHp12yvpXC4PC9+6JmITxKuLYwjlW9crq9ywPE5Rxco=",
|
||||
"reactSRI": "sha256-Ipu/TQ50iCCVZBUsZyNJfxrDk0E2yhaEIz0vqI+kFG8=",
|
||||
"reactDOMSRI": "sha256-nbMykgB6tsOFJ7OdVmPpdqMFVk4ZsqWocT6issAPUF0=",
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
||||
5
vendor/github.com/99designs/gqlgen/graphql/recovery.go
generated
vendored
5
vendor/github.com/99designs/gqlgen/graphql/recovery.go
generated
vendored
@@ -2,10 +2,11 @@ package graphql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
type RecoverFunc func(ctx context.Context, err interface{}) (userMessage error)
|
||||
@@ -15,5 +16,5 @@ func DefaultRecover(ctx context.Context, err interface{}) error {
|
||||
fmt.Fprintln(os.Stderr)
|
||||
debug.PrintStack()
|
||||
|
||||
return errors.New("internal system error")
|
||||
return gqlerror.Errorf("internal system error")
|
||||
}
|
||||
|
||||
2
vendor/github.com/99designs/gqlgen/graphql/string.go
generated
vendored
2
vendor/github.com/99designs/gqlgen/graphql/string.go
generated
vendored
@@ -52,6 +52,8 @@ func UnmarshalString(v interface{}) (string, error) {
|
||||
return v, nil
|
||||
case int:
|
||||
return strconv.Itoa(v), nil
|
||||
case int64:
|
||||
return strconv.FormatInt(v, 10), nil
|
||||
case float64:
|
||||
return fmt.Sprintf("%f", v), nil
|
||||
case bool:
|
||||
|
||||
6
vendor/github.com/99designs/gqlgen/graphql/time.go
generated
vendored
6
vendor/github.com/99designs/gqlgen/graphql/time.go
generated
vendored
@@ -13,13 +13,13 @@ func MarshalTime(t time.Time) Marshaler {
|
||||
}
|
||||
|
||||
return WriterFunc(func(w io.Writer) {
|
||||
io.WriteString(w, strconv.Quote(t.Format(time.RFC3339)))
|
||||
io.WriteString(w, strconv.Quote(t.Format(time.RFC3339Nano)))
|
||||
})
|
||||
}
|
||||
|
||||
func UnmarshalTime(v interface{}) (time.Time, error) {
|
||||
if tmpStr, ok := v.(string); ok {
|
||||
return time.Parse(time.RFC3339, tmpStr)
|
||||
return time.Parse(time.RFC3339Nano, tmpStr)
|
||||
}
|
||||
return time.Time{}, errors.New("time should be RFC3339 formatted string")
|
||||
return time.Time{}, errors.New("time should be RFC3339Nano formatted string")
|
||||
}
|
||||
|
||||
81
vendor/github.com/99designs/gqlgen/graphql/uint.go
generated
vendored
Normal file
81
vendor/github.com/99designs/gqlgen/graphql/uint.go
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
package graphql
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func MarshalUint(i uint) Marshaler {
|
||||
return WriterFunc(func(w io.Writer) {
|
||||
_, _ = io.WriteString(w, strconv.FormatUint(uint64(i), 10))
|
||||
})
|
||||
}
|
||||
|
||||
func UnmarshalUint(v interface{}) (uint, error) {
|
||||
switch v := v.(type) {
|
||||
case string:
|
||||
u64, err := strconv.ParseUint(v, 10, 64)
|
||||
return uint(u64), err
|
||||
case int:
|
||||
return uint(v), nil
|
||||
case int64:
|
||||
return uint(v), nil
|
||||
case json.Number:
|
||||
u64, err := strconv.ParseUint(string(v), 10, 64)
|
||||
return uint(u64), err
|
||||
default:
|
||||
return 0, fmt.Errorf("%T is not an uint", v)
|
||||
}
|
||||
}
|
||||
|
||||
func MarshalUint64(i uint64) Marshaler {
|
||||
return WriterFunc(func(w io.Writer) {
|
||||
_, _ = io.WriteString(w, strconv.FormatUint(i, 10))
|
||||
})
|
||||
}
|
||||
|
||||
func UnmarshalUint64(v interface{}) (uint64, error) {
|
||||
switch v := v.(type) {
|
||||
case string:
|
||||
return strconv.ParseUint(v, 10, 64)
|
||||
case int:
|
||||
return uint64(v), nil
|
||||
case int64:
|
||||
return uint64(v), nil
|
||||
case json.Number:
|
||||
return strconv.ParseUint(string(v), 10, 64)
|
||||
default:
|
||||
return 0, fmt.Errorf("%T is not an uint", v)
|
||||
}
|
||||
}
|
||||
|
||||
func MarshalUint32(i uint32) Marshaler {
|
||||
return WriterFunc(func(w io.Writer) {
|
||||
_, _ = io.WriteString(w, strconv.FormatUint(uint64(i), 10))
|
||||
})
|
||||
}
|
||||
|
||||
func UnmarshalUint32(v interface{}) (uint32, error) {
|
||||
switch v := v.(type) {
|
||||
case string:
|
||||
iv, err := strconv.ParseInt(v, 10, 32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint32(iv), nil
|
||||
case int:
|
||||
return uint32(v), nil
|
||||
case int64:
|
||||
return uint32(v), nil
|
||||
case json.Number:
|
||||
iv, err := strconv.ParseUint(string(v), 10, 32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint32(iv), nil
|
||||
default:
|
||||
return 0, fmt.Errorf("%T is not an uint", v)
|
||||
}
|
||||
}
|
||||
2
vendor/github.com/99designs/gqlgen/graphql/version.go
generated
vendored
2
vendor/github.com/99designs/gqlgen/graphql/version.go
generated
vendored
@@ -1,3 +1,3 @@
|
||||
package graphql
|
||||
|
||||
const Version = "v0.12.2"
|
||||
const Version = "v0.17.2"
|
||||
|
||||
247
vendor/github.com/99designs/gqlgen/handler/handler.go
generated
vendored
247
vendor/github.com/99designs/gqlgen/handler/handler.go
generated
vendored
@@ -1,247 +0,0 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/99designs/gqlgen/graphql/handler"
|
||||
"github.com/99designs/gqlgen/graphql/handler/extension"
|
||||
"github.com/99designs/gqlgen/graphql/handler/lru"
|
||||
"github.com/99designs/gqlgen/graphql/handler/transport"
|
||||
"github.com/99designs/gqlgen/graphql/playground"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
// Deprecated: switch to graphql/handler.New
|
||||
func GraphQL(exec graphql.ExecutableSchema, options ...Option) http.HandlerFunc {
|
||||
var cfg Config
|
||||
cfg.cacheSize = 1000
|
||||
|
||||
for _, option := range options {
|
||||
option(&cfg)
|
||||
}
|
||||
|
||||
srv := handler.New(exec)
|
||||
|
||||
srv.AddTransport(transport.Websocket{
|
||||
Upgrader: cfg.upgrader,
|
||||
InitFunc: cfg.websocketInitFunc,
|
||||
KeepAlivePingInterval: cfg.connectionKeepAlivePingInterval,
|
||||
})
|
||||
srv.AddTransport(transport.Options{})
|
||||
srv.AddTransport(transport.GET{})
|
||||
srv.AddTransport(transport.POST{})
|
||||
srv.AddTransport(transport.MultipartForm{
|
||||
MaxUploadSize: cfg.uploadMaxSize,
|
||||
MaxMemory: cfg.uploadMaxMemory,
|
||||
})
|
||||
|
||||
if cfg.cacheSize != 0 {
|
||||
srv.SetQueryCache(lru.New(cfg.cacheSize))
|
||||
}
|
||||
if cfg.recover != nil {
|
||||
srv.SetRecoverFunc(cfg.recover)
|
||||
}
|
||||
if cfg.errorPresenter != nil {
|
||||
srv.SetErrorPresenter(cfg.errorPresenter)
|
||||
}
|
||||
for _, hook := range cfg.fieldHooks {
|
||||
srv.AroundFields(hook)
|
||||
}
|
||||
for _, hook := range cfg.requestHooks {
|
||||
srv.AroundResponses(hook)
|
||||
}
|
||||
if cfg.complexityLimit != 0 {
|
||||
srv.Use(extension.FixedComplexityLimit(cfg.complexityLimit))
|
||||
} else if cfg.complexityLimitFunc != nil {
|
||||
srv.Use(&extension.ComplexityLimit{
|
||||
Func: func(ctx context.Context, rc *graphql.OperationContext) int {
|
||||
return cfg.complexityLimitFunc(graphql.WithOperationContext(ctx, rc))
|
||||
},
|
||||
})
|
||||
}
|
||||
if !cfg.disableIntrospection {
|
||||
srv.Use(extension.Introspection{})
|
||||
}
|
||||
if cfg.apqCache != nil {
|
||||
srv.Use(extension.AutomaticPersistedQuery{Cache: apqAdapter{cfg.apqCache}})
|
||||
}
|
||||
return srv.ServeHTTP
|
||||
}
|
||||
|
||||
// Deprecated: switch to graphql/handler.New
|
||||
type Config struct {
|
||||
cacheSize int
|
||||
upgrader websocket.Upgrader
|
||||
websocketInitFunc transport.WebsocketInitFunc
|
||||
connectionKeepAlivePingInterval time.Duration
|
||||
recover graphql.RecoverFunc
|
||||
errorPresenter graphql.ErrorPresenterFunc
|
||||
fieldHooks []graphql.FieldMiddleware
|
||||
requestHooks []graphql.ResponseMiddleware
|
||||
complexityLimit int
|
||||
complexityLimitFunc func(ctx context.Context) int
|
||||
disableIntrospection bool
|
||||
uploadMaxMemory int64
|
||||
uploadMaxSize int64
|
||||
apqCache PersistedQueryCache
|
||||
}
|
||||
|
||||
// Deprecated: switch to graphql/handler.New
|
||||
type Option func(cfg *Config)
|
||||
|
||||
// Deprecated: switch to graphql/handler.New
|
||||
func WebsocketUpgrader(upgrader websocket.Upgrader) Option {
|
||||
return func(cfg *Config) {
|
||||
cfg.upgrader = upgrader
|
||||
}
|
||||
}
|
||||
|
||||
// Deprecated: switch to graphql/handler.New
|
||||
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.
|
||||
// Deprecated: switch to graphql/handler.New
|
||||
func ErrorPresenter(f graphql.ErrorPresenterFunc) Option {
|
||||
return func(cfg *Config) {
|
||||
cfg.errorPresenter = f
|
||||
}
|
||||
}
|
||||
|
||||
// IntrospectionEnabled = false will forbid clients from calling introspection endpoints. Can be useful in prod when you dont
|
||||
// want clients introspecting the full schema.
|
||||
// Deprecated: switch to graphql/handler.New
|
||||
func IntrospectionEnabled(enabled bool) Option {
|
||||
return func(cfg *Config) {
|
||||
cfg.disableIntrospection = !enabled
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
// Deprecated: switch to graphql/handler.New
|
||||
func ComplexityLimit(limit int) Option {
|
||||
return func(cfg *Config) {
|
||||
cfg.complexityLimit = limit
|
||||
}
|
||||
}
|
||||
|
||||
// ComplexityLimitFunc allows you to define a function to dynamically set the 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.
|
||||
// Deprecated: switch to graphql/handler.New
|
||||
func ComplexityLimitFunc(complexityLimitFunc func(ctx context.Context) int) Option {
|
||||
return func(cfg *Config) {
|
||||
cfg.complexityLimitFunc = complexityLimitFunc
|
||||
}
|
||||
}
|
||||
|
||||
// ResolverMiddleware allows you to define a function that will be called around every resolver,
|
||||
// useful for logging.
|
||||
// Deprecated: switch to graphql/handler.New
|
||||
func ResolverMiddleware(middleware graphql.FieldMiddleware) Option {
|
||||
return func(cfg *Config) {
|
||||
cfg.fieldHooks = append(cfg.fieldHooks, middleware)
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// Deprecated: switch to graphql/handler.New
|
||||
func RequestMiddleware(middleware graphql.ResponseMiddleware) Option {
|
||||
return func(cfg *Config) {
|
||||
cfg.requestHooks = append(cfg.requestHooks, middleware)
|
||||
}
|
||||
}
|
||||
|
||||
// WebsocketInitFunc is called when the server receives connection init message from the client.
|
||||
// This can be used to check initial payload to see whether to accept the websocket connection.
|
||||
// Deprecated: switch to graphql/handler.New
|
||||
func WebsocketInitFunc(websocketInitFunc transport.WebsocketInitFunc) Option {
|
||||
return func(cfg *Config) {
|
||||
cfg.websocketInitFunc = websocketInitFunc
|
||||
}
|
||||
}
|
||||
|
||||
// CacheSize sets the maximum size of the query cache.
|
||||
// If size is less than or equal to 0, the cache is disabled.
|
||||
// Deprecated: switch to graphql/handler.New
|
||||
func CacheSize(size int) Option {
|
||||
return func(cfg *Config) {
|
||||
cfg.cacheSize = size
|
||||
}
|
||||
}
|
||||
|
||||
// UploadMaxSize sets the maximum number of bytes used to parse a request body
|
||||
// as multipart/form-data.
|
||||
// Deprecated: switch to graphql/handler.New
|
||||
func UploadMaxSize(size int64) Option {
|
||||
return func(cfg *Config) {
|
||||
cfg.uploadMaxSize = size
|
||||
}
|
||||
}
|
||||
|
||||
// UploadMaxMemory sets the maximum number of bytes used to parse a request body
|
||||
// as multipart/form-data in memory, with the remainder stored on disk in
|
||||
// temporary files.
|
||||
// Deprecated: switch to graphql/handler.New
|
||||
func UploadMaxMemory(size int64) Option {
|
||||
return func(cfg *Config) {
|
||||
cfg.uploadMaxMemory = size
|
||||
}
|
||||
}
|
||||
|
||||
// WebsocketKeepAliveDuration allows you to reconfigure the keepalive behavior.
|
||||
// By default, keepalive is enabled with a DefaultConnectionKeepAlivePingInterval
|
||||
// duration. Set handler.connectionKeepAlivePingInterval = 0 to disable keepalive
|
||||
// altogether.
|
||||
// Deprecated: switch to graphql/handler.New
|
||||
func WebsocketKeepAliveDuration(duration time.Duration) Option {
|
||||
return func(cfg *Config) {
|
||||
cfg.connectionKeepAlivePingInterval = duration
|
||||
}
|
||||
}
|
||||
|
||||
// Add cache that will hold queries for automatic persisted queries (APQ)
|
||||
// Deprecated: switch to graphql/handler.New
|
||||
func EnablePersistedQueryCache(cache PersistedQueryCache) Option {
|
||||
return func(cfg *Config) {
|
||||
cfg.apqCache = cache
|
||||
}
|
||||
}
|
||||
|
||||
func GetInitPayload(ctx context.Context) transport.InitPayload {
|
||||
return transport.GetInitPayload(ctx)
|
||||
}
|
||||
|
||||
type apqAdapter struct {
|
||||
PersistedQueryCache
|
||||
}
|
||||
|
||||
func (a apqAdapter) Get(ctx context.Context, key string) (value interface{}, ok bool) {
|
||||
return a.PersistedQueryCache.Get(ctx, key)
|
||||
}
|
||||
func (a apqAdapter) Add(ctx context.Context, key string, value interface{}) {
|
||||
a.PersistedQueryCache.Add(ctx, key, value.(string))
|
||||
}
|
||||
|
||||
type PersistedQueryCache interface {
|
||||
Add(ctx context.Context, hash string, query string)
|
||||
Get(ctx context.Context, hash string) (string, bool)
|
||||
}
|
||||
|
||||
// Deprecated: use playground.Handler instead
|
||||
func Playground(title string, endpoint string) http.HandlerFunc {
|
||||
return playground.Handler(title, endpoint)
|
||||
}
|
||||
|
||||
// Deprecated: use transport.InitPayload instead
|
||||
type InitPayload = transport.InitPayload
|
||||
56
vendor/github.com/99designs/gqlgen/init-templates/gqlgen.yml.gotmpl
generated
vendored
Normal file
56
vendor/github.com/99designs/gqlgen/init-templates/gqlgen.yml.gotmpl
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
# Where are all the schema files located? globs are supported eg src/**/*.graphqls
|
||||
schema:
|
||||
- graph/*.graphqls
|
||||
|
||||
# Where should the generated server code go?
|
||||
exec:
|
||||
filename: graph/generated/generated.go
|
||||
package: generated
|
||||
|
||||
# Uncomment to enable federation
|
||||
# federation:
|
||||
# filename: graph/generated/federation.go
|
||||
# package: generated
|
||||
|
||||
# Where should any generated models go?
|
||||
model:
|
||||
filename: graph/model/models_gen.go
|
||||
package: model
|
||||
|
||||
# Where should the resolver implementations go?
|
||||
resolver:
|
||||
layout: follow-schema
|
||||
dir: graph
|
||||
package: graph
|
||||
|
||||
# Optional: turn on use ` + "`" + `gqlgen:"fieldName"` + "`" + ` tags in your models
|
||||
# struct_tag: json
|
||||
|
||||
# Optional: turn on to use []Thing instead of []*Thing
|
||||
# omit_slice_element_pointers: false
|
||||
|
||||
# Optional: set to speed up generation time by not performing a final validation pass.
|
||||
# skip_validation: true
|
||||
|
||||
# gqlgen will search for any type names in the schema in these go packages
|
||||
# if they match it will use them, otherwise it will generate them.
|
||||
autobind:
|
||||
# - "{{.}}/graph/model"
|
||||
|
||||
# This section declares type mapping between the GraphQL and go type systems
|
||||
#
|
||||
# The first line in each type will be used as defaults for resolver arguments and
|
||||
# modelgen, the others will be allowed when binding to fields. Configure them to
|
||||
# your liking
|
||||
models:
|
||||
ID:
|
||||
model:
|
||||
- github.com/99designs/gqlgen/graphql.ID
|
||||
- github.com/99designs/gqlgen/graphql.Int
|
||||
- github.com/99designs/gqlgen/graphql.Int64
|
||||
- github.com/99designs/gqlgen/graphql.Int32
|
||||
Int:
|
||||
model:
|
||||
- github.com/99designs/gqlgen/graphql.Int
|
||||
- github.com/99designs/gqlgen/graphql.Int64
|
||||
- github.com/99designs/gqlgen/graphql.Int32
|
||||
28
vendor/github.com/99designs/gqlgen/init-templates/schema.graphqls
generated
vendored
Normal file
28
vendor/github.com/99designs/gqlgen/init-templates/schema.graphqls
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
# GraphQL schema example
|
||||
#
|
||||
# https://gqlgen.com/getting-started/
|
||||
|
||||
type Todo {
|
||||
id: ID!
|
||||
text: String!
|
||||
done: Boolean!
|
||||
user: User!
|
||||
}
|
||||
|
||||
type User {
|
||||
id: ID!
|
||||
name: String!
|
||||
}
|
||||
|
||||
type Query {
|
||||
todos: [Todo!]!
|
||||
}
|
||||
|
||||
input NewTodo {
|
||||
text: String!
|
||||
userId: String!
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
createTodo(input: NewTodo!): Todo!
|
||||
}
|
||||
2
vendor/github.com/99designs/gqlgen/internal/code/compare.go
generated
vendored
2
vendor/github.com/99designs/gqlgen/internal/code/compare.go
generated
vendored
@@ -7,8 +7,6 @@ import (
|
||||
|
||||
// CompatibleTypes isnt a strict comparison, it allows for pointer differences
|
||||
func CompatibleTypes(expected types.Type, actual types.Type) error {
|
||||
//fmt.Println("Comparing ", expected.String(), actual.String())
|
||||
|
||||
// Special case to deal with pointer mismatches
|
||||
{
|
||||
expectedPtr, expectedIsPtr := expected.(*types.Pointer)
|
||||
|
||||
84
vendor/github.com/99designs/gqlgen/internal/code/imports.go
generated
vendored
84
vendor/github.com/99designs/gqlgen/internal/code/imports.go
generated
vendored
@@ -45,6 +45,14 @@ func NameForDir(dir string) string {
|
||||
return SanitizePackageName(filepath.Base(dir))
|
||||
}
|
||||
|
||||
type goModuleSearchResult struct {
|
||||
path string
|
||||
goModPath string
|
||||
moduleName string
|
||||
}
|
||||
|
||||
var goModuleRootCache = map[string]goModuleSearchResult{}
|
||||
|
||||
// goModuleRoot returns the root of the current go module if there is a go.mod file in the directory tree
|
||||
// If not, it returns false
|
||||
func goModuleRoot(dir string) (string, bool) {
|
||||
@@ -53,34 +61,74 @@ func goModuleRoot(dir string) (string, bool) {
|
||||
panic(err)
|
||||
}
|
||||
dir = filepath.ToSlash(dir)
|
||||
modDir := dir
|
||||
assumedPart := ""
|
||||
|
||||
dirs := []string{dir}
|
||||
result := goModuleSearchResult{}
|
||||
|
||||
for {
|
||||
f, err := ioutil.ReadFile(filepath.Join(modDir, "go.mod"))
|
||||
if err == nil {
|
||||
// found it, stop searching
|
||||
return string(modregex.FindSubmatch(f)[1]) + assumedPart, true
|
||||
}
|
||||
modDir := dirs[len(dirs)-1]
|
||||
|
||||
assumedPart = "/" + filepath.Base(modDir) + assumedPart
|
||||
parentDir, err := filepath.Abs(filepath.Join(modDir, ".."))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if parentDir == modDir {
|
||||
// Walked all the way to the root and didnt find anything :'(
|
||||
if val, ok := goModuleRootCache[dir]; ok {
|
||||
result = val
|
||||
break
|
||||
}
|
||||
modDir = parentDir
|
||||
|
||||
if content, err := ioutil.ReadFile(filepath.Join(modDir, "go.mod")); err == nil {
|
||||
moduleName := string(modregex.FindSubmatch(content)[1])
|
||||
result = goModuleSearchResult{
|
||||
path: moduleName,
|
||||
goModPath: modDir,
|
||||
moduleName: moduleName,
|
||||
}
|
||||
goModuleRootCache[modDir] = result
|
||||
break
|
||||
}
|
||||
|
||||
if modDir == "" || modDir == "." || modDir == "/" || strings.HasSuffix(modDir, "\\") {
|
||||
// Reached the top of the file tree which means go.mod file is not found
|
||||
// Set root folder with a sentinel cache value
|
||||
goModuleRootCache[modDir] = result
|
||||
break
|
||||
}
|
||||
|
||||
dirs = append(dirs, filepath.Dir(modDir))
|
||||
}
|
||||
return "", false
|
||||
|
||||
// create a cache for each path in a tree traversed, except the top one as it is already cached
|
||||
for _, d := range dirs[:len(dirs)-1] {
|
||||
if result.moduleName == "" {
|
||||
// go.mod is not found in the tree, so the same sentinel value fits all the directories in a tree
|
||||
goModuleRootCache[d] = result
|
||||
} else {
|
||||
if relPath, err := filepath.Rel(result.goModPath, d); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
path := result.moduleName
|
||||
relPath := filepath.ToSlash(relPath)
|
||||
if !strings.HasSuffix(relPath, "/") {
|
||||
path += "/"
|
||||
}
|
||||
path += relPath
|
||||
|
||||
goModuleRootCache[d] = goModuleSearchResult{
|
||||
path: path,
|
||||
goModPath: result.goModPath,
|
||||
moduleName: result.moduleName,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res := goModuleRootCache[dir]
|
||||
if res.moduleName == "" {
|
||||
return "", false
|
||||
}
|
||||
return res.path, true
|
||||
}
|
||||
|
||||
// ImportPathForDir takes a path and returns a golang import path for the package
|
||||
func ImportPathForDir(dir string) (res string) {
|
||||
dir, err := filepath.Abs(dir)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
54
vendor/github.com/99designs/gqlgen/internal/code/packages.go
generated
vendored
54
vendor/github.com/99designs/gqlgen/internal/code/packages.go
generated
vendored
@@ -2,9 +2,12 @@ package code
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/tools/go/packages"
|
||||
)
|
||||
|
||||
@@ -13,7 +16,9 @@ var mode = packages.NeedName |
|
||||
packages.NeedImports |
|
||||
packages.NeedTypes |
|
||||
packages.NeedSyntax |
|
||||
packages.NeedTypesInfo
|
||||
packages.NeedTypesInfo |
|
||||
packages.NeedModule |
|
||||
packages.NeedDeps
|
||||
|
||||
// Packages is a wrapper around x/tools/go/packages that maintains a (hopefully prewarmed) cache of packages
|
||||
// that can be invalidated as writes are made and packages are known to change.
|
||||
@@ -26,6 +31,22 @@ type Packages struct {
|
||||
numNameCalls int // stupid test steam. ignore.
|
||||
}
|
||||
|
||||
// ReloadAll will call LoadAll after clearing the package cache, so we can reload
|
||||
// packages in the case that the packages have changed
|
||||
func (p *Packages) ReloadAll(importPaths ...string) []*packages.Package {
|
||||
p.packages = nil
|
||||
return p.LoadAll(importPaths...)
|
||||
}
|
||||
|
||||
func (p *Packages) checkModuleLoaded(pkgs []*packages.Package) bool {
|
||||
for i := range pkgs {
|
||||
if pkgs[i] == nil || pkgs[i].Module == nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// LoadAll will call packages.Load and return the package data for the given packages,
|
||||
// but if the package already have been loaded it will return cached values instead.
|
||||
func (p *Packages) LoadAll(importPaths ...string) []*packages.Package {
|
||||
@@ -44,6 +65,13 @@ func (p *Packages) LoadAll(importPaths ...string) []*packages.Package {
|
||||
if len(missing) > 0 {
|
||||
p.numLoadCalls++
|
||||
pkgs, err := packages.Load(&packages.Config{Mode: mode}, missing...)
|
||||
|
||||
// Sometimes packages.Load not loaded the module info. Call it again to reload it.
|
||||
if !p.checkModuleLoaded(pkgs) {
|
||||
fmt.Println("reloading module info")
|
||||
pkgs, err = packages.Load(&packages.Config{Mode: mode}, missing...)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
p.loadErrors = append(p.loadErrors, err)
|
||||
}
|
||||
@@ -72,6 +100,13 @@ func (p *Packages) addToCache(pkg *packages.Package) {
|
||||
|
||||
// Load works the same as LoadAll, except a single package at a time.
|
||||
func (p *Packages) Load(importPath string) *packages.Package {
|
||||
// Quick cache check first to avoid expensive allocations of LoadAll()
|
||||
if p.packages != nil {
|
||||
if pkg, ok := p.packages[importPath]; ok {
|
||||
return pkg
|
||||
}
|
||||
}
|
||||
|
||||
pkgs := p.LoadAll(importPath)
|
||||
if len(pkgs) == 0 {
|
||||
return nil
|
||||
@@ -149,6 +184,17 @@ func (p *Packages) Evict(importPath string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Packages) ModTidy() error {
|
||||
p.packages = nil
|
||||
tidyCmd := exec.Command("go", "mod", "tidy")
|
||||
tidyCmd.Stdout = os.Stdout
|
||||
tidyCmd.Stderr = os.Stdout
|
||||
if err := tidyCmd.Run(); err != nil {
|
||||
return fmt.Errorf("go mod tidy failed: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Errors returns any errors that were returned by Load, either from the call itself or any of the loaded packages.
|
||||
func (p *Packages) Errors() PkgErrors {
|
||||
var res []error //nolint:prealloc
|
||||
@@ -161,6 +207,10 @@ func (p *Packages) Errors() PkgErrors {
|
||||
return res
|
||||
}
|
||||
|
||||
func (p *Packages) Count() int {
|
||||
return len(p.packages)
|
||||
}
|
||||
|
||||
type PkgErrors []error
|
||||
|
||||
func (p PkgErrors) Error() string {
|
||||
|
||||
2
vendor/github.com/99designs/gqlgen/internal/rewrite/rewriter.go
generated
vendored
2
vendor/github.com/99designs/gqlgen/internal/rewrite/rewriter.go
generated
vendored
@@ -58,7 +58,7 @@ func (r *Rewriter) getFile(filename string) string {
|
||||
if _, ok := r.files[filename]; !ok {
|
||||
b, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("unable to load file, already exists: %s", err.Error()))
|
||||
panic(fmt.Errorf("unable to load file, already exists: %w", err))
|
||||
}
|
||||
|
||||
r.files[filename] = string(b)
|
||||
|
||||
187
vendor/github.com/99designs/gqlgen/main.go
generated
vendored
187
vendor/github.com/99designs/gqlgen/main.go
generated
vendored
@@ -1,9 +1,190 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/99designs/gqlgen/cmd"
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/99designs/gqlgen/api"
|
||||
"github.com/99designs/gqlgen/codegen/config"
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/99designs/gqlgen/internal/code"
|
||||
"github.com/99designs/gqlgen/plugin/servergen"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cmd.Execute()
|
||||
//go:embed init-templates/schema.graphqls
|
||||
var schemaFileContent string
|
||||
|
||||
//go:embed init-templates/gqlgen.yml.gotmpl
|
||||
var configFileTemplate string
|
||||
|
||||
func getConfigFileContent(pkgName string) string {
|
||||
var buf bytes.Buffer
|
||||
if err := template.Must(template.New("gqlgen.yml").Parse(configFileTemplate)).Execute(&buf, pkgName); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func fileExists(filename string) bool {
|
||||
_, err := os.Stat(filename)
|
||||
return !errors.Is(err, fs.ErrNotExist)
|
||||
}
|
||||
|
||||
func initFile(filename, contents string) error {
|
||||
if err := os.MkdirAll(filepath.Dir(filename), 0o755); err != nil {
|
||||
return fmt.Errorf("unable to create directory for file '%s': %w\n", filename, err)
|
||||
}
|
||||
if err := ioutil.WriteFile(filename, []byte(contents), 0o644); err != nil {
|
||||
return fmt.Errorf("unable to write file '%s': %w\n", filename, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var initCmd = &cli.Command{
|
||||
Name: "init",
|
||||
Usage: "create a new gqlgen project",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{Name: "verbose, v", Usage: "show logs"},
|
||||
&cli.StringFlag{Name: "config, c", Usage: "the config filename", Value: "gqlgen.yml"},
|
||||
&cli.StringFlag{Name: "server", Usage: "where to write the server stub to", Value: "server.go"},
|
||||
&cli.StringFlag{Name: "schema", Usage: "where to write the schema stub to", Value: "graph/schema.graphqls"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) error {
|
||||
configFilename := ctx.String("config")
|
||||
serverFilename := ctx.String("server")
|
||||
schemaFilename := ctx.String("schema")
|
||||
|
||||
pkgName := code.ImportPathForDir(".")
|
||||
if pkgName == "" {
|
||||
return fmt.Errorf("unable to determine import path for current directory, you probably need to run 'go mod init' first")
|
||||
}
|
||||
|
||||
// check schema and config don't already exist
|
||||
for _, filename := range []string{configFilename, schemaFilename, serverFilename} {
|
||||
if fileExists(filename) {
|
||||
return fmt.Errorf("%s already exists", filename)
|
||||
}
|
||||
}
|
||||
_, err := config.LoadConfigFromDefaultLocations()
|
||||
if err == nil {
|
||||
return fmt.Errorf("gqlgen.yml already exists in a parent directory\n")
|
||||
}
|
||||
|
||||
// create config
|
||||
fmt.Println("Creating", configFilename)
|
||||
if err := initFile(configFilename, getConfigFileContent(pkgName)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// create schema
|
||||
fmt.Println("Creating", schemaFilename)
|
||||
|
||||
if err := initFile(schemaFilename, schemaFileContent); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// create the package directory with a temporary file so that go recognises it as a package
|
||||
// and autobinding doesn't error out
|
||||
tmpPackageNameFile := "graph/model/_tmp_gqlgen_init.go"
|
||||
if err := initFile(tmpPackageNameFile, "package model"); err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.Remove(tmpPackageNameFile)
|
||||
|
||||
var cfg *config.Config
|
||||
if cfg, err = config.LoadConfig(configFilename); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Println("Creating", serverFilename)
|
||||
fmt.Println("Generating...")
|
||||
if err := api.Generate(cfg, api.AddPlugin(servergen.New(serverFilename))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("\nExec \"go run ./%s\" to start GraphQL server\n", serverFilename)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var generateCmd = &cli.Command{
|
||||
Name: "generate",
|
||||
Usage: "generate a graphql server based on schema",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{Name: "verbose, v", Usage: "show logs"},
|
||||
&cli.StringFlag{Name: "config, c", Usage: "the config filename"},
|
||||
},
|
||||
Action: func(ctx *cli.Context) error {
|
||||
var cfg *config.Config
|
||||
var err error
|
||||
if configFilename := ctx.String("config"); configFilename != "" {
|
||||
cfg, err = config.LoadConfig(configFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
cfg, err = config.LoadConfigFromDefaultLocations()
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
cfg, err = config.LoadDefaultConfig()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err = api.Generate(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var versionCmd = &cli.Command{
|
||||
Name: "version",
|
||||
Usage: "print the version string",
|
||||
Action: func(ctx *cli.Context) error {
|
||||
fmt.Println(graphql.Version)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func main() {
|
||||
app := cli.NewApp()
|
||||
app.Name = "gqlgen"
|
||||
app.Usage = generateCmd.Usage
|
||||
app.Description = "This is a library for quickly creating strictly typed graphql servers in golang. See https://gqlgen.com/ for a getting started guide."
|
||||
app.HideVersion = true
|
||||
app.Flags = generateCmd.Flags
|
||||
app.Version = graphql.Version
|
||||
app.Before = func(context *cli.Context) error {
|
||||
if context.Bool("verbose") {
|
||||
log.SetFlags(0)
|
||||
} else {
|
||||
log.SetOutput(ioutil.Discard)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
app.Action = generateCmd.Action
|
||||
app.Commands = []*cli.Command{
|
||||
generateCmd,
|
||||
initCmd,
|
||||
versionCmd,
|
||||
}
|
||||
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
fmt.Fprint(os.Stderr, err.Error()+"\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
349
vendor/github.com/99designs/gqlgen/plugin/federation/federation.go
generated
vendored
349
vendor/github.com/99designs/gqlgen/plugin/federation/federation.go
generated
vendored
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/99designs/gqlgen/codegen/config"
|
||||
"github.com/99designs/gqlgen/codegen/templates"
|
||||
"github.com/99designs/gqlgen/plugin"
|
||||
"github.com/99designs/gqlgen/plugin/federation/fieldset"
|
||||
)
|
||||
|
||||
type federation struct {
|
||||
@@ -75,8 +76,8 @@ scalar _FieldSet
|
||||
directive @external on FIELD_DEFINITION
|
||||
directive @requires(fields: _FieldSet!) on FIELD_DEFINITION
|
||||
directive @provides(fields: _FieldSet!) on FIELD_DEFINITION
|
||||
directive @key(fields: _FieldSet!) on OBJECT | INTERFACE
|
||||
directive @extends on OBJECT
|
||||
directive @key(fields: _FieldSet!) repeatable on OBJECT | INTERFACE
|
||||
directive @extends on OBJECT | INTERFACE
|
||||
`,
|
||||
BuiltIn: true,
|
||||
}
|
||||
@@ -87,87 +88,109 @@ directive @extends on OBJECT
|
||||
func (f *federation) InjectSourceLate(schema *ast.Schema) *ast.Source {
|
||||
f.setEntities(schema)
|
||||
|
||||
entities := ""
|
||||
resolvers := ""
|
||||
var entities, resolvers, entityResolverInputDefinitions string
|
||||
for i, e := range f.Entities {
|
||||
if i != 0 {
|
||||
entities += " | "
|
||||
}
|
||||
entities += e.Name
|
||||
|
||||
if e.ResolverName != "" {
|
||||
resolverArgs := ""
|
||||
for _, field := range e.KeyFields {
|
||||
resolverArgs += fmt.Sprintf("%s: %s,", field.Field.Name, field.Field.Type.String())
|
||||
for _, r := range e.Resolvers {
|
||||
if e.Multi {
|
||||
if entityResolverInputDefinitions != "" {
|
||||
entityResolverInputDefinitions += "\n\n"
|
||||
}
|
||||
entityResolverInputDefinitions += "input " + r.InputType + " {\n"
|
||||
for _, keyField := range r.KeyFields {
|
||||
entityResolverInputDefinitions += fmt.Sprintf("\t%s: %s\n", keyField.Field.ToGo(), keyField.Definition.Type.String())
|
||||
}
|
||||
entityResolverInputDefinitions += "}"
|
||||
resolvers += fmt.Sprintf("\t%s(reps: [%s!]!): [%s]\n", r.ResolverName, r.InputType, e.Name)
|
||||
} else {
|
||||
resolverArgs := ""
|
||||
for _, keyField := range r.KeyFields {
|
||||
resolverArgs += fmt.Sprintf("%s: %s,", keyField.Field.ToGoPrivate(), keyField.Definition.Type.String())
|
||||
}
|
||||
resolvers += fmt.Sprintf("\t%s(%s): %s!\n", r.ResolverName, resolverArgs, e.Name)
|
||||
}
|
||||
resolvers += fmt.Sprintf("\t%s(%s): %s!\n", e.ResolverName, resolverArgs, e.Def.Name)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if len(f.Entities) == 0 {
|
||||
// It's unusual for a service not to have any entities, but
|
||||
// possible if it only exports top-level queries and mutations.
|
||||
return nil
|
||||
var blocks []string
|
||||
if entities != "" {
|
||||
entities = `# a union of all types that use the @key directive
|
||||
union _Entity = ` + entities
|
||||
blocks = append(blocks, entities)
|
||||
}
|
||||
|
||||
// resolvers can be empty if a service defines only "empty
|
||||
// extend" types. This should be rare.
|
||||
if resolvers != "" {
|
||||
resolvers = `
|
||||
# fake type to build resolver interfaces for users to implement
|
||||
if entityResolverInputDefinitions != "" {
|
||||
blocks = append(blocks, entityResolverInputDefinitions)
|
||||
}
|
||||
resolvers = `# fake type to build resolver interfaces for users to implement
|
||||
type Entity {
|
||||
` + resolvers + `
|
||||
}
|
||||
}`
|
||||
blocks = append(blocks, resolvers)
|
||||
}
|
||||
|
||||
_serviceTypeDef := `type _Service {
|
||||
sdl: String
|
||||
}`
|
||||
blocks = append(blocks, _serviceTypeDef)
|
||||
|
||||
var additionalQueryFields string
|
||||
// Quote from the Apollo Federation subgraph specification:
|
||||
// If no types are annotated with the key directive, then the
|
||||
// _Entity union and _entities field should be removed from the schema
|
||||
if len(f.Entities) > 0 {
|
||||
additionalQueryFields += ` _entities(representations: [_Any!]!): [_Entity]!
|
||||
`
|
||||
}
|
||||
// _service field is required in any case
|
||||
additionalQueryFields += ` _service: _Service!`
|
||||
|
||||
extendTypeQueryDef := `extend type ` + schema.Query.Name + ` {
|
||||
` + additionalQueryFields + `
|
||||
}`
|
||||
blocks = append(blocks, extendTypeQueryDef)
|
||||
|
||||
return &ast.Source{
|
||||
Name: "federation/entity.graphql",
|
||||
BuiltIn: true,
|
||||
Input: `
|
||||
# a union of all types that use the @key directive
|
||||
union _Entity = ` + entities + `
|
||||
` + resolvers + `
|
||||
type _Service {
|
||||
sdl: String
|
||||
}
|
||||
|
||||
extend type Query {
|
||||
_entities(representations: [_Any!]!): [_Entity]!
|
||||
_service: _Service!
|
||||
}
|
||||
`,
|
||||
Input: "\n" + strings.Join(blocks, "\n\n") + "\n",
|
||||
}
|
||||
}
|
||||
|
||||
// Entity represents a federated type
|
||||
// that was declared in the GQL schema.
|
||||
type Entity struct {
|
||||
Name string // The same name as the type declaration
|
||||
KeyFields []*KeyField // The fields declared in @key.
|
||||
Name string // The same name as the type declaration
|
||||
Def *ast.Definition
|
||||
Resolvers []*EntityResolver
|
||||
Requires []*Requires
|
||||
Multi bool
|
||||
}
|
||||
|
||||
type EntityResolver struct {
|
||||
ResolverName string // The resolver name, such as FindUserByID
|
||||
Def *ast.Definition
|
||||
Requires []*Requires
|
||||
KeyFields []*KeyField // The fields declared in @key.
|
||||
InputType string // The Go generated input type for multi entity resolvers
|
||||
}
|
||||
|
||||
type KeyField struct {
|
||||
Field *ast.FieldDefinition
|
||||
TypeReference *config.TypeReference // The Go representation of that field type
|
||||
Definition *ast.FieldDefinition
|
||||
Field fieldset.Field // len > 1 for nested fields
|
||||
Type *config.TypeReference // The Go representation of that field type
|
||||
}
|
||||
|
||||
// Requires represents an @requires clause
|
||||
type Requires struct {
|
||||
Name string // the name of the field
|
||||
Fields []*RequireField // the name of the sibling fields
|
||||
}
|
||||
|
||||
// RequireField is similar to an entity but it is a field not
|
||||
// an object
|
||||
type RequireField struct {
|
||||
Name string // The same name as the type declaration
|
||||
NameGo string // The Go struct field name
|
||||
TypeReference *config.TypeReference // The Go representation of that field type
|
||||
Name string // the name of the field
|
||||
Field fieldset.Field // source Field, len > 1 for nested fields
|
||||
Type *config.TypeReference // The Go representation of that field type
|
||||
}
|
||||
|
||||
func (e *Entity) allFieldsAreExternal() bool {
|
||||
@@ -186,23 +209,32 @@ func (f *federation) GenerateCode(data *codegen.Data) error {
|
||||
}
|
||||
for _, e := range f.Entities {
|
||||
obj := data.Objects.ByName(e.Def.Name)
|
||||
for _, field := range obj.Fields {
|
||||
// Storing key fields in a slice rather than a map
|
||||
// to preserve insertion order at the tradeoff of higher
|
||||
// lookup complexity.
|
||||
keyField := f.getKeyField(e.KeyFields, field.Name)
|
||||
if keyField != nil {
|
||||
keyField.TypeReference = field.TypeReference
|
||||
}
|
||||
for _, r := range e.Requires {
|
||||
for _, rf := range r.Fields {
|
||||
if rf.Name == field.Name {
|
||||
rf.TypeReference = field.TypeReference
|
||||
rf.NameGo = field.GoFieldName
|
||||
}
|
||||
|
||||
for _, r := range e.Resolvers {
|
||||
// fill in types for key fields
|
||||
//
|
||||
for _, keyField := range r.KeyFields {
|
||||
if len(keyField.Field) == 0 {
|
||||
fmt.Println(
|
||||
"skipping @key field " + keyField.Definition.Name + " in " + r.ResolverName + " in " + e.Def.Name,
|
||||
)
|
||||
continue
|
||||
}
|
||||
cgField := keyField.Field.TypeReference(obj, data.Objects)
|
||||
keyField.Type = cgField.TypeReference
|
||||
}
|
||||
}
|
||||
|
||||
// fill in types for requires fields
|
||||
//
|
||||
for _, reqField := range e.Requires {
|
||||
if len(reqField.Field) == 0 {
|
||||
fmt.Println("skipping @requires field " + reqField.Name + " in " + e.Def.Name)
|
||||
continue
|
||||
}
|
||||
cgField := reqField.Field.TypeReference(obj, data.Objects)
|
||||
reqField.Type = cgField.TypeReference
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,93 +247,103 @@ func (f *federation) GenerateCode(data *codegen.Data) error {
|
||||
})
|
||||
}
|
||||
|
||||
func (f *federation) getKeyField(keyFields []*KeyField, fieldName string) *KeyField {
|
||||
for _, field := range keyFields {
|
||||
if field.Field.Name == fieldName {
|
||||
return field
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *federation) setEntities(schema *ast.Schema) {
|
||||
for _, schemaType := range schema.Types {
|
||||
if schemaType.Kind == ast.Object {
|
||||
dir := schemaType.Directives.ForName("key") // TODO: interfaces
|
||||
if dir != nil {
|
||||
if len(dir.Arguments) > 1 {
|
||||
panic("Multiple arguments are not currently supported in @key declaration.")
|
||||
}
|
||||
fieldName := dir.Arguments[0].Value.Raw // TODO: multiple arguments
|
||||
if strings.Contains(fieldName, "{") {
|
||||
panic("Nested fields are not currently supported in @key declaration.")
|
||||
}
|
||||
keys, ok := isFederatedEntity(schemaType)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
e := &Entity{
|
||||
Name: schemaType.Name,
|
||||
Def: schemaType,
|
||||
Resolvers: nil,
|
||||
Requires: nil,
|
||||
}
|
||||
|
||||
requires := []*Requires{}
|
||||
for _, f := range schemaType.Fields {
|
||||
dir := f.Directives.ForName("requires")
|
||||
if dir == nil {
|
||||
continue
|
||||
}
|
||||
fields := strings.Split(dir.Arguments[0].Value.Raw, " ")
|
||||
requireFields := []*RequireField{}
|
||||
for _, f := range fields {
|
||||
requireFields = append(requireFields, &RequireField{
|
||||
Name: f,
|
||||
})
|
||||
}
|
||||
requires = append(requires, &Requires{
|
||||
Name: f.Name,
|
||||
Fields: requireFields,
|
||||
})
|
||||
// Let's process custom entity resolver settings.
|
||||
dir := schemaType.Directives.ForName("entityResolver")
|
||||
if dir != nil {
|
||||
if dirArg := dir.Arguments.ForName("multi"); dirArg != nil {
|
||||
if dirVal, err := dirArg.Value.Value(nil); err == nil {
|
||||
e.Multi = dirVal.(bool)
|
||||
}
|
||||
|
||||
fieldNames := strings.Split(fieldName, " ")
|
||||
keyFields := make([]*KeyField, len(fieldNames))
|
||||
resolverName := fmt.Sprintf("find%sBy", schemaType.Name)
|
||||
for i, f := range fieldNames {
|
||||
field := schemaType.Fields.ForName(f)
|
||||
|
||||
keyFields[i] = &KeyField{Field: field}
|
||||
if i > 0 {
|
||||
resolverName += "And"
|
||||
}
|
||||
resolverName += templates.ToGo(f)
|
||||
|
||||
}
|
||||
|
||||
e := &Entity{
|
||||
Name: schemaType.Name,
|
||||
KeyFields: keyFields,
|
||||
Def: schemaType,
|
||||
ResolverName: resolverName,
|
||||
Requires: requires,
|
||||
}
|
||||
// If our schema has a field with a type defined in
|
||||
// another service, then we need to define an "empty
|
||||
// extend" of that type in this service, so this service
|
||||
// knows what the type is like. But the graphql-server
|
||||
// will never ask us to actually resolve this "empty
|
||||
// extend", so we don't require a resolver function for
|
||||
// it. (Well, it will never ask in practice; it's
|
||||
// unclear whether the spec guarantees this. See
|
||||
// https://github.com/apollographql/apollo-server/issues/3852
|
||||
// ). Example:
|
||||
// type MyType {
|
||||
// myvar: TypeDefinedInOtherService
|
||||
// }
|
||||
// // Federation needs this type, but
|
||||
// // it doesn't need a resolver for it!
|
||||
// extend TypeDefinedInOtherService @key(fields: "id") {
|
||||
// id: ID @external
|
||||
// }
|
||||
if e.allFieldsAreExternal() {
|
||||
e.ResolverName = ""
|
||||
}
|
||||
|
||||
f.Entities = append(f.Entities, e)
|
||||
}
|
||||
}
|
||||
|
||||
// If our schema has a field with a type defined in
|
||||
// another service, then we need to define an "empty
|
||||
// extend" of that type in this service, so this service
|
||||
// knows what the type is like. But the graphql-server
|
||||
// will never ask us to actually resolve this "empty
|
||||
// extend", so we don't require a resolver function for
|
||||
// it. (Well, it will never ask in practice; it's
|
||||
// unclear whether the spec guarantees this. See
|
||||
// https://github.com/apollographql/apollo-server/issues/3852
|
||||
// ). Example:
|
||||
// type MyType {
|
||||
// myvar: TypeDefinedInOtherService
|
||||
// }
|
||||
// // Federation needs this type, but
|
||||
// // it doesn't need a resolver for it!
|
||||
// extend TypeDefinedInOtherService @key(fields: "id") {
|
||||
// id: ID @external
|
||||
// }
|
||||
if !e.allFieldsAreExternal() {
|
||||
for _, dir := range keys {
|
||||
if len(dir.Arguments) != 1 || dir.Arguments[0].Name != "fields" {
|
||||
panic("Exactly one `fields` argument needed for @key declaration.")
|
||||
}
|
||||
arg := dir.Arguments[0]
|
||||
keyFieldSet := fieldset.New(arg.Value.Raw, nil)
|
||||
|
||||
keyFields := make([]*KeyField, len(keyFieldSet))
|
||||
resolverFields := []string{}
|
||||
for i, field := range keyFieldSet {
|
||||
def := field.FieldDefinition(schemaType, schema)
|
||||
|
||||
if def == nil {
|
||||
panic(fmt.Sprintf("no field for %v", field))
|
||||
}
|
||||
|
||||
keyFields[i] = &KeyField{Definition: def, Field: field}
|
||||
resolverFields = append(resolverFields, keyFields[i].Field.ToGo())
|
||||
}
|
||||
|
||||
resolverFieldsToGo := schemaType.Name + "By" + strings.Join(resolverFields, "And")
|
||||
var resolverName string
|
||||
if e.Multi {
|
||||
resolverFieldsToGo += "s" // Pluralize for better API readability
|
||||
resolverName = fmt.Sprintf("findMany%s", resolverFieldsToGo)
|
||||
} else {
|
||||
resolverName = fmt.Sprintf("find%s", resolverFieldsToGo)
|
||||
}
|
||||
|
||||
e.Resolvers = append(e.Resolvers, &EntityResolver{
|
||||
ResolverName: resolverName,
|
||||
KeyFields: keyFields,
|
||||
InputType: resolverFieldsToGo + "Input",
|
||||
})
|
||||
}
|
||||
|
||||
e.Requires = []*Requires{}
|
||||
for _, f := range schemaType.Fields {
|
||||
dir := f.Directives.ForName("requires")
|
||||
if dir == nil {
|
||||
continue
|
||||
}
|
||||
if len(dir.Arguments) != 1 || dir.Arguments[0].Name != "fields" {
|
||||
panic("Exactly one `fields` argument needed for @requires declaration.")
|
||||
}
|
||||
requiresFieldSet := fieldset.New(dir.Arguments[0].Value.Raw, nil)
|
||||
for _, field := range requiresFieldSet {
|
||||
e.Requires = append(e.Requires, &Requires{
|
||||
Name: field.ToGoPrivate(),
|
||||
Field: field,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
f.Entities = append(f.Entities, e)
|
||||
}
|
||||
|
||||
// make sure order remains stable across multiple builds
|
||||
@@ -309,3 +351,28 @@ func (f *federation) setEntities(schema *ast.Schema) {
|
||||
return f.Entities[i].Name < f.Entities[j].Name
|
||||
})
|
||||
}
|
||||
|
||||
func isFederatedEntity(schemaType *ast.Definition) ([]*ast.Directive, bool) {
|
||||
switch schemaType.Kind {
|
||||
case ast.Object:
|
||||
keys := schemaType.Directives.ForNames("key")
|
||||
if len(keys) > 0 {
|
||||
return keys, true
|
||||
}
|
||||
case ast.Interface:
|
||||
// TODO: support @key and @extends for interfaces
|
||||
if dir := schemaType.Directives.ForName("key"); dir != nil {
|
||||
fmt.Printf("@key directive found on \"interface %s\". Will be ignored.\n", schemaType.Name)
|
||||
}
|
||||
if dir := schemaType.Directives.ForName("extends"); dir != nil {
|
||||
panic(
|
||||
fmt.Sprintf(
|
||||
"@extends directive is not currently supported for interfaces, use \"extend interface %s\" instead.",
|
||||
schemaType.Name,
|
||||
))
|
||||
}
|
||||
default:
|
||||
// ignore
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
266
vendor/github.com/99designs/gqlgen/plugin/federation/federation.gotpl
generated
vendored
266
vendor/github.com/99designs/gqlgen/plugin/federation/federation.gotpl
generated
vendored
@@ -2,9 +2,15 @@
|
||||
{{ reserveImport "errors" }}
|
||||
{{ reserveImport "fmt" }}
|
||||
{{ reserveImport "strings" }}
|
||||
{{ reserveImport "sync" }}
|
||||
|
||||
{{ reserveImport "github.com/99designs/gqlgen/plugin/federation/fedruntime" }}
|
||||
|
||||
var (
|
||||
ErrUnknownType = errors.New("unknown type")
|
||||
ErrTypeNotFound = errors.New("type not found")
|
||||
)
|
||||
|
||||
func (ec *executionContext) __resolve__service(ctx context.Context) (fedruntime.Service, error) {
|
||||
if ec.DisableIntrospection {
|
||||
return fedruntime.Service{}, errors.New("federated introspection disabled")
|
||||
@@ -25,45 +31,229 @@ func (ec *executionContext) __resolve__service(ctx context.Context) (fedruntime.
|
||||
}
|
||||
|
||||
{{if .Entities}}
|
||||
func (ec *executionContext) __resolve_entities(ctx context.Context, representations []map[string]interface{}) ([]fedruntime.Entity, error) {
|
||||
list := []fedruntime.Entity{}
|
||||
for _, rep := range representations {
|
||||
typeName, ok := rep["__typename"].(string)
|
||||
if !ok {
|
||||
return nil, errors.New("__typename must be an existing string")
|
||||
}
|
||||
switch typeName {
|
||||
{{ range .Entities }}
|
||||
{{ if .ResolverName }}
|
||||
case "{{.Def.Name}}":
|
||||
{{ range $i, $keyField := .KeyFields -}}
|
||||
id{{$i}}, err := ec.{{.TypeReference.UnmarshalFunc}}(ctx, rep["{{$keyField.Field.Name}}"])
|
||||
if err != nil {
|
||||
return nil, errors.New(fmt.Sprintf("Field %s undefined in schema.", "{{$keyField.Field.Name}}"))
|
||||
}
|
||||
{{end}}
|
||||
|
||||
entity, err := ec.resolvers.Entity().{{.ResolverName | go}}(ctx,
|
||||
{{ range $i, $_ := .KeyFields -}} id{{$i}}, {{end}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
{{ range .Requires }}
|
||||
{{ range .Fields}}
|
||||
entity.{{.NameGo}}, err = ec.{{.TypeReference.UnmarshalFunc}}(ctx, rep["{{.Name}}"])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
list = append(list, entity)
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
default:
|
||||
return nil, errors.New("unknown type: "+typeName)
|
||||
func (ec *executionContext) __resolve_entities(ctx context.Context, representations []map[string]interface{}) []fedruntime.Entity {
|
||||
list := make([]fedruntime.Entity, len(representations))
|
||||
|
||||
repsMap := map[string]struct {
|
||||
i []int
|
||||
r []map[string]interface{}
|
||||
}{}
|
||||
|
||||
// We group entities by typename so that we can parallelize their resolution.
|
||||
// This is particularly helpful when there are entity groups in multi mode.
|
||||
buildRepresentationGroups := func(reps []map[string]interface{}) {
|
||||
for i, rep := range reps {
|
||||
typeName, ok := rep["__typename"].(string)
|
||||
if !ok {
|
||||
// If there is no __typename, we just skip the representation;
|
||||
// we just won't be resolving these unknown types.
|
||||
ec.Error(ctx, errors.New("__typename must be an existing string"))
|
||||
continue
|
||||
}
|
||||
|
||||
_r := repsMap[typeName]
|
||||
_r.i = append(_r.i, i)
|
||||
_r.r = append(_r.r, rep)
|
||||
repsMap[typeName] = _r
|
||||
}
|
||||
}
|
||||
return list, nil
|
||||
|
||||
isMulti := func(typeName string) bool {
|
||||
switch typeName {
|
||||
{{- range .Entities -}}
|
||||
{{- if .Resolvers -}}
|
||||
{{- if .Multi -}}
|
||||
case "{{.Def.Name}}":
|
||||
return true
|
||||
{{ end }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
resolveEntity := func(ctx context.Context, typeName string, rep map[string]interface{}, idx []int, i int) (err error) {
|
||||
// we need to do our own panic handling, because we may be called in a
|
||||
// goroutine, where the usual panic handling can't catch us
|
||||
defer func () {
|
||||
if r := recover(); r != nil {
|
||||
err = ec.Recover(ctx, r)
|
||||
}
|
||||
}()
|
||||
|
||||
switch typeName {
|
||||
{{ range $_, $entity := .Entities }}
|
||||
{{- if and .Resolvers (not .Multi) -}}
|
||||
case "{{.Def.Name}}":
|
||||
resolverName, err := entityResolverNameFor{{.Def.Name}}(ctx, rep)
|
||||
if err != nil {
|
||||
return fmt.Errorf(`finding resolver for Entity "{{.Def.Name}}": %w`, err)
|
||||
}
|
||||
switch resolverName {
|
||||
{{ range $i, $resolver := .Resolvers }}
|
||||
case "{{.ResolverName}}":
|
||||
{{- range $j, $keyField := .KeyFields }}
|
||||
id{{$j}}, err := ec.{{.Type.UnmarshalFunc}}(ctx, rep["{{.Field.Join `"].(map[string]interface{})["`}}"])
|
||||
if err != nil {
|
||||
return fmt.Errorf(`unmarshalling param {{$j}} for {{$resolver.ResolverName}}(): %w`, err)
|
||||
}
|
||||
{{- end}}
|
||||
entity, err := ec.resolvers.Entity().{{.ResolverName | go}}(ctx, {{- range $j, $_ := .KeyFields -}} id{{$j}}, {{end}})
|
||||
if err != nil {
|
||||
return fmt.Errorf(`resolving Entity "{{$entity.Def.Name}}": %w`, err)
|
||||
}
|
||||
{{ range $entity.Requires }}
|
||||
entity.{{.Field.JoinGo `.`}}, err = ec.{{.Type.UnmarshalFunc}}(ctx, rep["{{.Field.Join `"].(map[string]interface{})["`}}"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
{{- end }}
|
||||
list[idx[i]] = entity
|
||||
return nil
|
||||
{{- end }}
|
||||
}
|
||||
{{ end }}
|
||||
{{- end }}
|
||||
}
|
||||
return fmt.Errorf("%w: %s", ErrUnknownType, typeName)
|
||||
}
|
||||
|
||||
resolveManyEntities := func(ctx context.Context, typeName string, reps []map[string]interface{}, idx []int) (err error) {
|
||||
// we need to do our own panic handling, because we may be called in a
|
||||
// goroutine, where the usual panic handling can't catch us
|
||||
defer func () {
|
||||
if r := recover(); r != nil {
|
||||
err = ec.Recover(ctx, r)
|
||||
}
|
||||
}()
|
||||
|
||||
switch typeName {
|
||||
{{ range $_, $entity := .Entities }}
|
||||
{{ if and .Resolvers .Multi -}}
|
||||
case "{{.Def.Name}}":
|
||||
{{range $i, $_ := .Resolvers -}}
|
||||
_reps := make([]*{{.InputType}}, len(reps))
|
||||
|
||||
for i, rep := range reps {
|
||||
{{ range $i, $keyField := .KeyFields -}}
|
||||
id{{$i}}, err := ec.{{.Type.UnmarshalFunc}}(ctx, rep["{{.Field.Join `"].(map[string]interface{})["`}}"])
|
||||
if err != nil {
|
||||
return errors.New(fmt.Sprintf("Field %s undefined in schema.", "{{.Definition.Name}}"))
|
||||
}
|
||||
{{end}}
|
||||
|
||||
_reps[i] = &{{.InputType}} {
|
||||
{{ range $i, $keyField := .KeyFields -}}
|
||||
{{$keyField.Field.ToGo}}: id{{$i}},
|
||||
{{end}}
|
||||
}
|
||||
}
|
||||
|
||||
entities, err := ec.resolvers.Entity().{{.ResolverName | go}}(ctx, _reps)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i, entity := range entities {
|
||||
{{- range $entity.Requires }}
|
||||
entity.{{.Field.JoinGo `.`}}, err = ec.{{.Type.UnmarshalFunc}}(ctx, reps[i]["{{.Field.Join `"].(map[string]interface{})["`}}"])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
{{- end}}
|
||||
list[idx[i]] = entity
|
||||
}
|
||||
return nil
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{- end }}
|
||||
default:
|
||||
return errors.New("unknown type: "+typeName)
|
||||
}
|
||||
}
|
||||
|
||||
resolveEntityGroup := func(typeName string, reps []map[string]interface{}, idx []int) {
|
||||
if isMulti(typeName) {
|
||||
err := resolveManyEntities(ctx, typeName, reps, idx)
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
}
|
||||
} else {
|
||||
// if there are multiple entities to resolve, parallelize (similar to
|
||||
// graphql.FieldSet.Dispatch)
|
||||
var e sync.WaitGroup
|
||||
e.Add(len(reps))
|
||||
for i, rep := range reps {
|
||||
i, rep := i, rep
|
||||
go func(i int, rep map[string]interface{}) {
|
||||
err := resolveEntity(ctx, typeName, rep, idx, i)
|
||||
if err != nil {
|
||||
ec.Error(ctx, err)
|
||||
}
|
||||
e.Done()
|
||||
}(i, rep)
|
||||
}
|
||||
e.Wait()
|
||||
}
|
||||
}
|
||||
buildRepresentationGroups(representations)
|
||||
|
||||
switch len(repsMap) {
|
||||
case 0:
|
||||
return list
|
||||
case 1:
|
||||
for typeName, reps := range repsMap {
|
||||
resolveEntityGroup(typeName, reps.r, reps.i)
|
||||
}
|
||||
return list
|
||||
default:
|
||||
var g sync.WaitGroup
|
||||
g.Add(len(repsMap))
|
||||
for typeName, reps := range repsMap {
|
||||
go func(typeName string, reps []map[string]interface{}, idx []int) {
|
||||
resolveEntityGroup(typeName, reps, idx)
|
||||
g.Done()
|
||||
}(typeName, reps.r, reps.i)
|
||||
}
|
||||
g.Wait()
|
||||
return list
|
||||
}
|
||||
}
|
||||
|
||||
{{- /* Make sure the required fields are in the given entity representation and return the name of the proper resolver. */ -}}
|
||||
|
||||
{{ range $_, $entity := .Entities }}
|
||||
{{- if .Resolvers }}
|
||||
|
||||
func entityResolverNameFor{{$entity.Name}}(ctx context.Context, rep map[string]interface{}) (string, error) {
|
||||
{{- range .Resolvers }}
|
||||
for {
|
||||
var (
|
||||
m map[string]interface{}
|
||||
val interface{}
|
||||
ok bool
|
||||
)
|
||||
_ = val
|
||||
{{- range $_, $keyField := .KeyFields }}
|
||||
m = rep
|
||||
{{- range $i, $field := .Field }}
|
||||
if {{ if (ne $i $keyField.Field.LastIndex ) -}}val{{- else -}}_{{- end -}}, ok = m["{{.}}"]; !ok {
|
||||
break
|
||||
}
|
||||
{{- if (ne $i $keyField.Field.LastIndex ) }}
|
||||
if m, ok = val.(map[string]interface{}); !ok {
|
||||
break
|
||||
}
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
{{- end }}
|
||||
return "{{.ResolverName}}", nil
|
||||
}
|
||||
{{- end }}
|
||||
return "", fmt.Errorf("%w for {{$entity.Name}}", ErrTypeNotFound)
|
||||
}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{end}}
|
||||
|
||||
193
vendor/github.com/99designs/gqlgen/plugin/federation/fieldset/fieldset.go
generated
vendored
Normal file
193
vendor/github.com/99designs/gqlgen/plugin/federation/fieldset/fieldset.go
generated
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
package fieldset
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/99designs/gqlgen/codegen"
|
||||
"github.com/99designs/gqlgen/codegen/templates"
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
)
|
||||
|
||||
// Set represents a FieldSet that is used in federation directives @key and @requires.
|
||||
// Would be happier to reuse FieldSet parsing from gqlparser, but this suits for now.
|
||||
//
|
||||
type Set []Field
|
||||
|
||||
// Field represents a single field in a FieldSet
|
||||
//
|
||||
type Field []string
|
||||
|
||||
// New parses a FieldSet string into a TinyFieldSet.
|
||||
//
|
||||
func New(raw string, prefix []string) Set {
|
||||
if !strings.Contains(raw, "{") {
|
||||
return parseUnnestedKeyFieldSet(raw, prefix)
|
||||
}
|
||||
|
||||
var (
|
||||
ret = Set{}
|
||||
subPrefix = prefix
|
||||
)
|
||||
before, during, after := extractSubs(raw)
|
||||
|
||||
if before != "" {
|
||||
befores := New(before, prefix)
|
||||
if len(befores) > 0 {
|
||||
subPrefix = befores[len(befores)-1]
|
||||
ret = append(ret, befores[:len(befores)-1]...)
|
||||
}
|
||||
}
|
||||
if during != "" {
|
||||
ret = append(ret, New(during, subPrefix)...)
|
||||
}
|
||||
if after != "" {
|
||||
ret = append(ret, New(after, prefix)...)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// FieldDefinition looks up a field in the type.
|
||||
//
|
||||
func (f Field) FieldDefinition(schemaType *ast.Definition, schema *ast.Schema) *ast.FieldDefinition {
|
||||
objType := schemaType
|
||||
def := objType.Fields.ForName(f[0])
|
||||
|
||||
for _, part := range f[1:] {
|
||||
if objType.Kind != ast.Object {
|
||||
panic(fmt.Sprintf(`invalid sub-field reference "%s" in %v: `, objType.Name, f))
|
||||
}
|
||||
x := def.Type.Name()
|
||||
objType = schema.Types[x]
|
||||
if objType == nil {
|
||||
panic("invalid schema type: " + x)
|
||||
}
|
||||
def = objType.Fields.ForName(part)
|
||||
}
|
||||
if def == nil {
|
||||
return nil
|
||||
}
|
||||
ret := *def // shallow copy
|
||||
ret.Name = f.ToGoPrivate()
|
||||
|
||||
return &ret
|
||||
}
|
||||
|
||||
// TypeReference looks up the type of a field.
|
||||
//
|
||||
func (f Field) TypeReference(obj *codegen.Object, objects codegen.Objects) *codegen.Field {
|
||||
var def *codegen.Field
|
||||
|
||||
for _, part := range f {
|
||||
def = fieldByName(obj, part)
|
||||
if def == nil {
|
||||
panic("unable to find field " + f[0])
|
||||
}
|
||||
obj = objects.ByName(def.TypeReference.Definition.Name)
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
// ToGo converts a (possibly nested) field into a proper public Go name.
|
||||
//
|
||||
func (f Field) ToGo() string {
|
||||
var ret string
|
||||
|
||||
for _, field := range f {
|
||||
ret += templates.ToGo(field)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// ToGoPrivate converts a (possibly nested) field into a proper private Go name.
|
||||
//
|
||||
func (f Field) ToGoPrivate() string {
|
||||
var ret string
|
||||
|
||||
for i, field := range f {
|
||||
if i == 0 {
|
||||
ret += templates.ToGoPrivate(field)
|
||||
continue
|
||||
}
|
||||
ret += templates.ToGo(field)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Join concatenates the field parts with a string separator between. Useful in templates.
|
||||
//
|
||||
func (f Field) Join(str string) string {
|
||||
return strings.Join(f, str)
|
||||
}
|
||||
|
||||
// JoinGo concatenates the Go name of field parts with a string separator between. Useful in templates.
|
||||
//
|
||||
func (f Field) JoinGo(str string) string {
|
||||
strs := []string{}
|
||||
|
||||
for _, s := range f {
|
||||
strs = append(strs, templates.ToGo(s))
|
||||
}
|
||||
return strings.Join(strs, str)
|
||||
}
|
||||
|
||||
func (f Field) LastIndex() int {
|
||||
return len(f) - 1
|
||||
}
|
||||
|
||||
// local functions
|
||||
|
||||
// parseUnnestedKeyFieldSet // handles simple case where none of the fields are nested.
|
||||
//
|
||||
func parseUnnestedKeyFieldSet(raw string, prefix []string) Set {
|
||||
ret := Set{}
|
||||
|
||||
for _, s := range strings.Fields(raw) {
|
||||
next := append(prefix[:], s) //nolint:gocritic // slicing out on purpose
|
||||
ret = append(ret, next)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// extractSubs splits out and trims sub-expressions from before, inside, and after "{}".
|
||||
//
|
||||
func extractSubs(str string) (string, string, string) {
|
||||
start := strings.Index(str, "{")
|
||||
end := matchingBracketIndex(str, start)
|
||||
|
||||
if start < 0 || end < 0 {
|
||||
panic("invalid key fieldSet: " + str)
|
||||
}
|
||||
return strings.TrimSpace(str[:start]), strings.TrimSpace(str[start+1 : end]), strings.TrimSpace(str[end+1:])
|
||||
}
|
||||
|
||||
// matchingBracketIndex returns the index of the closing bracket, assuming an open bracket at start.
|
||||
//
|
||||
func matchingBracketIndex(str string, start int) int {
|
||||
if start < 0 || len(str) <= start+1 {
|
||||
return -1
|
||||
}
|
||||
var depth int
|
||||
|
||||
for i, c := range str[start+1:] {
|
||||
switch c {
|
||||
case '{':
|
||||
depth++
|
||||
case '}':
|
||||
if depth == 0 {
|
||||
return start + 1 + i
|
||||
}
|
||||
depth--
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func fieldByName(obj *codegen.Object, name string) *codegen.Field {
|
||||
for _, field := range obj.Fields {
|
||||
if field.Name == name {
|
||||
return field
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
39
vendor/github.com/99designs/gqlgen/plugin/federation/readme.md
generated
vendored
Normal file
39
vendor/github.com/99designs/gqlgen/plugin/federation/readme.md
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
# Federation plugin
|
||||
|
||||
Add support for graphql federation in your graphql Go server!
|
||||
|
||||
TODO(miguel): add details.
|
||||
|
||||
# Tests
|
||||
There are several different tests. Some will process the configuration file directly. You can see those in the `federation_test.go`. There are also tests for entity resolvers, which will simulate requests from a federation server like Apollo Federation.
|
||||
|
||||
Running entity resolver tests.
|
||||
1. Go to `plugin/federation`
|
||||
2. Run the command `go generate`
|
||||
3. Run the tests with `go test ./...`.
|
||||
|
||||
# Architecture
|
||||
|
||||
TODO(miguel): add details.
|
||||
|
||||
# Entity resolvers - GetMany entities
|
||||
|
||||
The federation plugin implements `GetMany` semantics in which entity resolvers get the entire list of representations that need to be resolved. This functionality is currently optin tho, and to enable it you need to specify the directive `@entityResolver` in the federated entity you want this feature for. E.g.
|
||||
|
||||
```
|
||||
directive @entityResolver(multi: Boolean) on OBJECT
|
||||
|
||||
type MultiHello @key(fields: "name") @entityResolver(multi: true) {
|
||||
name: String!
|
||||
}
|
||||
```
|
||||
|
||||
That allows the federation plugin to generate `GetMany` resolver function that can take a list of representations to be resolved.
|
||||
|
||||
From that entity type, the resolver function would be
|
||||
|
||||
```
|
||||
func (r *entityResolver) FindManyMultiHellosByName(ctx context.Context, reps []*generated.ManyMultiHellosByNameInput) ([]*generated.MultiHello, error) {
|
||||
/// <Your code to resolve the list of items>
|
||||
}
|
||||
```
|
||||
84
vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go
generated
vendored
84
vendor/github.com/99designs/gqlgen/plugin/modelgen/models.go
generated
vendored
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"go/types"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/99designs/gqlgen/codegen/config"
|
||||
"github.com/99designs/gqlgen/codegen/templates"
|
||||
@@ -13,6 +14,13 @@ import (
|
||||
|
||||
type BuildMutateHook = func(b *ModelBuild) *ModelBuild
|
||||
|
||||
type FieldMutateHook = func(td *ast.Definition, fd *ast.FieldDefinition, f *Field) (*Field, error)
|
||||
|
||||
// defaultFieldMutateHook is the default hook for the Plugin which applies the GoTagFieldHook.
|
||||
func defaultFieldMutateHook(td *ast.Definition, fd *ast.FieldDefinition, f *Field) (*Field, error) {
|
||||
return GoTagFieldHook(td, fd, f)
|
||||
}
|
||||
|
||||
func defaultBuildMutateHook(b *ModelBuild) *ModelBuild {
|
||||
return b
|
||||
}
|
||||
@@ -28,6 +36,7 @@ type ModelBuild struct {
|
||||
type Interface struct {
|
||||
Description string
|
||||
Name string
|
||||
Implements []string
|
||||
}
|
||||
|
||||
type Object struct {
|
||||
@@ -58,11 +67,13 @@ type EnumValue struct {
|
||||
func New() plugin.Plugin {
|
||||
return &Plugin{
|
||||
MutateHook: defaultBuildMutateHook,
|
||||
FieldHook: defaultFieldMutateHook,
|
||||
}
|
||||
}
|
||||
|
||||
type Plugin struct {
|
||||
MutateHook BuildMutateHook
|
||||
FieldHook FieldMutateHook
|
||||
}
|
||||
|
||||
var _ plugin.ConfigMutator = &Plugin{}
|
||||
@@ -87,6 +98,7 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error {
|
||||
it := &Interface{
|
||||
Description: schemaType.Description,
|
||||
Name: schemaType.Name,
|
||||
Implements: schemaType.Interfaces,
|
||||
}
|
||||
|
||||
b.Interfaces = append(b.Interfaces, it)
|
||||
@@ -98,8 +110,23 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error {
|
||||
Description: schemaType.Description,
|
||||
Name: schemaType.Name,
|
||||
}
|
||||
|
||||
// If Interface A implements interface B, and Interface C also implements interface B
|
||||
// then both A and C have methods of B.
|
||||
// The reason for checking unique is to prevent the same method B from being generated twice.
|
||||
uniqueMap := map[string]bool{}
|
||||
for _, implementor := range cfg.Schema.GetImplements(schemaType) {
|
||||
it.Implements = append(it.Implements, implementor.Name)
|
||||
if !uniqueMap[implementor.Name] {
|
||||
it.Implements = append(it.Implements, implementor.Name)
|
||||
uniqueMap[implementor.Name] = true
|
||||
}
|
||||
// for interface implements
|
||||
for _, iface := range implementor.Interfaces {
|
||||
if !uniqueMap[iface] {
|
||||
it.Implements = append(it.Implements, iface)
|
||||
uniqueMap[iface] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, field := range schemaType.Fields {
|
||||
@@ -162,12 +189,22 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error {
|
||||
typ = types.NewPointer(typ)
|
||||
}
|
||||
|
||||
it.Fields = append(it.Fields, &Field{
|
||||
f := &Field{
|
||||
Name: name,
|
||||
Type: typ,
|
||||
Description: field.Description,
|
||||
Tag: `json:"` + field.Name + `"`,
|
||||
})
|
||||
}
|
||||
|
||||
if m.FieldHook != nil {
|
||||
mf, err := m.FieldHook(schemaType, field, f)
|
||||
if err != nil {
|
||||
return fmt.Errorf("generror: field %v.%v: %w", it.Name, field.Name, err)
|
||||
}
|
||||
f = mf
|
||||
}
|
||||
|
||||
it.Fields = append(it.Fields, f)
|
||||
}
|
||||
|
||||
b.Models = append(b.Models, it)
|
||||
@@ -214,13 +251,52 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error {
|
||||
b = m.MutateHook(b)
|
||||
}
|
||||
|
||||
return templates.Render(templates.Options{
|
||||
err := templates.Render(templates.Options{
|
||||
PackageName: cfg.Model.Package,
|
||||
Filename: cfg.Model.Filename,
|
||||
Data: b,
|
||||
GeneratedHeader: true,
|
||||
Packages: cfg.Packages,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// We may have generated code in a package we already loaded, so we reload all packages
|
||||
// to allow packages to be compared correctly
|
||||
cfg.ReloadAllPackages()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GoTagFieldHook applies the goTag directive to the generated Field f. When applying the Tag to the field, the field
|
||||
// name is used when no value argument is present.
|
||||
func GoTagFieldHook(td *ast.Definition, fd *ast.FieldDefinition, f *Field) (*Field, error) {
|
||||
args := make([]string, 0)
|
||||
for _, goTag := range fd.Directives.ForNames("goTag") {
|
||||
key := ""
|
||||
value := fd.Name
|
||||
|
||||
if arg := goTag.Arguments.ForName("key"); arg != nil {
|
||||
if k, err := arg.Value.Value(nil); err == nil {
|
||||
key = k.(string)
|
||||
}
|
||||
}
|
||||
|
||||
if arg := goTag.Arguments.ForName("value"); arg != nil {
|
||||
if v, err := arg.Value.Value(nil); err == nil {
|
||||
value = v.(string)
|
||||
}
|
||||
}
|
||||
|
||||
args = append(args, key+":\""+value+"\"")
|
||||
}
|
||||
|
||||
if len(args) > 0 {
|
||||
f.Tag = f.Tag + " " + strings.Join(args, " ")
|
||||
}
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func isStruct(t types.Type) bool {
|
||||
|
||||
3
vendor/github.com/99designs/gqlgen/plugin/modelgen/models.gotpl
generated
vendored
3
vendor/github.com/99designs/gqlgen/plugin/modelgen/models.gotpl
generated
vendored
@@ -15,6 +15,9 @@
|
||||
{{- range $model := .Interfaces }}
|
||||
{{ with .Description }} {{.|prefixLines "// "}} {{ end }}
|
||||
type {{.Name|go }} interface {
|
||||
{{- range $impl := .Implements }}
|
||||
{{ $impl|go }}
|
||||
{{- end }}
|
||||
Is{{.Name|go }}()
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
15
vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.go
generated
vendored
15
vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.go
generated
vendored
@@ -1,6 +1,8 @@
|
||||
package resolvergen
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -10,7 +12,6 @@ import (
|
||||
"github.com/99designs/gqlgen/codegen/templates"
|
||||
"github.com/99designs/gqlgen/internal/rewrite"
|
||||
"github.com/99designs/gqlgen/plugin"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func New() plugin.Plugin {
|
||||
@@ -86,7 +87,11 @@ func (m *Plugin) generatePerSchema(data *codegen.Data) error {
|
||||
|
||||
files := map[string]*File{}
|
||||
|
||||
for _, o := range data.Objects {
|
||||
objects := make(codegen.Objects, len(data.Objects)+len(data.Inputs))
|
||||
copy(objects, data.Objects)
|
||||
copy(objects[len(data.Objects):], data.Inputs)
|
||||
|
||||
for _, o := range objects {
|
||||
if o.HasResolvers() {
|
||||
fn := gqlToResolverName(data.Config.Resolver.Dir(), o.Position.Src.Name, data.Config.Resolver.FilenameTemplate)
|
||||
if files[fn] == nil {
|
||||
@@ -94,7 +99,7 @@ func (m *Plugin) generatePerSchema(data *codegen.Data) error {
|
||||
}
|
||||
|
||||
rewriter.MarkStructCopied(templates.LcFirst(o.Name) + templates.UcFirst(data.Config.Resolver.Type))
|
||||
rewriter.GetMethodBody(data.Config.Resolver.Type, o.Name)
|
||||
rewriter.GetMethodBody(data.Config.Resolver.Type, strings.Title(o.Name))
|
||||
files[fn].Objects = append(files[fn].Objects, o)
|
||||
}
|
||||
for _, f := range o.Fields {
|
||||
@@ -144,7 +149,7 @@ func (m *Plugin) generatePerSchema(data *codegen.Data) error {
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := os.Stat(data.Config.Resolver.Filename); os.IsNotExist(errors.Cause(err)) {
|
||||
if _, err := os.Stat(data.Config.Resolver.Filename); errors.Is(err, fs.ErrNotExist) {
|
||||
err := templates.Render(templates.Options{
|
||||
PackageName: data.Config.Resolver.Package,
|
||||
FileNotice: `
|
||||
@@ -172,7 +177,7 @@ type ResolverBuild struct {
|
||||
|
||||
type File struct {
|
||||
// These are separated because the type definition of the resolver object may live in a different file from the
|
||||
//resolver method implementations, for example when extending a type in a different graphql schema file
|
||||
// resolver method implementations, for example when extending a type in a different graphql schema file
|
||||
Objects []*codegen.Object
|
||||
Resolvers []*Resolver
|
||||
imports []rewrite.Import
|
||||
|
||||
4
vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.gotpl
generated
vendored
4
vendor/github.com/99designs/gqlgen/plugin/resolvergen/resolver.gotpl
generated
vendored
@@ -26,8 +26,8 @@
|
||||
{{ end }}
|
||||
|
||||
{{ range $object := .Objects -}}
|
||||
// {{$object.Name}} returns {{ $object.ResolverInterface | ref }} implementation.
|
||||
func (r *{{$.ResolverType}}) {{$object.Name}}() {{ $object.ResolverInterface | ref }} { return &{{lcFirst $object.Name}}{{ucFirst $.ResolverType}}{r} }
|
||||
// {{ucFirst $object.Name}} returns {{ $object.ResolverInterface | ref }} implementation.
|
||||
func (r *{{$.ResolverType}}) {{ucFirst $object.Name}}() {{ $object.ResolverInterface | ref }} { return &{{lcFirst $object.Name}}{{ucFirst $.ResolverType}}{r} }
|
||||
{{ end }}
|
||||
|
||||
{{ range $object := .Objects -}}
|
||||
|
||||
6
vendor/github.com/99designs/gqlgen/plugin/servergen/server.go
generated
vendored
6
vendor/github.com/99designs/gqlgen/plugin/servergen/server.go
generated
vendored
@@ -1,13 +1,14 @@
|
||||
package servergen
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/99designs/gqlgen/codegen"
|
||||
"github.com/99designs/gqlgen/codegen/templates"
|
||||
"github.com/99designs/gqlgen/plugin"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func New(filename string) plugin.Plugin {
|
||||
@@ -23,13 +24,14 @@ var _ plugin.CodeGenerator = &Plugin{}
|
||||
func (m *Plugin) Name() string {
|
||||
return "servergen"
|
||||
}
|
||||
|
||||
func (m *Plugin) GenerateCode(data *codegen.Data) error {
|
||||
serverBuild := &ServerBuild{
|
||||
ExecPackageName: data.Config.Exec.ImportPath(),
|
||||
ResolverPackageName: data.Config.Resolver.ImportPath(),
|
||||
}
|
||||
|
||||
if _, err := os.Stat(m.filename); os.IsNotExist(errors.Cause(err)) {
|
||||
if _, err := os.Stat(m.filename); errors.Is(err, fs.ErrNotExist) {
|
||||
return templates.Render(templates.Options{
|
||||
PackageName: "main",
|
||||
Filename: m.filename,
|
||||
|
||||
2
vendor/github.com/99designs/gqlgen/tools.go
generated
vendored
2
vendor/github.com/99designs/gqlgen/tools.go
generated
vendored
@@ -1,8 +1,8 @@
|
||||
//go:build tools
|
||||
// +build tools
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "github.com/matryer/moq"
|
||||
_ "github.com/vektah/dataloaden"
|
||||
)
|
||||
|
||||
2
vendor/github.com/Yamashou/gqlgenc/.gitignore
generated
vendored
2
vendor/github.com/Yamashou/gqlgenc/.gitignore
generated
vendored
@@ -5,3 +5,5 @@
|
||||
/client.go
|
||||
/query/
|
||||
/.idea/
|
||||
|
||||
coverage.out
|
||||
|
||||
28
vendor/github.com/Yamashou/gqlgenc/.golangci.yml
generated
vendored
28
vendor/github.com/Yamashou/gqlgenc/.golangci.yml
generated
vendored
@@ -35,6 +35,15 @@ linters:
|
||||
- interfacer
|
||||
- gomnd
|
||||
- goerr113
|
||||
- exhaustivestruct
|
||||
- errorlint # TODO able this lint
|
||||
- forbidigo
|
||||
- cyclop
|
||||
- govet
|
||||
- errname
|
||||
- varnamelen
|
||||
- nilnil
|
||||
- structcheck
|
||||
fast: false
|
||||
|
||||
issues:
|
||||
@@ -63,3 +72,22 @@ issues:
|
||||
text: "`Introspection` is unused" # used in config/config.go
|
||||
linters:
|
||||
- varcheck
|
||||
- path: config/config.go
|
||||
text: "`ClientV2` is unused" # used in config/config.go
|
||||
linters:
|
||||
- structcheck
|
||||
- path: graphqljson/graphql.go
|
||||
text: "append to slice `frontier` with non-zero initialized length" # used in config/config.go
|
||||
linters:
|
||||
- makezero
|
||||
- path: clientv2/client_test.go
|
||||
text: "should not use basic type string as key in context.WithValue"
|
||||
linters:
|
||||
- golint
|
||||
- path: clientv2/client_test.go
|
||||
text: "should not use built-in type string as key for value; define your own type to avoid collisions"
|
||||
linters:
|
||||
- staticcheck
|
||||
- path: clientv2/client_test.go
|
||||
linters:
|
||||
- revive
|
||||
|
||||
2
vendor/github.com/Yamashou/gqlgenc/Makefile
generated
vendored
2
vendor/github.com/Yamashou/gqlgenc/Makefile
generated
vendored
@@ -4,7 +4,7 @@ fmt:
|
||||
gofumports -local github.com/Yamashou/gqlgenc -w .
|
||||
|
||||
lint:
|
||||
golangci-lint run
|
||||
golangci-lint cache clean && golangci-lint run
|
||||
|
||||
test:
|
||||
go test -v ./...
|
||||
|
||||
33
vendor/github.com/Yamashou/gqlgenc/README.md
generated
vendored
33
vendor/github.com/Yamashou/gqlgenc/README.md
generated
vendored
@@ -25,11 +25,12 @@ go get -u github.com/Yamashou/gqlgenc
|
||||
|
||||
### Client Codes Only
|
||||
|
||||
gqlgenc base is gqlgen with [plugins](https://gqlgen.com/reference/plugins/). So the setting is yaml in each format.
|
||||
gqlgenc can be configured using a .gqlgenc.yml file,
|
||||
gqlgenc base is gqlgen with [plugins](https://gqlgen.com/reference/plugins/). So the setting is yaml in each format.
|
||||
gqlgenc can be configured using a `.gqlgenc.yml` file
|
||||
|
||||
Load a schema from a remote server:
|
||||
|
||||
```yaml
|
||||
|
||||
model:
|
||||
package: generated
|
||||
filename: ./models_gen.go # https://github.com/99designs/gqlgen/tree/master/plugin/modelgen
|
||||
@@ -43,13 +44,33 @@ models:
|
||||
model: github.com/99designs/gqlgen/graphql.Time
|
||||
endpoint:
|
||||
url: https://api.annict.com/graphql # Where do you want to send your request?
|
||||
headers: # If you need header for getting introspection query, set it
|
||||
headers: # If you need header for getting introspection query, set it
|
||||
Authorization: "Bearer ${ANNICT_KEY}" # support environment variables
|
||||
query:
|
||||
- "./query/*.graphql" # Where are all the query files located?
|
||||
- "./query/*.graphql" # Where are all the query files located?
|
||||
```
|
||||
|
||||
Execute the following command on same directory for .gqlgenc.yaml
|
||||
Load a schema from a local file:
|
||||
|
||||
```yaml
|
||||
model:
|
||||
package: generated
|
||||
filename: ./models_gen.go # https://github.com/99designs/gqlgen/tree/master/plugin/modelgen
|
||||
client:
|
||||
package: generated
|
||||
filename: ./client.go # Where should any generated client go?
|
||||
models:
|
||||
Int:
|
||||
model: github.com/99designs/gqlgen/graphql.Int64
|
||||
Date:
|
||||
model: github.com/99designs/gqlgen/graphql.Time
|
||||
schema:
|
||||
- "schema/**/*.graphql" # Where are all the schema files located?
|
||||
query:
|
||||
- "./query/*.graphql" # Where are all the query files located?
|
||||
```
|
||||
|
||||
Execute the following command on same directory for .gqlgenc.yml
|
||||
|
||||
```shell script
|
||||
gqlgenc
|
||||
|
||||
19
vendor/github.com/Yamashou/gqlgenc/TESTING.md
generated
vendored
Normal file
19
vendor/github.com/Yamashou/gqlgenc/TESTING.md
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
# Run tests
|
||||
|
||||
To run tests simply run
|
||||
|
||||
```shell script
|
||||
go test ./... -coverprofile=coverage.out
|
||||
```
|
||||
|
||||
To deep dive into test coverage, run the following command to see the result in your terminal
|
||||
|
||||
```shell script
|
||||
go tool cover -func=coverage.out
|
||||
```
|
||||
|
||||
or the following to see the result in your browser
|
||||
|
||||
```shell script
|
||||
go tool cover -html=coverage.out
|
||||
```
|
||||
120
vendor/github.com/Yamashou/gqlgenc/client/client.go
generated
vendored
120
vendor/github.com/Yamashou/gqlgenc/client/client.go
generated
vendored
@@ -4,14 +4,18 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/Yamashou/gqlgenc/graphqljson"
|
||||
"golang.org/x/xerrors"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
// HTTPRequestOption represents the options applicable to the http client
|
||||
type HTTPRequestOption func(req *http.Request)
|
||||
|
||||
// Client is the http client wrapper
|
||||
type Client struct {
|
||||
Client *http.Client
|
||||
BaseURL string
|
||||
@@ -25,6 +29,7 @@ type Request struct {
|
||||
OperationName string `json:"operationName,omitempty"`
|
||||
}
|
||||
|
||||
// NewClient creates a new http client wrapper
|
||||
func NewClient(client *http.Client, baseURL string, options ...HTTPRequestOption) *Client {
|
||||
return &Client{
|
||||
Client: client,
|
||||
@@ -33,21 +38,21 @@ func NewClient(client *http.Client, baseURL string, options ...HTTPRequestOption
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) newRequest(ctx context.Context, query string, vars map[string]interface{}, httpRequestOptions []HTTPRequestOption) (*http.Request, error) {
|
||||
func (c *Client) newRequest(ctx context.Context, operationName, query string, vars map[string]interface{}, httpRequestOptions []HTTPRequestOption) (*http.Request, error) {
|
||||
r := &Request{
|
||||
Query: query,
|
||||
Variables: vars,
|
||||
OperationName: "",
|
||||
OperationName: operationName,
|
||||
}
|
||||
|
||||
requestBody, err := json.Marshal(r)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("encode: %w", err)
|
||||
return nil, fmt.Errorf("encode: %w", err)
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.BaseURL, bytes.NewBuffer(requestBody))
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("create request struct failed: %w", err)
|
||||
return nil, fmt.Errorf("create request struct failed: %w", err)
|
||||
}
|
||||
|
||||
for _, httpRequestOption := range c.HTTPRequestOptions {
|
||||
@@ -60,28 +65,117 @@ func (c *Client) newRequest(ctx context.Context, query string, vars map[string]i
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// GqlErrorList is the struct of a standard graphql error response
|
||||
type GqlErrorList struct {
|
||||
Errors gqlerror.List `json:"errors"`
|
||||
}
|
||||
|
||||
func (e *GqlErrorList) Error() string {
|
||||
return e.Errors.Error()
|
||||
}
|
||||
|
||||
// HTTPError is the error when a GqlErrorList cannot be parsed
|
||||
type HTTPError struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// ErrorResponse represent an handled error
|
||||
type ErrorResponse struct {
|
||||
// populated when http status code is not OK
|
||||
NetworkError *HTTPError `json:"networkErrors"`
|
||||
// populated when http status code is OK but the server returned at least one graphql error
|
||||
GqlErrors *gqlerror.List `json:"graphqlErrors"`
|
||||
}
|
||||
|
||||
// HasErrors returns true when at least one error is declared
|
||||
func (er *ErrorResponse) HasErrors() bool {
|
||||
return er.NetworkError != nil || er.GqlErrors != nil
|
||||
}
|
||||
|
||||
func (er *ErrorResponse) Error() string {
|
||||
content, err := json.Marshal(er)
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
return string(content)
|
||||
}
|
||||
|
||||
// Post sends a http POST request to the graphql endpoint with the given query then unpacks
|
||||
// the response into the given object.
|
||||
func (c *Client) Post(ctx context.Context, query string, respData interface{}, vars map[string]interface{}, httpRequestOptions ...HTTPRequestOption) error {
|
||||
req, err := c.newRequest(ctx, query, vars, httpRequestOptions)
|
||||
func (c *Client) Post(ctx context.Context, operationName, query string, respData interface{}, vars map[string]interface{}, httpRequestOptions ...HTTPRequestOption) error {
|
||||
req, err := c.newRequest(ctx, operationName, query, vars, httpRequestOptions)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("don't create request: %w", err)
|
||||
return fmt.Errorf("don't create request: %w", err)
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json; charset=utf-8")
|
||||
req.Header.Set("Accept", "application/json; charset=utf-8")
|
||||
|
||||
resp, err := c.Client.Do(req)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("request failed: %w", err)
|
||||
return fmt.Errorf("request failed: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if err := graphqljson.Unmarshal(resp.Body, respData); err != nil {
|
||||
return err
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read response body: %w", err)
|
||||
}
|
||||
|
||||
if resp.StatusCode < 200 || 299 < resp.StatusCode {
|
||||
return xerrors.Errorf("http status code: %v", resp.StatusCode)
|
||||
return parseResponse(body, resp.StatusCode, respData)
|
||||
}
|
||||
|
||||
func parseResponse(body []byte, httpCode int, result interface{}) error {
|
||||
errResponse := &ErrorResponse{}
|
||||
isKOCode := httpCode < 200 || 299 < httpCode
|
||||
if isKOCode {
|
||||
errResponse.NetworkError = &HTTPError{
|
||||
Code: httpCode,
|
||||
Message: fmt.Sprintf("Response body %s", string(body)),
|
||||
}
|
||||
}
|
||||
|
||||
// some servers return a graphql error with a non OK http code, try anyway to parse the body
|
||||
if err := unmarshal(body, result); err != nil {
|
||||
if gqlErr, ok := err.(*GqlErrorList); ok {
|
||||
errResponse.GqlErrors = &gqlErr.Errors
|
||||
} else if !isKOCode { // if is KO code there is already the http error, this error should not be returned
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if errResponse.HasErrors() {
|
||||
return errResponse
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// response is a GraphQL layer response from a handler.
|
||||
type response struct {
|
||||
Data json.RawMessage `json:"data"`
|
||||
Errors json.RawMessage `json:"errors"`
|
||||
}
|
||||
|
||||
func unmarshal(data []byte, res interface{}) error {
|
||||
resp := response{}
|
||||
if err := json.Unmarshal(data, &resp); err != nil {
|
||||
return fmt.Errorf("failed to decode data %s: %w", string(data), err)
|
||||
}
|
||||
|
||||
if resp.Errors != nil && len(resp.Errors) > 0 {
|
||||
// try to parse standard graphql error
|
||||
errors := &GqlErrorList{}
|
||||
if e := json.Unmarshal(data, errors); e != nil {
|
||||
return fmt.Errorf("faild to parse graphql errors. Response content %s - %w ", string(data), e)
|
||||
}
|
||||
|
||||
return errors
|
||||
}
|
||||
|
||||
if err := graphqljson.UnmarshalData(resp.Data, res); err != nil {
|
||||
return fmt.Errorf("failed to decode data into response %s: %w", string(data), err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
35
vendor/github.com/Yamashou/gqlgenc/clientgen/client.go
generated
vendored
35
vendor/github.com/Yamashou/gqlgenc/clientgen/client.go
generated
vendored
@@ -1,9 +1,11 @@
|
||||
package clientgen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/99designs/gqlgen/codegen/config"
|
||||
"github.com/99designs/gqlgen/plugin"
|
||||
"golang.org/x/xerrors"
|
||||
gqlgencConfig "github.com/Yamashou/gqlgenc/config"
|
||||
)
|
||||
|
||||
var _ plugin.ConfigMutator = &Plugin{}
|
||||
@@ -11,12 +13,14 @@ var _ plugin.ConfigMutator = &Plugin{}
|
||||
type Plugin struct {
|
||||
queryFilePaths []string
|
||||
Client config.PackageConfig
|
||||
GenerateConfig *gqlgencConfig.GenerateConfig
|
||||
}
|
||||
|
||||
func New(queryFilePaths []string, client config.PackageConfig) *Plugin {
|
||||
func New(queryFilePaths []string, client config.PackageConfig, generateConfig *gqlgencConfig.GenerateConfig) *Plugin {
|
||||
return &Plugin{
|
||||
queryFilePaths: queryFilePaths,
|
||||
Client: client,
|
||||
GenerateConfig: generateConfig,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,49 +31,54 @@ func (p *Plugin) Name() string {
|
||||
func (p *Plugin) MutateConfig(cfg *config.Config) error {
|
||||
querySources, err := LoadQuerySources(p.queryFilePaths)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("load query sources failed: %w", err)
|
||||
return fmt.Errorf("load query sources failed: %w", err)
|
||||
}
|
||||
|
||||
// 1. 全体のqueryDocumentを1度にparse
|
||||
// 1. Parse document from source of query
|
||||
queryDocument, err := ParseQueryDocuments(cfg.Schema, querySources)
|
||||
queryDocument, err := ParseQueryDocuments(cfg.Schema, querySources, p.GenerateConfig)
|
||||
if err != nil {
|
||||
return xerrors.Errorf(": %w", err)
|
||||
return fmt.Errorf(": %w", err)
|
||||
}
|
||||
|
||||
// 2. OperationごとのqueryDocumentを作成
|
||||
// 2. Separate documents for each operation
|
||||
queryDocuments, err := QueryDocumentsByOperations(cfg.Schema, queryDocument.Operations)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse query document failed: %w", err)
|
||||
return fmt.Errorf("parse query document failed: %w", err)
|
||||
}
|
||||
|
||||
// 3. テンプレートと情報ソースを元にコード生成
|
||||
// 3. Generate code from template and document source
|
||||
sourceGenerator := NewSourceGenerator(cfg, p.Client)
|
||||
source := NewSource(cfg.Schema, queryDocument, sourceGenerator)
|
||||
source := NewSource(cfg.Schema, queryDocument, sourceGenerator, p.GenerateConfig)
|
||||
query, err := source.Query()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("generating query object: %w", err)
|
||||
return fmt.Errorf("generating query object: %w", err)
|
||||
}
|
||||
|
||||
mutation, err := source.Mutation()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("generating mutation object: %w", err)
|
||||
return fmt.Errorf("generating mutation object: %w", err)
|
||||
}
|
||||
|
||||
fragments, err := source.Fragments()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("generating fragment failed: %w", err)
|
||||
return fmt.Errorf("generating fragment failed: %w", err)
|
||||
}
|
||||
|
||||
operationResponses, err := source.OperationResponses()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("generating operation response failed: %w", err)
|
||||
return fmt.Errorf("generating operation response failed: %w", err)
|
||||
}
|
||||
|
||||
if err := RenderTemplate(cfg, query, mutation, fragments, source.Operations(queryDocuments), operationResponses, p.Client); err != nil {
|
||||
return xerrors.Errorf("template failed: %w", err)
|
||||
operations, err := source.Operations(queryDocuments)
|
||||
if err != nil {
|
||||
return fmt.Errorf("generating operation failed: %w", err)
|
||||
}
|
||||
|
||||
if err := RenderTemplate(cfg, query, mutation, fragments, operations, operationResponses, p.GenerateConfig, p.Client); err != nil {
|
||||
return fmt.Errorf("template failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user