mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 12:54:38 +03:00
Remove vendored dependencies (#4110)
This commit is contained in:
23
.github/workflows/golangci-lint.yml
vendored
23
.github/workflows/golangci-lint.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
|||||||
run: docker exec -t build /bin/bash -c "make generate-backend"
|
run: docker exec -t build /bin/bash -c "make generate-backend"
|
||||||
|
|
||||||
- name: Run golangci-lint
|
- name: Run golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v2
|
uses: golangci/golangci-lint-action@v3
|
||||||
with:
|
with:
|
||||||
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
|
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
|
||||||
version: latest
|
version: latest
|
||||||
@@ -42,19 +42,26 @@ jobs:
|
|||||||
# working-directory: somedir
|
# working-directory: somedir
|
||||||
|
|
||||||
# Optional: golangci-lint command line arguments.
|
# Optional: golangci-lint command line arguments.
|
||||||
args: --modules-download-mode=vendor --timeout=5m
|
#
|
||||||
|
# Note: By default, the `.golangci.yml` file should be at the root of the repository.
|
||||||
|
# The location of the configuration file can be changed by using `--config=`
|
||||||
|
args: --timeout=5m
|
||||||
|
|
||||||
# Optional: show only new issues if it's a pull request. The default value is `false`.
|
# Optional: show only new issues if it's a pull request. The default value is `false`.
|
||||||
# only-new-issues: true
|
# only-new-issues: true
|
||||||
|
|
||||||
# Optional: if set to true then the action will use pre-installed Go.
|
# Optional: if set to true, then all caching functionality will be completely disabled,
|
||||||
# skip-go-installation: true
|
# takes precedence over all other caching options.
|
||||||
|
# skip-cache: true
|
||||||
|
|
||||||
# Optional: if set to true then the action don't cache or restore ~/go/pkg.
|
# Optional: if set to true, then the action won't cache or restore ~/go/pkg.
|
||||||
skip-pkg-cache: true
|
# skip-pkg-cache: true
|
||||||
|
|
||||||
# Optional: if set to true then the action don't cache or restore ~/.cache/go-build.
|
# Optional: if set to true, then the action won't cache or restore ~/.cache/go-build.
|
||||||
skip-build-cache: true
|
# skip-build-cache: true
|
||||||
|
|
||||||
|
# Optional: The mode to install golangci-lint. It can be 'binary' or 'goinstall'.
|
||||||
|
# install-mode: "goinstall"
|
||||||
|
|
||||||
- name: Cleanup build container
|
- name: Cleanup build container
|
||||||
run: docker rm -f -v build
|
run: docker rm -f -v build
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -2,6 +2,9 @@
|
|||||||
# Go
|
# Go
|
||||||
####
|
####
|
||||||
|
|
||||||
|
# Vendored dependencies
|
||||||
|
vendor
|
||||||
|
|
||||||
# Binaries for programs and plugins
|
# Binaries for programs and plugins
|
||||||
*.exe
|
*.exe
|
||||||
*.exe~
|
*.exe~
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
# options for analysis running
|
# options for analysis running
|
||||||
run:
|
run:
|
||||||
timeout: 5m
|
timeout: 5m
|
||||||
modules-download-mode: vendor
|
|
||||||
|
|
||||||
linters:
|
linters:
|
||||||
disable-all: true
|
disable-all: true
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:generate go run -mod=vendor github.com/99designs/gqlgen
|
//go:generate go run github.com/99designs/gqlgen
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ RUN apk add --no-cache make alpine-sdk
|
|||||||
WORKDIR /stash
|
WORKDIR /stash
|
||||||
COPY ./go* ./*.go Makefile gqlgen.yml .gqlgenc.yml /stash/
|
COPY ./go* ./*.go Makefile gqlgen.yml .gqlgenc.yml /stash/
|
||||||
COPY ./scripts /stash/scripts/
|
COPY ./scripts /stash/scripts/
|
||||||
COPY ./vendor /stash/vendor/
|
|
||||||
COPY ./pkg /stash/pkg/
|
COPY ./pkg /stash/pkg/
|
||||||
COPY ./cmd /stash/cmd
|
COPY ./cmd /stash/cmd
|
||||||
COPY ./internal /stash/internal
|
COPY ./internal /stash/internal
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ RUN apt update && apt install -y build-essential golang
|
|||||||
WORKDIR /stash
|
WORKDIR /stash
|
||||||
COPY ./go* ./*.go Makefile gqlgen.yml .gqlgenc.yml /stash/
|
COPY ./go* ./*.go Makefile gqlgen.yml .gqlgenc.yml /stash/
|
||||||
COPY ./scripts /stash/scripts/
|
COPY ./scripts /stash/scripts/
|
||||||
COPY ./vendor /stash/vendor/
|
|
||||||
COPY ./pkg /stash/pkg/
|
COPY ./pkg /stash/pkg/
|
||||||
COPY ./cmd /stash/cmd
|
COPY ./cmd /stash/cmd
|
||||||
COPY ./internal /stash/internal
|
COPY ./internal /stash/internal
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
COMPILER_CONTAINER="stashapp/compiler:7"
|
COMPILER_CONTAINER="stashapp/compiler:7"
|
||||||
|
|
||||||
BUILD_DATE=`go run -mod=vendor scripts/getDate.go`
|
BUILD_DATE=`go run scripts/getDate.go`
|
||||||
GITHASH=`git rev-parse --short HEAD`
|
GITHASH=`git rev-parse --short HEAD`
|
||||||
STASH_VERSION=`git describe --tags --exclude latest_develop`
|
STASH_VERSION=`git describe --tags --exclude latest_develop`
|
||||||
|
|
||||||
|
|||||||
3
vendor/github.com/99designs/gqlgen/.dockerignore
generated
vendored
3
vendor/github.com/99designs/gqlgen/.dockerignore
generated
vendored
@@ -1,3 +0,0 @@
|
|||||||
/**/node_modules
|
|
||||||
/codegen/tests/gen
|
|
||||||
/vendor
|
|
||||||
20
vendor/github.com/99designs/gqlgen/.editorconfig
generated
vendored
20
vendor/github.com/99designs/gqlgen/.editorconfig
generated
vendored
@@ -1,20 +0,0 @@
|
|||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
end_of_line = lf
|
|
||||||
charset = utf-8
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
insert_final_newline = true
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 4
|
|
||||||
|
|
||||||
[*.{go,gotpl}]
|
|
||||||
indent_style = tab
|
|
||||||
|
|
||||||
[*.yml]
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
# These often end up with go code inside, so lets keep tabs
|
|
||||||
[*.{html,md}]
|
|
||||||
indent_size = 2
|
|
||||||
indent_style = tab
|
|
||||||
3
vendor/github.com/99designs/gqlgen/.gitattributes
generated
vendored
3
vendor/github.com/99designs/gqlgen/.gitattributes
generated
vendored
@@ -1,3 +0,0 @@
|
|||||||
/codegen/templates/data.go linguist-generated
|
|
||||||
/_examples/dataloader/*_gen.go linguist-generated
|
|
||||||
generated.go linguist-generated
|
|
||||||
16
vendor/github.com/99designs/gqlgen/.gitignore
generated
vendored
16
vendor/github.com/99designs/gqlgen/.gitignore
generated
vendored
@@ -1,16 +0,0 @@
|
|||||||
/vendor
|
|
||||||
/docs/public
|
|
||||||
/docs/.hugo_build.lock
|
|
||||||
/_examples/chat/node_modules
|
|
||||||
/integration/node_modules
|
|
||||||
/integration/schema-fetched.graphql
|
|
||||||
/_examples/chat/package-lock.json
|
|
||||||
/_examples/federation/package-lock.json
|
|
||||||
/_examples/federation/node_modules
|
|
||||||
/codegen/gen
|
|
||||||
/gen
|
|
||||||
|
|
||||||
/.vscode
|
|
||||||
.idea/
|
|
||||||
*.test
|
|
||||||
*.out
|
|
||||||
39
vendor/github.com/99designs/gqlgen/.golangci.yml
generated
vendored
39
vendor/github.com/99designs/gqlgen/.golangci.yml
generated
vendored
@@ -1,39 +0,0 @@
|
|||||||
run:
|
|
||||||
tests: true
|
|
||||||
skip-dirs:
|
|
||||||
- bin
|
|
||||||
|
|
||||||
linters-settings:
|
|
||||||
errcheck:
|
|
||||||
ignore: fmt:.*,[rR]ead|[wW]rite|[cC]lose,io:Copy
|
|
||||||
|
|
||||||
linters:
|
|
||||||
disable-all: true
|
|
||||||
enable:
|
|
||||||
- bodyclose
|
|
||||||
- deadcode
|
|
||||||
- depguard
|
|
||||||
- dupl
|
|
||||||
- errcheck
|
|
||||||
- gocritic
|
|
||||||
- gofmt
|
|
||||||
- goimports
|
|
||||||
- gosimple
|
|
||||||
- govet
|
|
||||||
- ineffassign
|
|
||||||
- misspell
|
|
||||||
- nakedret
|
|
||||||
- prealloc
|
|
||||||
- staticcheck
|
|
||||||
- structcheck
|
|
||||||
- typecheck
|
|
||||||
- unconvert
|
|
||||||
- unused
|
|
||||||
- varcheck
|
|
||||||
|
|
||||||
issues:
|
|
||||||
exclude-rules:
|
|
||||||
# Exclude some linters from running on tests files.
|
|
||||||
- path: _test\.go
|
|
||||||
linters:
|
|
||||||
- dupl
|
|
||||||
8634
vendor/github.com/99designs/gqlgen/CHANGELOG.md
generated
vendored
8634
vendor/github.com/99designs/gqlgen/CHANGELOG.md
generated
vendored
File diff suppressed because it is too large
Load Diff
27
vendor/github.com/99designs/gqlgen/CONTRIBUTING.md
generated
vendored
27
vendor/github.com/99designs/gqlgen/CONTRIBUTING.md
generated
vendored
@@ -1,27 +0,0 @@
|
|||||||
# Contribution Guidelines
|
|
||||||
|
|
||||||
Want to contribute to gqlgen? Here are some guidelines for how we accept help.
|
|
||||||
|
|
||||||
## Getting in Touch
|
|
||||||
|
|
||||||
Our [discord](https://discord.gg/DYEq3EMs4U) server is the best place to ask questions or get advice on using gqlgen.
|
|
||||||
|
|
||||||
## Reporting Bugs and Issues
|
|
||||||
|
|
||||||
We use [GitHub Issues](https://github.com/99designs/gqlgen/issues) to track bugs, so please do a search before submitting to ensure your problem isn't already tracked.
|
|
||||||
|
|
||||||
### New Issues
|
|
||||||
|
|
||||||
Please provide the expected and observed behaviours in your issue. A minimal GraphQL schema or configuration file should be provided where appropriate.
|
|
||||||
|
|
||||||
## Proposing a Change
|
|
||||||
|
|
||||||
If you intend to implement a feature for gqlgen, or make a non-trivial change to the current implementation, we recommend [first filing an issue](https://github.com/99designs/gqlgen/issues/new) marked with the `proposal` tag, so that the engineering team can provide guidance and feedback on the direction of an implementation. This also help ensure that other people aren't also working on the same thing.
|
|
||||||
|
|
||||||
Bug fixes are welcome and should come with appropriate test coverage.
|
|
||||||
|
|
||||||
New features should be made against the `next` branch.
|
|
||||||
|
|
||||||
### License
|
|
||||||
|
|
||||||
By contributing to gqlgen, you agree that your contributions will be licensed under its MIT license.
|
|
||||||
19
vendor/github.com/99designs/gqlgen/LICENSE
generated
vendored
19
vendor/github.com/99designs/gqlgen/LICENSE
generated
vendored
@@ -1,19 +0,0 @@
|
|||||||
Copyright (c) 2020 gqlgen authors
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
150
vendor/github.com/99designs/gqlgen/README.md
generated
vendored
150
vendor/github.com/99designs/gqlgen/README.md
generated
vendored
@@ -1,150 +0,0 @@
|
|||||||

|
|
||||||
|
|
||||||
|
|
||||||
# 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 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 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/)
|
|
||||||
|
|
||||||
## Quick start
|
|
||||||
1. [Initialise a new go module](https://golang.org/doc/tutorial/create-module)
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
If you think you've found a bug, or something isn't behaving the way you think it should, please raise an [issue](https://github.com/99designs/gqlgen/issues) on GitHub.
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
We welcome contributions, Read our [Contribution Guidelines](https://github.com/99designs/gqlgen/blob/master/CONTRIBUTING.md) to learn more about contributing to **gqlgen**
|
|
||||||
## Frequently asked questions
|
|
||||||
|
|
||||||
### How do I prevent fetching child objects that might not be used?
|
|
||||||
|
|
||||||
When you have nested or recursive schema like this:
|
|
||||||
|
|
||||||
```graphql
|
|
||||||
type User {
|
|
||||||
id: ID!
|
|
||||||
name: String!
|
|
||||||
friends: [User!]!
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You need to tell gqlgen that it should only fetch friends if the user requested it. There are two ways to do this;
|
|
||||||
|
|
||||||
- #### Using Custom Models
|
|
||||||
|
|
||||||
Write a custom model that omits the friends field:
|
|
||||||
|
|
||||||
```go
|
|
||||||
type User struct {
|
|
||||||
ID int
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
And reference the model in `gqlgen.yml`:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# gqlgen.yml
|
|
||||||
models:
|
|
||||||
User:
|
|
||||||
model: github.com/you/pkg/model.User # go import path to the User struct above
|
|
||||||
```
|
|
||||||
|
|
||||||
- #### Using Explicit Resolvers
|
|
||||||
|
|
||||||
If you want to Keep using the generated model, mark the field as requiring a resolver explicitly in `gqlgen.yml` like this:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# gqlgen.yml
|
|
||||||
models:
|
|
||||||
User:
|
|
||||||
fields:
|
|
||||||
friends:
|
|
||||||
resolver: true # force a resolver to be generated
|
|
||||||
```
|
|
||||||
|
|
||||||
After doing either of the above and running generate we will need to provide a resolver for friends:
|
|
||||||
|
|
||||||
```go
|
|
||||||
func (r *userResolver) Friends(ctx context.Context, obj *User) ([]*User, error) {
|
|
||||||
// select * from user where friendid = obj.ID
|
|
||||||
return friends, nil
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
models:
|
|
||||||
ID: # The GraphQL type ID is backed by
|
|
||||||
model:
|
|
||||||
- github.com/99designs/gqlgen/graphql.IntID # a go integer
|
|
||||||
- github.com/99designs/gqlgen/graphql.ID # or a go string
|
|
||||||
```
|
|
||||||
|
|
||||||
This means gqlgen will be able to automatically bind to strings or ints for models you have written yourself, but the
|
|
||||||
first model in this list is used as the default type and it will always be used when:
|
|
||||||
|
|
||||||
- Generating models based on schema
|
|
||||||
- As arguments in resolvers
|
|
||||||
|
|
||||||
There isn't any way around this, gqlgen has no way to know what you want in a given context.
|
|
||||||
|
|
||||||
## Other Resources
|
|
||||||
|
|
||||||
- [Christopher Biscardi @ Gophercon UK 2018](https://youtu.be/FdURVezcdcw)
|
|
||||||
- [Introducing gqlgen: a GraphQL Server Generator for Go](https://99designs.com.au/blog/engineering/gqlgen-a-graphql-server-generator-for-go/)
|
|
||||||
- [Dive into GraphQL by Iván Corrales Solera](https://medium.com/@ivan.corrales.solera/dive-into-graphql-9bfedf22e1a)
|
|
||||||
- [Sample Project built on gqlgen with Postgres by Oleg Shalygin](https://github.com/oshalygin/gqlgen-pg-todo-example)
|
|
||||||
14
vendor/github.com/99designs/gqlgen/RELEASE-CHECKLIST.md
generated
vendored
14
vendor/github.com/99designs/gqlgen/RELEASE-CHECKLIST.md
generated
vendored
@@ -1,14 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
40
vendor/github.com/99designs/gqlgen/TESTING.md
generated
vendored
40
vendor/github.com/99designs/gqlgen/TESTING.md
generated
vendored
@@ -1,40 +0,0 @@
|
|||||||
How to write tests for gqlgen
|
|
||||||
===
|
|
||||||
|
|
||||||
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
|
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
||||||
### Testing the errors generated by the binary
|
|
||||||
|
|
||||||
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/testserver/input_test.go` for an example.
|
|
||||||
|
|
||||||
### Testing introspection
|
|
||||||
|
|
||||||
Introspection is tested by diffing the output of `graphql get-schema` against an expected output.
|
|
||||||
|
|
||||||
Setting up the integration environment is a little tricky:
|
|
||||||
```bash
|
|
||||||
cd integration
|
|
||||||
go generate ./...
|
|
||||||
go run ./server/server.go
|
|
||||||
```
|
|
||||||
in another terminal
|
|
||||||
```bash
|
|
||||||
cd integration
|
|
||||||
npm install
|
|
||||||
./node_modules/.bin/graphql-codegen
|
|
||||||
```
|
|
||||||
|
|
||||||
will write the schema to `integration/schema-fetched.graphql`, compare that with `schema-expected.graphql`
|
|
||||||
|
|
||||||
CI will run this and fail the build if the two files dont match.
|
|
||||||
|
|
||||||
125
vendor/github.com/99designs/gqlgen/api/generate.go
generated
vendored
125
vendor/github.com/99designs/gqlgen/api/generate.go
generated
vendored
@@ -1,125 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/codegen"
|
|
||||||
"github.com/99designs/gqlgen/codegen/config"
|
|
||||||
"github.com/99designs/gqlgen/plugin"
|
|
||||||
"github.com/99designs/gqlgen/plugin/federation"
|
|
||||||
"github.com/99designs/gqlgen/plugin/modelgen"
|
|
||||||
"github.com/99designs/gqlgen/plugin/resolvergen"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Generate(cfg *config.Config, option ...Option) error {
|
|
||||||
_ = syscall.Unlink(cfg.Exec.Filename)
|
|
||||||
if cfg.Model.IsDefined() {
|
|
||||||
_ = syscall.Unlink(cfg.Model.Filename)
|
|
||||||
}
|
|
||||||
|
|
||||||
plugins := []plugin.Plugin{}
|
|
||||||
if cfg.Model.IsDefined() {
|
|
||||||
plugins = append(plugins, modelgen.New())
|
|
||||||
}
|
|
||||||
plugins = append(plugins, resolvergen.New())
|
|
||||||
if cfg.Federation.IsDefined() {
|
|
||||||
plugins = append([]plugin.Plugin{federation.New()}, plugins...)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, o := range option {
|
|
||||||
o(cfg, &plugins)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, p := range plugins {
|
|
||||||
if inj, ok := p.(plugin.EarlySourceInjector); ok {
|
|
||||||
if s := inj.InjectSourceEarly(); s != nil {
|
|
||||||
cfg.Sources = append(cfg.Sources, s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cfg.LoadSchema(); err != nil {
|
|
||||||
return fmt.Errorf("failed to load schema: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, p := range plugins {
|
|
||||||
if inj, ok := p.(plugin.LateSourceInjector); ok {
|
|
||||||
if s := inj.InjectSourceLate(cfg.Schema); s != nil {
|
|
||||||
cfg.Sources = append(cfg.Sources, s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadSchema again now we have everything
|
|
||||||
if err := cfg.LoadSchema(); err != nil {
|
|
||||||
return fmt.Errorf("failed to load schema: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := cfg.Init(); err != nil {
|
|
||||||
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 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 fmt.Errorf("merging type systems failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = codegen.GenerateCode(data); err != nil {
|
|
||||||
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 fmt.Errorf("%s: %w", p.Name(), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = codegen.GenerateCode(data); err != nil {
|
|
||||||
return fmt.Errorf("generating core failed: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !cfg.SkipValidation {
|
|
||||||
if err := validate(cfg); err != nil {
|
|
||||||
return fmt.Errorf("validation failed: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func validate(cfg *config.Config) error {
|
|
||||||
roots := []string{cfg.Exec.ImportPath()}
|
|
||||||
if cfg.Model.IsDefined() {
|
|
||||||
roots = append(roots, cfg.Model.ImportPath())
|
|
||||||
}
|
|
||||||
|
|
||||||
if cfg.Resolver.IsDefined() {
|
|
||||||
roots = append(roots, cfg.Resolver.ImportPath())
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg.Packages.LoadAll(roots...)
|
|
||||||
errs := cfg.Packages.Errors()
|
|
||||||
if len(errs) > 0 {
|
|
||||||
return errs
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
47
vendor/github.com/99designs/gqlgen/api/option.go
generated
vendored
47
vendor/github.com/99designs/gqlgen/api/option.go
generated
vendored
@@ -1,47 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/99designs/gqlgen/codegen/config"
|
|
||||||
"github.com/99designs/gqlgen/plugin"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Option func(cfg *config.Config, plugins *[]plugin.Plugin)
|
|
||||||
|
|
||||||
func NoPlugins() Option {
|
|
||||||
return func(cfg *config.Config, plugins *[]plugin.Plugin) {
|
|
||||||
*plugins = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func AddPlugin(p plugin.Plugin) Option {
|
|
||||||
return func(cfg *config.Config, plugins *[]plugin.Plugin) {
|
|
||||||
*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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
118
vendor/github.com/99designs/gqlgen/codegen/args.go
generated
vendored
118
vendor/github.com/99designs/gqlgen/codegen/args.go
generated
vendored
@@ -1,118 +0,0 @@
|
|||||||
package codegen
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"go/types"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/codegen/config"
|
|
||||||
"github.com/99designs/gqlgen/codegen/templates"
|
|
||||||
"github.com/vektah/gqlparser/v2/ast"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ArgSet struct {
|
|
||||||
Args []*FieldArgument
|
|
||||||
FuncDecl string
|
|
||||||
}
|
|
||||||
|
|
||||||
type FieldArgument struct {
|
|
||||||
*ast.ArgumentDefinition
|
|
||||||
TypeReference *config.TypeReference
|
|
||||||
VarName string // The name of the var in go
|
|
||||||
Object *Object // A link back to the parent object
|
|
||||||
Default interface{} // The default value
|
|
||||||
Directives []*Directive
|
|
||||||
Value interface{} // value set in Data
|
|
||||||
}
|
|
||||||
|
|
||||||
// ImplDirectives get not Builtin and location ARGUMENT_DEFINITION directive
|
|
||||||
func (f *FieldArgument) ImplDirectives() []*Directive {
|
|
||||||
d := make([]*Directive, 0)
|
|
||||||
for i := range f.Directives {
|
|
||||||
if !f.Directives[i].Builtin && f.Directives[i].IsLocation(ast.LocationArgumentDefinition) {
|
|
||||||
d = append(d, f.Directives[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FieldArgument) DirectiveObjName() string {
|
|
||||||
return "rawArgs"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *FieldArgument) Stream() bool {
|
|
||||||
return f.Object != nil && f.Object.Stream
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *builder) buildArg(obj *Object, arg *ast.ArgumentDefinition) (*FieldArgument, error) {
|
|
||||||
tr, err := b.Binder.TypeReference(arg.Type, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
argDirs, err := b.getDirectives(arg.Directives)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
newArg := FieldArgument{
|
|
||||||
ArgumentDefinition: arg,
|
|
||||||
TypeReference: tr,
|
|
||||||
Object: obj,
|
|
||||||
VarName: templates.ToGoPrivate(arg.Name),
|
|
||||||
Directives: argDirs,
|
|
||||||
}
|
|
||||||
|
|
||||||
if arg.DefaultValue != nil {
|
|
||||||
newArg.Default, err = arg.DefaultValue.Value(nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("default value is not valid: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &newArg, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *builder) bindArgs(field *Field, params *types.Tuple) ([]*FieldArgument, error) {
|
|
||||||
var newArgs []*FieldArgument
|
|
||||||
|
|
||||||
nextArg:
|
|
||||||
for j := 0; j < params.Len(); j++ {
|
|
||||||
param := params.At(j)
|
|
||||||
for _, oldArg := range field.Args {
|
|
||||||
if strings.EqualFold(oldArg.Name, param.Name()) {
|
|
||||||
tr, err := b.Binder.TypeReference(oldArg.Type, param.Type())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
oldArg.TypeReference = tr
|
|
||||||
|
|
||||||
newArgs = append(newArgs, oldArg)
|
|
||||||
continue nextArg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// no matching arg found, abort
|
|
||||||
return nil, fmt.Errorf("arg %s not in schema", param.Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
return newArgs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Data) Args() map[string][]*FieldArgument {
|
|
||||||
ret := map[string][]*FieldArgument{}
|
|
||||||
for _, o := range a.Objects {
|
|
||||||
for _, f := range o.Fields {
|
|
||||||
if len(f.Args) > 0 {
|
|
||||||
ret[f.ArgsFunc()] = f.Args
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, d := range a.Directives() {
|
|
||||||
if len(d.Args) > 0 {
|
|
||||||
ret[d.ArgsFunc()] = d.Args
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
36
vendor/github.com/99designs/gqlgen/codegen/args.gotpl
generated
vendored
36
vendor/github.com/99designs/gqlgen/codegen/args.gotpl
generated
vendored
@@ -1,36 +0,0 @@
|
|||||||
{{ range $name, $args := .Args }}
|
|
||||||
func (ec *executionContext) {{ $name }}(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
|
|
||||||
var err error
|
|
||||||
args := map[string]interface{}{}
|
|
||||||
{{- range $i, $arg := . }}
|
|
||||||
var arg{{$i}} {{ $arg.TypeReference.GO | ref}}
|
|
||||||
if tmp, ok := rawArgs[{{$arg.Name|quote}}]; ok {
|
|
||||||
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, graphql.ErrorOnPath(ctx, err)
|
|
||||||
}
|
|
||||||
if data, ok := tmp.({{ $arg.TypeReference.GO | ref }}) ; ok {
|
|
||||||
arg{{$i}} = data
|
|
||||||
{{- if $arg.TypeReference.IsNilable }}
|
|
||||||
} else if tmp == nil {
|
|
||||||
arg{{$i}} = nil
|
|
||||||
{{- end }}
|
|
||||||
} else {
|
|
||||||
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)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
}
|
|
||||||
args[{{$arg.Name|quote}}] = arg{{$i}}
|
|
||||||
{{- end }}
|
|
||||||
return args, nil
|
|
||||||
}
|
|
||||||
{{ end }}
|
|
||||||
11
vendor/github.com/99designs/gqlgen/codegen/complexity.go
generated
vendored
11
vendor/github.com/99designs/gqlgen/codegen/complexity.go
generated
vendored
@@ -1,11 +0,0 @@
|
|||||||
package codegen
|
|
||||||
|
|
||||||
func (o *Object) UniqueFields() map[string][]*Field {
|
|
||||||
m := map[string][]*Field{}
|
|
||||||
|
|
||||||
for _, f := range o.Fields {
|
|
||||||
m[f.GoFieldName] = append(m[f.GoFieldName], f)
|
|
||||||
}
|
|
||||||
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
494
vendor/github.com/99designs/gqlgen/codegen/config/binder.go
generated
vendored
494
vendor/github.com/99designs/gqlgen/codegen/config/binder.go
generated
vendored
@@ -1,494 +0,0 @@
|
|||||||
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/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
|
|
||||||
objectCache map[string]map[string]types.Object
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) NewBinder() *Binder {
|
|
||||||
return &Binder{
|
|
||||||
pkgs: c.Packages,
|
|
||||||
schema: c.Schema,
|
|
||||||
cfg: c,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Binder) TypePosition(typ types.Type) token.Position {
|
|
||||||
named, isNamed := typ.(*types.Named)
|
|
||||||
if !isNamed {
|
|
||||||
return token.Position{
|
|
||||||
Filename: "unknown",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return b.ObjectPosition(named.Obj())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Binder) ObjectPosition(typ types.Object) token.Position {
|
|
||||||
if typ == nil {
|
|
||||||
return token.Position{
|
|
||||||
Filename: "unknown",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pkg := b.pkgs.Load(typ.Pkg().Path())
|
|
||||||
return pkg.Fset.Position(typ.Pos())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Binder) FindTypeFromName(name string) (types.Type, error) {
|
|
||||||
pkgName, typeName := code.PkgAndType(name)
|
|
||||||
return b.FindType(pkgName, typeName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Binder) FindType(pkgName string, typeName string) (types.Type, error) {
|
|
||||||
if pkgName == "" {
|
|
||||||
if typeName == "map[string]interface{}" {
|
|
||||||
return MapType, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if typeName == "interface{}" {
|
|
||||||
return InterfaceType, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
obj, err := b.FindObject(pkgName, typeName)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if fun, isFunc := obj.(*types.Func); isFunc {
|
|
||||||
return fun.Type().(*types.Signature).Params().At(0).Type(), nil
|
|
||||||
}
|
|
||||||
return obj.Type(), 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
|
|
||||||
if len(models) == 0 {
|
|
||||||
return nil, fmt.Errorf(name + " not found in typemap")
|
|
||||||
}
|
|
||||||
|
|
||||||
if models[0] == "map[string]interface{}" {
|
|
||||||
return MapType, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if models[0] == "interface{}" {
|
|
||||||
return InterfaceType, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
pkgName, typeName := code.PkgAndType(models[0])
|
|
||||||
if pkgName == "" {
|
|
||||||
return nil, fmt.Errorf("missing package name for %s", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
obj, err := b.FindObject(pkgName, typeName)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj.Type(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Binder) FindObject(pkgName string, typeName string) (types.Object, error) {
|
|
||||||
if pkgName == "" {
|
|
||||||
return nil, fmt.Errorf("package cannot be nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
pkg := b.pkgs.LoadWithTypes(pkgName)
|
|
||||||
if pkg == nil {
|
|
||||||
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 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
parent := def.Parent()
|
|
||||||
if parent == nil || parent != scope {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Binder) PointerTo(ref *TypeReference) *TypeReference {
|
|
||||||
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.
|
|
||||||
type TypeReference struct {
|
|
||||||
Definition *ast.Definition
|
|
||||||
GQL *ast.Type
|
|
||||||
GO types.Type // Type of the field being bound. Could be a pointer or a value type of Target.
|
|
||||||
Target types.Type // The actual type that we know how to bind to. May require pointer juggling when traversing to fields.
|
|
||||||
CastType types.Type // Before calling marshalling functions cast from/to this base type
|
|
||||||
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 {
|
|
||||||
newRef := *ref
|
|
||||||
newRef.GO = p.Elem()
|
|
||||||
return &newRef
|
|
||||||
}
|
|
||||||
|
|
||||||
if ref.IsSlice() {
|
|
||||||
newRef := *ref
|
|
||||||
newRef.GO = ref.GO.(*types.Slice).Elem()
|
|
||||||
newRef.GQL = ref.GQL.Elem
|
|
||||||
return &newRef
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TypeReference) IsPtr() bool {
|
|
||||||
_, isPtr := t.GO.(*types.Pointer)
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TypeReference) IsSlice() bool {
|
|
||||||
_, isSlice := t.GO.(*types.Slice)
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TypeReference) IsStruct() bool {
|
|
||||||
_, isStruct := t.GO.Underlying().(*types.Struct)
|
|
||||||
return isStruct
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TypeReference) IsScalar() bool {
|
|
||||||
return t.Definition.Kind == ast.Scalar
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TypeReference) UniquenessKey() string {
|
|
||||||
nullability := "O"
|
|
||||||
if t.GQL.NonNull {
|
|
||||||
nullability = "N"
|
|
||||||
}
|
|
||||||
|
|
||||||
elemNullability := ""
|
|
||||||
if t.GQL.Elem != nil && t.GQL.Elem.NonNull {
|
|
||||||
// Fix for #896
|
|
||||||
elemNullability = "ᚄ"
|
|
||||||
}
|
|
||||||
return nullability + t.Definition.Name + "2" + templates.TypeIdentifier(t.GO) + elemNullability
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TypeReference) MarshalFunc() string {
|
|
||||||
if t.Definition == nil {
|
|
||||||
panic(errors.New("Definition missing for " + t.GQL.Name()))
|
|
||||||
}
|
|
||||||
|
|
||||||
if t.Definition.Kind == ast.InputObject {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return "marshal" + t.UniquenessKey()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TypeReference) UnmarshalFunc() string {
|
|
||||||
if t.Definition == nil {
|
|
||||||
panic(errors.New("Definition missing for " + t.GQL.Name()))
|
|
||||||
}
|
|
||||||
|
|
||||||
if !t.Definition.IsInputType() {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return "unmarshal" + t.UniquenessKey()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *TypeReference) IsTargetNilable() bool {
|
|
||||||
return IsNilable(t.Target)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Binder) PushRef(ret *TypeReference) {
|
|
||||||
b.References = append(b.References, ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isMap(t types.Type) bool {
|
|
||||||
if t == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
_, ok := t.(*types.Map)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func isIntf(t types.Type) bool {
|
|
||||||
if t == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
_, ok := t.(*types.Interface)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Binder) TypeReference(schemaType *ast.Type, bindTarget types.Type) (ret *TypeReference, err error) {
|
|
||||||
if !isValid(bindTarget) {
|
|
||||||
b.SawInvalid = true
|
|
||||||
return nil, fmt.Errorf("%s has an invalid type", schemaType.Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
var pkgName, typeName string
|
|
||||||
def := b.schema.Types[schemaType.Name()]
|
|
||||||
defer func() {
|
|
||||||
if err == nil && ret != nil {
|
|
||||||
b.PushRef(ret)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if len(b.cfg.Models[schemaType.Name()].Model) == 0 {
|
|
||||||
return nil, fmt.Errorf("%s was not found", schemaType.Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, model := range b.cfg.Models[schemaType.Name()].Model {
|
|
||||||
if model == "map[string]interface{}" {
|
|
||||||
if !isMap(bindTarget) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return &TypeReference{
|
|
||||||
Definition: def,
|
|
||||||
GQL: schemaType,
|
|
||||||
GO: MapType,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if model == "interface{}" {
|
|
||||||
if !isIntf(bindTarget) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return &TypeReference{
|
|
||||||
Definition: def,
|
|
||||||
GQL: schemaType,
|
|
||||||
GO: InterfaceType,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
pkgName, typeName = code.PkgAndType(model)
|
|
||||||
if pkgName == "" {
|
|
||||||
return nil, fmt.Errorf("missing package name for %s", schemaType.Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
ref := &TypeReference{
|
|
||||||
Definition: def,
|
|
||||||
GQL: schemaType,
|
|
||||||
}
|
|
||||||
|
|
||||||
obj, err := b.FindObject(pkgName, typeName)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
} else if underlying := basicUnderlying(obj.Type()); def.IsLeafType() && underlying != nil && underlying.Kind() == types.String {
|
|
||||||
// TODO delete before v1. Backwards compatibility case for named types wrapping strings (see #595)
|
|
||||||
|
|
||||||
ref.GO = obj.Type()
|
|
||||||
ref.CastType = underlying
|
|
||||||
|
|
||||||
underlyingRef, err := b.TypeReference(&ast.Type{NamedType: "String"}, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ref.Marshaler = underlyingRef.Marshaler
|
|
||||||
ref.Unmarshaler = underlyingRef.Unmarshaler
|
|
||||||
} else {
|
|
||||||
ref.GO = obj.Type()
|
|
||||||
}
|
|
||||||
|
|
||||||
ref.Target = ref.GO
|
|
||||||
ref.GO = b.CopyModifiersFromAst(schemaType, ref.GO)
|
|
||||||
|
|
||||||
if bindTarget != nil {
|
|
||||||
if err = code.CompatibleTypes(ref.GO, bindTarget); err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
ref.GO = bindTarget
|
|
||||||
}
|
|
||||||
|
|
||||||
return ref, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("%s is incompatible with %s", schemaType.Name(), bindTarget.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
func isValid(t types.Type) bool {
|
|
||||||
basic, isBasic := t.(*types.Basic)
|
|
||||||
if !isBasic {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return basic.Kind() != types.Invalid
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Binder) CopyModifiersFromAst(t *ast.Type, base types.Type) types.Type {
|
|
||||||
if t.Elem != nil {
|
|
||||||
child := b.CopyModifiersFromAst(t.Elem, base)
|
|
||||||
if _, isStruct := child.Underlying().(*types.Struct); isStruct && !b.cfg.OmitSliceElementPointers {
|
|
||||||
child = types.NewPointer(child)
|
|
||||||
}
|
|
||||||
return types.NewSlice(child)
|
|
||||||
}
|
|
||||||
|
|
||||||
var isInterface bool
|
|
||||||
if named, ok := base.(*types.Named); ok {
|
|
||||||
_, isInterface = named.Underlying().(*types.Interface)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isInterface && !IsNilable(base) && !t.NonNull {
|
|
||||||
return types.NewPointer(base)
|
|
||||||
}
|
|
||||||
|
|
||||||
return base
|
|
||||||
}
|
|
||||||
|
|
||||||
func IsNilable(t types.Type) bool {
|
|
||||||
if namedType, isNamed := t.(*types.Named); isNamed {
|
|
||||||
return IsNilable(namedType.Underlying())
|
|
||||||
}
|
|
||||||
_, isPtr := t.(*types.Pointer)
|
|
||||||
_, isMap := t.(*types.Map)
|
|
||||||
_, isInterface := t.(*types.Interface)
|
|
||||||
_, isSlice := t.(*types.Slice)
|
|
||||||
_, isChan := t.(*types.Chan)
|
|
||||||
return isPtr || isMap || isInterface || isSlice || isChan
|
|
||||||
}
|
|
||||||
|
|
||||||
func hasMethod(it types.Type, name string) bool {
|
|
||||||
if ptr, isPtr := it.(*types.Pointer); isPtr {
|
|
||||||
it = ptr.Elem()
|
|
||||||
}
|
|
||||||
namedType, ok := it.(*types.Named)
|
|
||||||
if !ok {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < namedType.NumMethods(); i++ {
|
|
||||||
if namedType.Method(i).Name() == name {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func basicUnderlying(it types.Type) *types.Basic {
|
|
||||||
if ptr, isPtr := it.(*types.Pointer); isPtr {
|
|
||||||
it = ptr.Elem()
|
|
||||||
}
|
|
||||||
namedType, ok := it.(*types.Named)
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if basic, ok := namedType.Underlying().(*types.Basic); ok {
|
|
||||||
return basic
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
648
vendor/github.com/99designs/gqlgen/codegen/config/config.go
generated
vendored
648
vendor/github.com/99designs/gqlgen/codegen/config/config.go
generated
vendored
@@ -1,648 +0,0 @@
|
|||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/internal/code"
|
|
||||||
"github.com/vektah/gqlparser/v2"
|
|
||||||
"github.com/vektah/gqlparser/v2/ast"
|
|
||||||
"gopkg.in/yaml.v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
SchemaFilename StringList `yaml:"schema,omitempty"`
|
|
||||||
Exec ExecConfig `yaml:"exec"`
|
|
||||||
Model PackageConfig `yaml:"model,omitempty"`
|
|
||||||
Federation PackageConfig `yaml:"federation,omitempty"`
|
|
||||||
Resolver ResolverConfig `yaml:"resolver,omitempty"`
|
|
||||||
AutoBind []string `yaml:"autobind"`
|
|
||||||
Models TypeMap `yaml:"models,omitempty"`
|
|
||||||
StructTag string `yaml:"struct_tag,omitempty"`
|
|
||||||
Directives map[string]DirectiveConfig `yaml:"directives,omitempty"`
|
|
||||||
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
|
|
||||||
Federated bool `yaml:"federated,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var cfgFilenames = []string{".gqlgen.yml", "gqlgen.yml", "gqlgen.yaml"}
|
|
||||||
|
|
||||||
// DefaultConfig creates a copy of the default config
|
|
||||||
func DefaultConfig() *Config {
|
|
||||||
return &Config{
|
|
||||||
SchemaFilename: StringList{"schema.graphql"},
|
|
||||||
Model: PackageConfig{Filename: "models_gen.go"},
|
|
||||||
Exec: ExecConfig{Filename: "generated.go"},
|
|
||||||
Directives: map[string]DirectiveConfig{},
|
|
||||||
Models: TypeMap{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadDefaultConfig loads the default config so that it is ready to be used
|
|
||||||
func LoadDefaultConfig() (*Config, error) {
|
|
||||||
config := DefaultConfig()
|
|
||||||
|
|
||||||
for _, filename := range config.SchemaFilename {
|
|
||||||
filename = filepath.ToSlash(filename)
|
|
||||||
var err error
|
|
||||||
var schemaRaw []byte
|
|
||||||
schemaRaw, err = ioutil.ReadFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("unable to open schema: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
config.Sources = append(config.Sources, &ast.Source{Name: filename, Input: string(schemaRaw)})
|
|
||||||
}
|
|
||||||
|
|
||||||
return config, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadConfigFromDefaultLocations looks for a config file in the current directory, and all parent directories
|
|
||||||
// walking up the tree. The closest config file will be returned.
|
|
||||||
func LoadConfigFromDefaultLocations() (*Config, error) {
|
|
||||||
cfgFile, err := findCfg()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = os.Chdir(filepath.Dir(cfgFile))
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("unable to enter config dir: %w", err)
|
|
||||||
}
|
|
||||||
return LoadConfig(cfgFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
var path2regex = strings.NewReplacer(
|
|
||||||
`.`, `\.`,
|
|
||||||
`*`, `.+`,
|
|
||||||
`\`, `[\\/]`,
|
|
||||||
`/`, `[\\/]`,
|
|
||||||
)
|
|
||||||
|
|
||||||
// LoadConfig reads the gqlgen.yml config file
|
|
||||||
func LoadConfig(filename string) (*Config, error) {
|
|
||||||
config := DefaultConfig()
|
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("unable to read config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := yaml.UnmarshalStrict(b, config); err != nil {
|
|
||||||
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},
|
|
||||||
"specifiedBy": {SkipRuntime: true},
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, value := range defaultDirectives {
|
|
||||||
if _, defined := config.Directives[key]; !defined {
|
|
||||||
config.Directives[key] = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
preGlobbing := config.SchemaFilename
|
|
||||||
config.SchemaFilename = StringList{}
|
|
||||||
for _, f := range preGlobbing {
|
|
||||||
var matches []string
|
|
||||||
|
|
||||||
// for ** we want to override default globbing patterns and walk all
|
|
||||||
// subdirectories to match schema files.
|
|
||||||
if strings.Contains(f, "**") {
|
|
||||||
pathParts := strings.SplitN(f, "**", 2)
|
|
||||||
rest := strings.TrimPrefix(strings.TrimPrefix(pathParts[1], `\`), `/`)
|
|
||||||
// turn the rest of the glob into a regex, anchored only at the end because ** allows
|
|
||||||
// for any number of dirs in between and walk will let us match against the full path name
|
|
||||||
globRe := regexp.MustCompile(path2regex.Replace(rest) + `$`)
|
|
||||||
|
|
||||||
if err := filepath.Walk(pathParts[0], func(path string, info os.FileInfo, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if globRe.MatchString(strings.TrimPrefix(path, pathParts[0])) {
|
|
||||||
matches = append(matches, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}); err != nil {
|
|
||||||
return 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 fmt.Errorf("failed to glob schema filename %s: %w", f, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, m := range matches {
|
|
||||||
if config.SchemaFilename.Has(m) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
config.SchemaFilename = append(config.SchemaFilename, m)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, filename := range config.SchemaFilename {
|
|
||||||
filename = filepath.ToSlash(filename)
|
|
||||||
var err error
|
|
||||||
var schemaRaw []byte
|
|
||||||
schemaRaw, err = ioutil.ReadFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("unable to open schema: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
config.Sources = append(config.Sources, &ast.Source{Name: filename, Input: string(schemaRaw)})
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) Init() error {
|
|
||||||
if c.Packages == nil {
|
|
||||||
c.Packages = &code.Packages{}
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Schema == nil {
|
|
||||||
if err := c.LoadSchema(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err := c.injectTypesFromSchema()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = c.autobind()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
c.injectBuiltins()
|
|
||||||
// prefetch all packages in one big packages.Load call
|
|
||||||
c.Packages.LoadAll(c.packageList()...)
|
|
||||||
|
|
||||||
// check everything is valid on the way out
|
|
||||||
err = c.check()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Directives["goField"] = DirectiveConfig{
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
if bd := schemaType.Directives.ForName("goModel"); bd != nil {
|
|
||||||
if ma := bd.Arguments.ForName("model"); ma != nil {
|
|
||||||
if mv, err := ma.Value.Value(nil); err == nil {
|
|
||||||
c.Models.Add(schemaType.Name, mv.(string))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ma := bd.Arguments.ForName("models"); ma != nil {
|
|
||||||
if mvs, err := ma.Value.Value(nil); err == nil {
|
|
||||||
for _, mv := range mvs.([]interface{}) {
|
|
||||||
c.Models.Add(schemaType.Name, mv.(string))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if schemaType.Kind == ast.Object || schemaType.Kind == ast.InputObject {
|
|
||||||
for _, field := range schemaType.Fields {
|
|
||||||
if fd := field.Directives.ForName("goField"); fd != nil {
|
|
||||||
forceResolver := c.Models[schemaType.Name].Fields[field.Name].Resolver
|
|
||||||
fieldName := c.Models[schemaType.Name].Fields[field.Name].FieldName
|
|
||||||
|
|
||||||
if ra := fd.Arguments.ForName("forceResolver"); ra != nil {
|
|
||||||
if fr, err := ra.Value.Value(nil); err == nil {
|
|
||||||
forceResolver = fr.(bool)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if na := fd.Arguments.ForName("name"); na != nil {
|
|
||||||
if fr, err := na.Value.Value(nil); err == nil {
|
|
||||||
fieldName = fr.(string)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Models[schemaType.Name].Fields == nil {
|
|
||||||
c.Models[schemaType.Name] = TypeMapEntry{
|
|
||||||
Model: c.Models[schemaType.Name].Model,
|
|
||||||
Fields: map[string]TypeMapField{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Models[schemaType.Name].Fields[field.Name] = TypeMapField{
|
|
||||||
FieldName: fieldName,
|
|
||||||
Resolver: forceResolver,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type TypeMapEntry struct {
|
|
||||||
Model StringList `yaml:"model"`
|
|
||||||
Fields map[string]TypeMapField `yaml:"fields,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type TypeMapField struct {
|
|
||||||
Resolver bool `yaml:"resolver"`
|
|
||||||
FieldName string `yaml:"fieldName"`
|
|
||||||
GeneratedMethod string `yaml:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type StringList []string
|
|
||||||
|
|
||||||
func (a *StringList) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
||||||
var single string
|
|
||||||
err := unmarshal(&single)
|
|
||||||
if err == nil {
|
|
||||||
*a = []string{single}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var multi []string
|
|
||||||
err = unmarshal(&multi)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
*a = multi
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a StringList) Has(file string) bool {
|
|
||||||
for _, existing := range a {
|
|
||||||
if existing == file {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) check() error {
|
|
||||||
if c.Models == nil {
|
|
||||||
c.Models = TypeMap{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type FilenamePackage struct {
|
|
||||||
Filename string
|
|
||||||
Package string
|
|
||||||
Declaree string
|
|
||||||
}
|
|
||||||
|
|
||||||
fileList := map[string][]FilenamePackage{}
|
|
||||||
|
|
||||||
if err := c.Models.Check(); err != nil {
|
|
||||||
return fmt.Errorf("config.models: %w", err)
|
|
||||||
}
|
|
||||||
if err := c.Exec.Check(); err != nil {
|
|
||||||
return fmt.Errorf("config.exec: %w", err)
|
|
||||||
}
|
|
||||||
fileList[c.Exec.ImportPath()] = append(fileList[c.Exec.ImportPath()], FilenamePackage{
|
|
||||||
Filename: c.Exec.Filename,
|
|
||||||
Package: c.Exec.Package,
|
|
||||||
Declaree: "exec",
|
|
||||||
})
|
|
||||||
|
|
||||||
if c.Model.IsDefined() {
|
|
||||||
if err := c.Model.Check(); err != nil {
|
|
||||||
return fmt.Errorf("config.model: %w", err)
|
|
||||||
}
|
|
||||||
fileList[c.Model.ImportPath()] = append(fileList[c.Model.ImportPath()], FilenamePackage{
|
|
||||||
Filename: c.Model.Filename,
|
|
||||||
Package: c.Model.Package,
|
|
||||||
Declaree: "model",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if c.Resolver.IsDefined() {
|
|
||||||
if err := c.Resolver.Check(); err != nil {
|
|
||||||
return fmt.Errorf("config.resolver: %w", err)
|
|
||||||
}
|
|
||||||
fileList[c.Resolver.ImportPath()] = append(fileList[c.Resolver.ImportPath()], FilenamePackage{
|
|
||||||
Filename: c.Resolver.Filename,
|
|
||||||
Package: c.Resolver.Package,
|
|
||||||
Declaree: "resolver",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if c.Federation.IsDefined() {
|
|
||||||
if err := c.Federation.Check(); err != nil {
|
|
||||||
return fmt.Errorf("config.federation: %w", err)
|
|
||||||
}
|
|
||||||
fileList[c.Federation.ImportPath()] = append(fileList[c.Federation.ImportPath()], FilenamePackage{
|
|
||||||
Filename: c.Federation.Filename,
|
|
||||||
Package: c.Federation.Package,
|
|
||||||
Declaree: "federation",
|
|
||||||
})
|
|
||||||
if c.Federation.ImportPath() != c.Exec.ImportPath() {
|
|
||||||
return fmt.Errorf("federation and exec must be in the same package")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if c.Federated {
|
|
||||||
return fmt.Errorf("federated has been removed, instead use\nfederation:\n filename: path/to/federated.go")
|
|
||||||
}
|
|
||||||
|
|
||||||
for importPath, pkg := range fileList {
|
|
||||||
for _, file1 := range pkg {
|
|
||||||
for _, file2 := range pkg {
|
|
||||||
if file1.Package != file2.Package {
|
|
||||||
return fmt.Errorf("%s and %s define the same import path (%s) with different package names (%s vs %s)",
|
|
||||||
file1.Declaree,
|
|
||||||
file2.Declaree,
|
|
||||||
importPath,
|
|
||||||
file1.Package,
|
|
||||||
file2.Package,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type TypeMap map[string]TypeMapEntry
|
|
||||||
|
|
||||||
func (tm TypeMap) Exists(typeName string) bool {
|
|
||||||
_, ok := tm[typeName]
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tm TypeMap) UserDefined(typeName string) bool {
|
|
||||||
m, ok := tm[typeName]
|
|
||||||
return ok && len(m.Model) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tm TypeMap) Check() error {
|
|
||||||
for typeName, entry := range tm {
|
|
||||||
for _, model := range entry.Model {
|
|
||||||
if strings.LastIndex(model, ".") < strings.LastIndex(model, "/") {
|
|
||||||
return fmt.Errorf("model %s: invalid type specifier \"%s\" - you need to specify a struct to map to", typeName, entry.Model)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tm TypeMap) ReferencedPackages() []string {
|
|
||||||
var pkgs []string
|
|
||||||
|
|
||||||
for _, typ := range tm {
|
|
||||||
for _, model := range typ.Model {
|
|
||||||
if model == "map[string]interface{}" || model == "interface{}" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
pkg, _ := code.PkgAndType(model)
|
|
||||||
if pkg == "" || inStrSlice(pkgs, pkg) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
pkgs = append(pkgs, code.QualifyPackagePath(pkg))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Slice(pkgs, func(i, j int) bool {
|
|
||||||
return pkgs[i] > pkgs[j]
|
|
||||||
})
|
|
||||||
return pkgs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tm TypeMap) Add(name string, goType string) {
|
|
||||||
modelCfg := tm[name]
|
|
||||||
modelCfg.Model = append(modelCfg.Model, goType)
|
|
||||||
tm[name] = modelCfg
|
|
||||||
}
|
|
||||||
|
|
||||||
type DirectiveConfig struct {
|
|
||||||
SkipRuntime bool `yaml:"skip_runtime"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func inStrSlice(haystack []string, needle string) bool {
|
|
||||||
for _, v := range haystack {
|
|
||||||
if needle == v {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// findCfg searches for the config file in this directory and all parents up the tree
|
|
||||||
// looking for the closest match
|
|
||||||
func findCfg() (string, error) {
|
|
||||||
dir, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
return "", fmt.Errorf("unable to get working dir to findCfg: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg := findCfgInDir(dir)
|
|
||||||
|
|
||||||
for cfg == "" && dir != filepath.Dir(dir) {
|
|
||||||
dir = filepath.Dir(dir)
|
|
||||||
cfg = findCfgInDir(dir)
|
|
||||||
}
|
|
||||||
|
|
||||||
if cfg == "" {
|
|
||||||
return "", os.ErrNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
return cfg, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func findCfgInDir(dir string) string {
|
|
||||||
for _, cfgName := range cfgFilenames {
|
|
||||||
path := filepath.Join(dir, cfgName)
|
|
||||||
if _, err := os.Stat(path); err == nil {
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) autobind() error {
|
|
||||||
if len(c.AutoBind) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
ps := c.Packages.LoadAll(c.AutoBind...)
|
|
||||||
|
|
||||||
for _, t := range c.Schema.Types {
|
|
||||||
if c.Models.UserDefined(t.Name) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, p := range ps {
|
|
||||||
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 {
|
|
||||||
c.Models.Add(t.Name(), t.Pkg().Path()+"."+t.Name())
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, t := range c.Models {
|
|
||||||
for j, m := range t.Model {
|
|
||||||
pkg, typename := code.PkgAndType(m)
|
|
||||||
|
|
||||||
// skip anything that looks like an import path
|
|
||||||
if strings.Contains(pkg, "/") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, p := range ps {
|
|
||||||
if p.Name != pkg {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if t := p.Types.Scope().Lookup(typename); t != nil {
|
|
||||||
c.Models[i].Model[j] = t.Pkg().Path() + "." + t.Name()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) injectBuiltins() {
|
|
||||||
builtins := TypeMap{
|
|
||||||
"__Directive": {Model: StringList{"github.com/99designs/gqlgen/graphql/introspection.Directive"}},
|
|
||||||
"__DirectiveLocation": {Model: StringList{"github.com/99designs/gqlgen/graphql.String"}},
|
|
||||||
"__Type": {Model: StringList{"github.com/99designs/gqlgen/graphql/introspection.Type"}},
|
|
||||||
"__TypeKind": {Model: StringList{"github.com/99designs/gqlgen/graphql.String"}},
|
|
||||||
"__Field": {Model: StringList{"github.com/99designs/gqlgen/graphql/introspection.Field"}},
|
|
||||||
"__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.FloatContext"}},
|
|
||||||
"String": {Model: StringList{"github.com/99designs/gqlgen/graphql.String"}},
|
|
||||||
"Boolean": {Model: StringList{"github.com/99designs/gqlgen/graphql.Boolean"}},
|
|
||||||
"Int": {Model: StringList{
|
|
||||||
"github.com/99designs/gqlgen/graphql.Int",
|
|
||||||
"github.com/99designs/gqlgen/graphql.Int32",
|
|
||||||
"github.com/99designs/gqlgen/graphql.Int64",
|
|
||||||
}},
|
|
||||||
"ID": {
|
|
||||||
Model: StringList{
|
|
||||||
"github.com/99designs/gqlgen/graphql.ID",
|
|
||||||
"github.com/99designs/gqlgen/graphql.IntID",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for typeName, entry := range builtins {
|
|
||||||
if !c.Models.Exists(typeName) {
|
|
||||||
c.Models[typeName] = entry
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// These are additional types that are injected if defined in the schema as scalars.
|
|
||||||
extraBuiltins := TypeMap{
|
|
||||||
"Time": {Model: StringList{"github.com/99designs/gqlgen/graphql.Time"}},
|
|
||||||
"Map": {Model: StringList{"github.com/99designs/gqlgen/graphql.Map"}},
|
|
||||||
"Upload": {Model: StringList{"github.com/99designs/gqlgen/graphql.Upload"}},
|
|
||||||
"Any": {Model: StringList{"github.com/99designs/gqlgen/graphql.Any"}},
|
|
||||||
}
|
|
||||||
|
|
||||||
for typeName, entry := range extraBuiltins {
|
|
||||||
if t, ok := c.Schema.Types[typeName]; !c.Models.Exists(typeName) && ok && t.Kind == ast.Scalar {
|
|
||||||
c.Models[typeName] = entry
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) LoadSchema() error {
|
|
||||||
if c.Packages != nil {
|
|
||||||
c.Packages = &code.Packages{}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.check(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
schema, err := gqlparser.LoadSchema(c.Sources...)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if schema.Query == nil {
|
|
||||||
schema.Query = &ast.Definition{
|
|
||||||
Kind: ast.Object,
|
|
||||||
Name: "Query",
|
|
||||||
}
|
|
||||||
schema.Types["Query"] = schema.Query
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Schema = schema
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func abs(path string) string {
|
|
||||||
absPath, err := filepath.Abs(path)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return filepath.ToSlash(absPath)
|
|
||||||
}
|
|
||||||
97
vendor/github.com/99designs/gqlgen/codegen/config/exec.go
generated
vendored
97
vendor/github.com/99designs/gqlgen/codegen/config/exec.go
generated
vendored
@@ -1,97 +0,0 @@
|
|||||||
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 != ""
|
|
||||||
}
|
|
||||||
62
vendor/github.com/99designs/gqlgen/codegen/config/package.go
generated
vendored
62
vendor/github.com/99designs/gqlgen/codegen/config/package.go
generated
vendored
@@ -1,62 +0,0 @@
|
|||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"go/types"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/internal/code"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PackageConfig struct {
|
|
||||||
Filename string `yaml:"filename,omitempty"`
|
|
||||||
Package string `yaml:"package,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *PackageConfig) ImportPath() string {
|
|
||||||
if !c.IsDefined() {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return code.ImportPathForDir(c.Dir())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *PackageConfig) Dir() string {
|
|
||||||
if !c.IsDefined() {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return filepath.Dir(c.Filename)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *PackageConfig) Pkg() *types.Package {
|
|
||||||
if !c.IsDefined() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return types.NewPackage(c.ImportPath(), c.Package)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *PackageConfig) IsDefined() bool {
|
|
||||||
return c.Filename != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *PackageConfig) Check() error {
|
|
||||||
if strings.ContainsAny(c.Package, "./\\") {
|
|
||||||
return fmt.Errorf("package should be the output package name only, do not include the output filename")
|
|
||||||
}
|
|
||||||
if c.Filename == "" {
|
|
||||||
return fmt.Errorf("filename must be specified")
|
|
||||||
}
|
|
||||||
if !strings.HasSuffix(c.Filename, ".go") {
|
|
||||||
return fmt.Errorf("filename should be path to a go source file")
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Filename = abs(c.Filename)
|
|
||||||
|
|
||||||
// If Package is not set, first attempt to load the package at the output dir. If that fails
|
|
||||||
// fallback to just the base dir name of the output filename.
|
|
||||||
if c.Package == "" {
|
|
||||||
c.Package = code.NameForDir(c.Dir())
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
100
vendor/github.com/99designs/gqlgen/codegen/config/resolver.go
generated
vendored
100
vendor/github.com/99designs/gqlgen/codegen/config/resolver.go
generated
vendored
@@ -1,100 +0,0 @@
|
|||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"go/types"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/internal/code"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ResolverConfig struct {
|
|
||||||
Filename string `yaml:"filename,omitempty"`
|
|
||||||
FilenameTemplate string `yaml:"filename_template,omitempty"`
|
|
||||||
Package string `yaml:"package,omitempty"`
|
|
||||||
Type string `yaml:"type,omitempty"`
|
|
||||||
Layout ResolverLayout `yaml:"layout,omitempty"`
|
|
||||||
DirName string `yaml:"dir"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResolverLayout string
|
|
||||||
|
|
||||||
var (
|
|
||||||
LayoutSingleFile ResolverLayout = "single-file"
|
|
||||||
LayoutFollowSchema ResolverLayout = "follow-schema"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (r *ResolverConfig) Check() error {
|
|
||||||
if r.Layout == "" {
|
|
||||||
r.Layout = LayoutSingleFile
|
|
||||||
}
|
|
||||||
if r.Type == "" {
|
|
||||||
r.Type = "Resolver"
|
|
||||||
}
|
|
||||||
|
|
||||||
switch r.Layout {
|
|
||||||
case LayoutSingleFile:
|
|
||||||
if r.Filename == "" {
|
|
||||||
return fmt.Errorf("filename must be specified with layout=%s", r.Layout)
|
|
||||||
}
|
|
||||||
if !strings.HasSuffix(r.Filename, ".go") {
|
|
||||||
return fmt.Errorf("filename should be path to a go source file with layout=%s", r.Layout)
|
|
||||||
}
|
|
||||||
r.Filename = abs(r.Filename)
|
|
||||||
case LayoutFollowSchema:
|
|
||||||
if r.DirName == "" {
|
|
||||||
return fmt.Errorf("dirname must be specified with layout=%s", r.Layout)
|
|
||||||
}
|
|
||||||
r.DirName = abs(r.DirName)
|
|
||||||
if r.Filename == "" {
|
|
||||||
r.Filename = filepath.Join(r.DirName, "resolver.go")
|
|
||||||
} else {
|
|
||||||
r.Filename = abs(r.Filename)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("invalid layout %s. must be %s or %s", r.Layout, LayoutSingleFile, LayoutFollowSchema)
|
|
||||||
}
|
|
||||||
|
|
||||||
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 *ResolverConfig) ImportPath() string {
|
|
||||||
if r.Dir() == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return code.ImportPathForDir(r.Dir())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ResolverConfig) Dir() string {
|
|
||||||
switch r.Layout {
|
|
||||||
case LayoutSingleFile:
|
|
||||||
if r.Filename == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return filepath.Dir(r.Filename)
|
|
||||||
case LayoutFollowSchema:
|
|
||||||
return r.DirName
|
|
||||||
default:
|
|
||||||
panic("invalid layout " + r.Layout)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ResolverConfig) Pkg() *types.Package {
|
|
||||||
if r.Dir() == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return types.NewPackage(r.ImportPath(), r.Package)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ResolverConfig) IsDefined() bool {
|
|
||||||
return r.Filename != "" || r.DirName != ""
|
|
||||||
}
|
|
||||||
185
vendor/github.com/99designs/gqlgen/codegen/data.go
generated
vendored
185
vendor/github.com/99designs/gqlgen/codegen/data.go
generated
vendored
@@ -1,185 +0,0 @@
|
|||||||
package codegen
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
"github.com/vektah/gqlparser/v2/ast"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/codegen/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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
|
|
||||||
// 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
|
|
||||||
ReferencedTypes map[string]*config.TypeReference
|
|
||||||
ComplexityRoots map[string]*Object
|
|
||||||
|
|
||||||
QueryRoot *Object
|
|
||||||
MutationRoot *Object
|
|
||||||
SubscriptionRoot *Object
|
|
||||||
}
|
|
||||||
|
|
||||||
type builder struct {
|
|
||||||
Config *config.Config
|
|
||||||
Schema *ast.Schema
|
|
||||||
Binder *config.Binder
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
|
|
||||||
b.Binder = b.Config.NewBinder()
|
|
||||||
|
|
||||||
var err error
|
|
||||||
b.Directives, err = b.buildDirectives()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
dataDirectives := make(map[string]*Directive)
|
|
||||||
for name, d := range b.Directives {
|
|
||||||
if !d.Builtin {
|
|
||||||
dataDirectives[name] = d
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s := Data{
|
|
||||||
Config: cfg,
|
|
||||||
AllDirectives: dataDirectives,
|
|
||||||
Schema: b.Schema,
|
|
||||||
Interfaces: map[string]*Interface{},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, schemaType := range b.Schema.Types {
|
|
||||||
switch schemaType.Kind {
|
|
||||||
case ast.Object:
|
|
||||||
obj, err := b.buildObject(schemaType)
|
|
||||||
if err != nil {
|
|
||||||
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, fmt.Errorf("unable to build input definition: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
s.Inputs = append(s.Inputs, input)
|
|
||||||
|
|
||||||
case ast.Union, ast.Interface:
|
|
||||||
s.Interfaces[schemaType.Name], err = b.buildInterface(schemaType)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("unable to bind to interface: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.Schema.Query != nil {
|
|
||||||
s.QueryRoot = s.Objects.ByName(s.Schema.Query.Name)
|
|
||||||
} else {
|
|
||||||
return nil, fmt.Errorf("query entry point missing")
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.Schema.Mutation != nil {
|
|
||||||
s.MutationRoot = s.Objects.ByName(s.Schema.Mutation.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.Schema.Subscription != nil {
|
|
||||||
s.SubscriptionRoot = s.Objects.ByName(s.Schema.Subscription.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := b.injectIntrospectionRoots(&s); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
s.ReferencedTypes = b.buildTypes()
|
|
||||||
|
|
||||||
sort.Slice(s.Objects, func(i, j int) bool {
|
|
||||||
return s.Objects[i].Definition.Name < s.Objects[j].Definition.Name
|
|
||||||
})
|
|
||||||
|
|
||||||
sort.Slice(s.Inputs, func(i, j int) bool {
|
|
||||||
return s.Inputs[i].Definition.Name < s.Inputs[j].Definition.Name
|
|
||||||
})
|
|
||||||
|
|
||||||
if b.Binder.SawInvalid {
|
|
||||||
// if we have a syntax error, show it
|
|
||||||
err := cfg.Packages.Errors()
|
|
||||||
if len(err) > 0 {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise show a generic error message
|
|
||||||
return nil, fmt.Errorf("invalid types were encountered while traversing the go source code, this probably means the invalid code generated isnt correct. add try adding -v to debug")
|
|
||||||
}
|
|
||||||
|
|
||||||
return &s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *builder) injectIntrospectionRoots(s *Data) error {
|
|
||||||
obj := s.Objects.ByName(b.Schema.Query.Name)
|
|
||||||
if obj == nil {
|
|
||||||
return fmt.Errorf("root query type must be defined")
|
|
||||||
}
|
|
||||||
|
|
||||||
__type, err := b.buildField(obj, &ast.FieldDefinition{
|
|
||||||
Name: "__type",
|
|
||||||
Type: ast.NamedType("__Type", nil),
|
|
||||||
Arguments: []*ast.ArgumentDefinition{
|
|
||||||
{
|
|
||||||
Name: "name",
|
|
||||||
Type: ast.NonNullNamedType("String", nil),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
__schema, err := b.buildField(obj, &ast.FieldDefinition{
|
|
||||||
Name: "__schema",
|
|
||||||
Type: ast.NamedType("__Schema", nil),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.Fields = append(obj.Fields, __type, __schema)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
174
vendor/github.com/99designs/gqlgen/codegen/directive.go
generated
vendored
174
vendor/github.com/99designs/gqlgen/codegen/directive.go
generated
vendored
@@ -1,174 +0,0 @@
|
|||||||
package codegen
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/codegen/templates"
|
|
||||||
"github.com/vektah/gqlparser/v2/ast"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DirectiveList map[string]*Directive
|
|
||||||
|
|
||||||
// LocationDirectives filter directives by location
|
|
||||||
func (dl DirectiveList) LocationDirectives(location string) DirectiveList {
|
|
||||||
return locationDirectives(dl, ast.DirectiveLocation(location))
|
|
||||||
}
|
|
||||||
|
|
||||||
type Directive struct {
|
|
||||||
*ast.DirectiveDefinition
|
|
||||||
Name string
|
|
||||||
Args []*FieldArgument
|
|
||||||
Builtin bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsLocation check location directive
|
|
||||||
func (d *Directive) IsLocation(location ...ast.DirectiveLocation) bool {
|
|
||||||
for _, l := range d.Locations {
|
|
||||||
for _, a := range location {
|
|
||||||
if l == a {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func locationDirectives(directives DirectiveList, location ...ast.DirectiveLocation) map[string]*Directive {
|
|
||||||
mDirectives := make(map[string]*Directive)
|
|
||||||
for name, d := range directives {
|
|
||||||
if d.IsLocation(location...) {
|
|
||||||
mDirectives[name] = d
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mDirectives
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *builder) buildDirectives() (map[string]*Directive, error) {
|
|
||||||
directives := make(map[string]*Directive, len(b.Schema.Directives))
|
|
||||||
|
|
||||||
for name, dir := range b.Schema.Directives {
|
|
||||||
if _, ok := directives[name]; ok {
|
|
||||||
return nil, fmt.Errorf("directive with name %s already exists", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
var args []*FieldArgument
|
|
||||||
for _, arg := range dir.Arguments {
|
|
||||||
tr, err := b.Binder.TypeReference(arg.Type, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
newArg := &FieldArgument{
|
|
||||||
ArgumentDefinition: arg,
|
|
||||||
TypeReference: tr,
|
|
||||||
VarName: templates.ToGoPrivate(arg.Name),
|
|
||||||
}
|
|
||||||
|
|
||||||
if arg.DefaultValue != nil {
|
|
||||||
var err error
|
|
||||||
newArg.Default, err = arg.DefaultValue.Value(nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("default value for directive argument %s(%s) is not valid: %w", dir.Name, arg.Name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
args = append(args, newArg)
|
|
||||||
}
|
|
||||||
|
|
||||||
directives[name] = &Directive{
|
|
||||||
DirectiveDefinition: dir,
|
|
||||||
Name: name,
|
|
||||||
Args: args,
|
|
||||||
Builtin: b.Config.Directives[name].SkipRuntime,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return directives, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *builder) getDirectives(list ast.DirectiveList) ([]*Directive, error) {
|
|
||||||
dirs := make([]*Directive, len(list))
|
|
||||||
for i, d := range list {
|
|
||||||
argValues := make(map[string]interface{}, len(d.Arguments))
|
|
||||||
for _, da := range d.Arguments {
|
|
||||||
val, err := da.Value.Value(nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
argValues[da.Name] = val
|
|
||||||
}
|
|
||||||
def, ok := b.Directives[d.Name]
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("directive %s not found", d.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
var args []*FieldArgument
|
|
||||||
for _, a := range def.Args {
|
|
||||||
value := a.Default
|
|
||||||
if argValue, ok := argValues[a.Name]; ok {
|
|
||||||
value = argValue
|
|
||||||
}
|
|
||||||
args = append(args, &FieldArgument{
|
|
||||||
ArgumentDefinition: a.ArgumentDefinition,
|
|
||||||
Value: value,
|
|
||||||
VarName: a.VarName,
|
|
||||||
TypeReference: a.TypeReference,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
dirs[i] = &Directive{
|
|
||||||
Name: d.Name,
|
|
||||||
Args: args,
|
|
||||||
DirectiveDefinition: list[i].Definition,
|
|
||||||
Builtin: b.Config.Directives[d.Name].SkipRuntime,
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return dirs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Directive) ArgsFunc() string {
|
|
||||||
if len(d.Args) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return "dir_" + d.Name + "_args"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Directive) CallArgs() string {
|
|
||||||
args := []string{"ctx", "obj", "n"}
|
|
||||||
|
|
||||||
for _, arg := range d.Args {
|
|
||||||
args = append(args, "args["+strconv.Quote(arg.Name)+"].("+templates.CurrentImports.LookupType(arg.TypeReference.GO)+")")
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.Join(args, ", ")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Directive) ResolveArgs(obj string, next int) string {
|
|
||||||
args := []string{"ctx", obj, fmt.Sprintf("directive%d", next)}
|
|
||||||
|
|
||||||
for _, arg := range d.Args {
|
|
||||||
dArg := arg.VarName
|
|
||||||
if arg.Value == nil && arg.Default == nil {
|
|
||||||
dArg = "nil"
|
|
||||||
}
|
|
||||||
|
|
||||||
args = append(args, dArg)
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.Join(args, ", ")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Directive) Declaration() string {
|
|
||||||
res := ucFirst(d.Name) + " func(ctx context.Context, obj interface{}, next graphql.Resolver"
|
|
||||||
|
|
||||||
for _, arg := range d.Args {
|
|
||||||
res += fmt.Sprintf(", %s %s", templates.ToGoPrivate(arg.Name), templates.CurrentImports.LookupType(arg.TypeReference.GO))
|
|
||||||
}
|
|
||||||
|
|
||||||
res += ") (res interface{}, err error)"
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
149
vendor/github.com/99designs/gqlgen/codegen/directives.gotpl
generated
vendored
149
vendor/github.com/99designs/gqlgen/codegen/directives.gotpl
generated
vendored
@@ -1,149 +0,0 @@
|
|||||||
{{ define "implDirectives" }}{{ $in := .DirectiveObjName }}
|
|
||||||
{{- range $i, $directive := .ImplDirectives -}}
|
|
||||||
directive{{add $i 1}} := func(ctx context.Context) (interface{}, error) {
|
|
||||||
{{- range $arg := $directive.Args }}
|
|
||||||
{{- if notNil "Value" $arg }}
|
|
||||||
{{ $arg.VarName }}, err := ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, {{ $arg.Value | dump }})
|
|
||||||
if err != nil{
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
{{- else if notNil "Default" $arg }}
|
|
||||||
{{ $arg.VarName }}, err := ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, {{ $arg.Default | dump }})
|
|
||||||
if err != nil{
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
if ec.directives.{{$directive.Name|ucFirst}} == nil {
|
|
||||||
return nil, errors.New("directive {{$directive.Name}} is not implemented")
|
|
||||||
}
|
|
||||||
return ec.directives.{{$directive.Name|ucFirst}}({{$directive.ResolveArgs $in $i }})
|
|
||||||
}
|
|
||||||
{{ end -}}
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
{{define "queryDirectives"}}
|
|
||||||
for _, d := range obj.Directives {
|
|
||||||
switch d.Name {
|
|
||||||
{{- range $directive := . }}
|
|
||||||
case "{{$directive.Name}}":
|
|
||||||
{{- if $directive.Args }}
|
|
||||||
rawArgs := d.ArgumentMap(ec.Variables)
|
|
||||||
args, err := ec.{{ $directive.ArgsFunc }}(ctx,rawArgs)
|
|
||||||
if err != nil {
|
|
||||||
ec.Error(ctx, err)
|
|
||||||
return graphql.Null
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
n := next
|
|
||||||
next = func(ctx context.Context) (interface{}, error) {
|
|
||||||
if ec.directives.{{$directive.Name|ucFirst}} == nil {
|
|
||||||
return nil, errors.New("directive {{$directive.Name}} is not implemented")
|
|
||||||
}
|
|
||||||
return ec.directives.{{$directive.Name|ucFirst}}({{$directive.CallArgs}})
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tmp, err := next(ctx)
|
|
||||||
if err != nil {
|
|
||||||
ec.Error(ctx, err)
|
|
||||||
return graphql.Null
|
|
||||||
}
|
|
||||||
if data, ok := tmp.(graphql.Marshaler); ok {
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
ec.Errorf(ctx, `unexpected type %T from directive, should be graphql.Marshaler`, tmp)
|
|
||||||
return graphql.Null
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
{{ if .Directives.LocationDirectives "QUERY" }}
|
|
||||||
func (ec *executionContext) _queryMiddleware(ctx context.Context, obj *ast.OperationDefinition, next func(ctx context.Context) (interface{}, error)) graphql.Marshaler {
|
|
||||||
{{ template "queryDirectives" .Directives.LocationDirectives "QUERY" }}
|
|
||||||
}
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
{{ if .Directives.LocationDirectives "MUTATION" }}
|
|
||||||
func (ec *executionContext) _mutationMiddleware(ctx context.Context, obj *ast.OperationDefinition, next func(ctx context.Context) (interface{}, error)) graphql.Marshaler {
|
|
||||||
{{ template "queryDirectives" .Directives.LocationDirectives "MUTATION" }}
|
|
||||||
}
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
{{ if .Directives.LocationDirectives "SUBSCRIPTION" }}
|
|
||||||
func (ec *executionContext) _subscriptionMiddleware(ctx context.Context, obj *ast.OperationDefinition, next func(ctx context.Context) (interface{}, error)) func() graphql.Marshaler {
|
|
||||||
for _, d := range obj.Directives {
|
|
||||||
switch d.Name {
|
|
||||||
{{- range $directive := .Directives.LocationDirectives "SUBSCRIPTION" }}
|
|
||||||
case "{{$directive.Name}}":
|
|
||||||
{{- if $directive.Args }}
|
|
||||||
rawArgs := d.ArgumentMap(ec.Variables)
|
|
||||||
args, err := ec.{{ $directive.ArgsFunc }}(ctx,rawArgs)
|
|
||||||
if err != nil {
|
|
||||||
ec.Error(ctx, err)
|
|
||||||
return func() graphql.Marshaler {
|
|
||||||
return graphql.Null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
n := next
|
|
||||||
next = func(ctx context.Context) (interface{}, error) {
|
|
||||||
if ec.directives.{{$directive.Name|ucFirst}} == nil {
|
|
||||||
return nil, errors.New("directive {{$directive.Name}} is not implemented")
|
|
||||||
}
|
|
||||||
return ec.directives.{{$directive.Name|ucFirst}}({{$directive.CallArgs}})
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tmp, err := next(ctx)
|
|
||||||
if err != nil {
|
|
||||||
ec.Error(ctx, err)
|
|
||||||
return func() graphql.Marshaler {
|
|
||||||
return graphql.Null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if data, ok := tmp.(func() graphql.Marshaler); ok {
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
ec.Errorf(ctx, `unexpected type %T from directive, should be graphql.Marshaler`, tmp)
|
|
||||||
return func() graphql.Marshaler {
|
|
||||||
return graphql.Null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
{{ if .Directives.LocationDirectives "FIELD" }}
|
|
||||||
func (ec *executionContext) _fieldMiddleware(ctx context.Context, obj interface{}, next graphql.Resolver) interface{} {
|
|
||||||
{{- if .Directives.LocationDirectives "FIELD" }}
|
|
||||||
fc := graphql.GetFieldContext(ctx)
|
|
||||||
for _, d := range fc.Field.Directives {
|
|
||||||
switch d.Name {
|
|
||||||
{{- range $directive := .Directives.LocationDirectives "FIELD" }}
|
|
||||||
case "{{$directive.Name}}":
|
|
||||||
{{- if $directive.Args }}
|
|
||||||
rawArgs := d.ArgumentMap(ec.Variables)
|
|
||||||
args, err := ec.{{ $directive.ArgsFunc }}(ctx,rawArgs)
|
|
||||||
if err != nil {
|
|
||||||
ec.Error(ctx, err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
n := next
|
|
||||||
next = func(ctx context.Context) (interface{}, error) {
|
|
||||||
if ec.directives.{{$directive.Name|ucFirst}} == nil {
|
|
||||||
return nil, errors.New("directive {{$directive.Name}} is not implemented")
|
|
||||||
}
|
|
||||||
return ec.directives.{{$directive.Name|ucFirst}}({{$directive.CallArgs}})
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
res, err := ec.ResolverMiddleware(ctx, next)
|
|
||||||
if err != nil {
|
|
||||||
ec.Error(ctx, err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
{{ end }}
|
|
||||||
556
vendor/github.com/99designs/gqlgen/codegen/field.go
generated
vendored
556
vendor/github.com/99designs/gqlgen/codegen/field.go
generated
vendored
@@ -1,556 +0,0 @@
|
|||||||
package codegen
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"go/types"
|
|
||||||
"log"
|
|
||||||
"reflect"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/codegen/config"
|
|
||||||
"github.com/99designs/gqlgen/codegen/templates"
|
|
||||||
"github.com/vektah/gqlparser/v2/ast"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Field struct {
|
|
||||||
*ast.FieldDefinition
|
|
||||||
|
|
||||||
TypeReference *config.TypeReference
|
|
||||||
GoFieldType GoFieldType // The field type in go, if any
|
|
||||||
GoReceiverName string // The name of method & var receiver in go, if any
|
|
||||||
GoFieldName string // The name of the method or var in go, if any
|
|
||||||
IsResolver bool // Does this field need a resolver
|
|
||||||
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?
|
|
||||||
Directives []*Directive
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *builder) buildField(obj *Object, field *ast.FieldDefinition) (*Field, error) {
|
|
||||||
dirs, err := b.getDirectives(field.Directives)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
f := Field{
|
|
||||||
FieldDefinition: field,
|
|
||||||
Object: obj,
|
|
||||||
Directives: dirs,
|
|
||||||
GoFieldName: templates.ToGo(field.Name),
|
|
||||||
GoFieldType: GoFieldVariable,
|
|
||||||
GoReceiverName: "obj",
|
|
||||||
}
|
|
||||||
|
|
||||||
if field.DefaultValue != nil {
|
|
||||||
var err error
|
|
||||||
f.Default, err = field.DefaultValue.Value(nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("default value %s is not valid: %w", field.Name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, arg := range field.Arguments {
|
|
||||||
newArg, err := b.buildArg(obj, arg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
f.Args = append(f.Args, newArg)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = b.bindField(obj, &f); err != nil {
|
|
||||||
f.IsResolver = true
|
|
||||||
if errors.Is(err, config.ErrTypeNotFound) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
log.Println(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if f.IsResolver && !f.TypeReference.IsPtr() && f.TypeReference.IsStruct() {
|
|
||||||
f.TypeReference = b.Binder.PointerTo(f.TypeReference)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &f, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *builder) bindField(obj *Object, f *Field) (errret error) {
|
|
||||||
defer func() {
|
|
||||||
if f.TypeReference == nil {
|
|
||||||
tr, err := b.Binder.TypeReference(f.Type, nil)
|
|
||||||
if err != nil {
|
|
||||||
errret = err
|
|
||||||
}
|
|
||||||
f.TypeReference = tr
|
|
||||||
}
|
|
||||||
if f.TypeReference != nil {
|
|
||||||
dirs, err := b.getDirectives(f.TypeReference.Definition.Directives)
|
|
||||||
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...)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
f.Stream = obj.Stream
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case f.Name == "__schema":
|
|
||||||
f.GoFieldType = GoFieldMethod
|
|
||||||
f.GoReceiverName = "ec"
|
|
||||||
f.GoFieldName = "introspectSchema"
|
|
||||||
return nil
|
|
||||||
case f.Name == "__type":
|
|
||||||
f.GoFieldType = GoFieldMethod
|
|
||||||
f.GoReceiverName = "ec"
|
|
||||||
f.GoFieldName = "introspectType"
|
|
||||||
return nil
|
|
||||||
case f.Name == "_entities":
|
|
||||||
f.GoFieldType = GoFieldMethod
|
|
||||||
f.GoReceiverName = "ec"
|
|
||||||
f.GoFieldName = "__resolve_entities"
|
|
||||||
f.MethodHasContext = true
|
|
||||||
f.NoErr = true
|
|
||||||
return nil
|
|
||||||
case f.Name == "_service":
|
|
||||||
f.GoFieldType = GoFieldMethod
|
|
||||||
f.GoReceiverName = "ec"
|
|
||||||
f.GoFieldName = "__resolve__service"
|
|
||||||
f.MethodHasContext = true
|
|
||||||
return nil
|
|
||||||
case obj.Root:
|
|
||||||
f.IsResolver = true
|
|
||||||
return nil
|
|
||||||
case b.Config.Models[obj.Name].Fields[f.Name].Resolver:
|
|
||||||
f.IsResolver = true
|
|
||||||
return nil
|
|
||||||
case obj.Type == config.MapType:
|
|
||||||
f.GoFieldType = GoFieldMap
|
|
||||||
return nil
|
|
||||||
case b.Config.Models[obj.Name].Fields[f.Name].FieldName != "":
|
|
||||||
f.GoFieldName = b.Config.Models[obj.Name].Fields[f.Name].FieldName
|
|
||||||
}
|
|
||||||
|
|
||||||
target, err := b.findBindTarget(obj.Type.(*types.Named), f.GoFieldName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
pos := b.Binder.ObjectPosition(target)
|
|
||||||
|
|
||||||
switch target := target.(type) {
|
|
||||||
case nil:
|
|
||||||
objPos := b.Binder.TypePosition(obj.Type)
|
|
||||||
return fmt.Errorf(
|
|
||||||
"%s:%d adding resolver method for %s.%s, nothing matched",
|
|
||||||
objPos.Filename,
|
|
||||||
objPos.Line,
|
|
||||||
obj.Name,
|
|
||||||
f.Name,
|
|
||||||
)
|
|
||||||
|
|
||||||
case *types.Func:
|
|
||||||
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")
|
|
||||||
}
|
|
||||||
params := sig.Params()
|
|
||||||
// If the first argument is the context, remove it from the comparison and set
|
|
||||||
// the MethodHasContext flag so that the context will be passed to this model's method
|
|
||||||
if params.Len() > 0 && params.At(0).Type().String() == "context.Context" {
|
|
||||||
f.MethodHasContext = true
|
|
||||||
vars := make([]*types.Var, params.Len()-1)
|
|
||||||
for i := 1; i < params.Len(); i++ {
|
|
||||||
vars[i-1] = params.At(i)
|
|
||||||
}
|
|
||||||
params = types.NewTuple(vars...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// success, args and return type match. Bind to method
|
|
||||||
f.GoFieldType = GoFieldMethod
|
|
||||||
f.GoReceiverName = "obj"
|
|
||||||
f.GoFieldName = target.Name()
|
|
||||||
f.Args = newArgs
|
|
||||||
f.TypeReference = tr
|
|
||||||
|
|
||||||
return nil
|
|
||||||
|
|
||||||
case *types.Var:
|
|
||||||
tr, err := b.Binder.TypeReference(f.Type, target.Type())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// success, bind to var
|
|
||||||
f.GoFieldType = GoFieldVariable
|
|
||||||
f.GoReceiverName = "obj"
|
|
||||||
f.GoFieldName = target.Name()
|
|
||||||
f.TypeReference = tr
|
|
||||||
|
|
||||||
return nil
|
|
||||||
default:
|
|
||||||
panic(fmt.Errorf("unknown bind target %T for %s", target, f.Name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// findBindTarget attempts to match the name to a field or method on a Type
|
|
||||||
// with the following priorites:
|
|
||||||
// 1. Any Fields with a struct tag (see config.StructTag). Errors if more than one match is found
|
|
||||||
// 2. Any method or field with a matching name. Errors if more than one match is found
|
|
||||||
// 3. Same logic again for embedded fields
|
|
||||||
func (b *builder) findBindTarget(t types.Type, name string) (types.Object, error) {
|
|
||||||
// NOTE: a struct tag will override both methods and fields
|
|
||||||
// Bind to struct tag
|
|
||||||
found, err := b.findBindStructTagTarget(t, name)
|
|
||||||
if found != nil || err != nil {
|
|
||||||
return found, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search for a method to bind to
|
|
||||||
foundMethod, err := b.findBindMethodTarget(t, name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search for a field to bind to
|
|
||||||
foundField, err := b.findBindFieldTarget(t, name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case foundField == nil && foundMethod != nil:
|
|
||||||
// Bind to method
|
|
||||||
return foundMethod, nil
|
|
||||||
case foundField != nil && foundMethod == nil:
|
|
||||||
// Bind to field
|
|
||||||
return foundField, nil
|
|
||||||
case foundField != nil && foundMethod != nil:
|
|
||||||
// Error
|
|
||||||
return nil, fmt.Errorf("found more than one way to bind for %s", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search embeds
|
|
||||||
return b.findBindEmbedsTarget(t, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *builder) findBindStructTagTarget(in types.Type, name string) (types.Object, error) {
|
|
||||||
if b.Config.StructTag == "" {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
switch t := in.(type) {
|
|
||||||
case *types.Named:
|
|
||||||
return b.findBindStructTagTarget(t.Underlying(), name)
|
|
||||||
case *types.Struct:
|
|
||||||
var found types.Object
|
|
||||||
for i := 0; i < t.NumFields(); i++ {
|
|
||||||
field := t.Field(i)
|
|
||||||
if !field.Exported() || field.Embedded() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
tags := reflect.StructTag(t.Tag(i))
|
|
||||||
if val, ok := tags.Lookup(b.Config.StructTag); ok && equalFieldName(val, name) {
|
|
||||||
if found != nil {
|
|
||||||
return nil, fmt.Errorf("tag %s is ambigious; multiple fields have the same tag value of %s", b.Config.StructTag, val)
|
|
||||||
}
|
|
||||||
|
|
||||||
found = field
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return found, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *builder) findBindMethodTarget(in types.Type, name string) (types.Object, error) {
|
|
||||||
switch t := in.(type) {
|
|
||||||
case *types.Named:
|
|
||||||
if _, ok := t.Underlying().(*types.Interface); ok {
|
|
||||||
return b.findBindMethodTarget(t.Underlying(), name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return b.findBindMethoderTarget(t.Method, t.NumMethods(), name)
|
|
||||||
case *types.Interface:
|
|
||||||
// FIX-ME: Should use ExplicitMethod here? What's the difference?
|
|
||||||
return b.findBindMethoderTarget(t.Method, t.NumMethods(), name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *builder) findBindMethoderTarget(methodFunc func(i int) *types.Func, methodCount int, name string) (types.Object, error) {
|
|
||||||
var found types.Object
|
|
||||||
for i := 0; i < methodCount; i++ {
|
|
||||||
method := methodFunc(i)
|
|
||||||
if !method.Exported() || !strings.EqualFold(method.Name(), name) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if found != nil {
|
|
||||||
return nil, fmt.Errorf("found more than one matching method to bind for %s", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
found = method
|
|
||||||
}
|
|
||||||
|
|
||||||
return found, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *builder) findBindFieldTarget(in types.Type, name string) (types.Object, error) {
|
|
||||||
switch t := in.(type) {
|
|
||||||
case *types.Named:
|
|
||||||
return b.findBindFieldTarget(t.Underlying(), name)
|
|
||||||
case *types.Struct:
|
|
||||||
var found types.Object
|
|
||||||
for i := 0; i < t.NumFields(); i++ {
|
|
||||||
field := t.Field(i)
|
|
||||||
if !field.Exported() || !equalFieldName(field.Name(), name) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if found != nil {
|
|
||||||
return nil, fmt.Errorf("found more than one matching field to bind for %s", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
found = field
|
|
||||||
}
|
|
||||||
|
|
||||||
return found, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *builder) findBindEmbedsTarget(in types.Type, name string) (types.Object, error) {
|
|
||||||
switch t := in.(type) {
|
|
||||||
case *types.Named:
|
|
||||||
return b.findBindEmbedsTarget(t.Underlying(), name)
|
|
||||||
case *types.Struct:
|
|
||||||
return b.findBindStructEmbedsTarget(t, name)
|
|
||||||
case *types.Interface:
|
|
||||||
return b.findBindInterfaceEmbedsTarget(t, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *builder) findBindStructEmbedsTarget(strukt *types.Struct, name string) (types.Object, error) {
|
|
||||||
var found types.Object
|
|
||||||
for i := 0; i < strukt.NumFields(); i++ {
|
|
||||||
field := strukt.Field(i)
|
|
||||||
if !field.Embedded() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldType := field.Type()
|
|
||||||
if ptr, ok := fieldType.(*types.Pointer); ok {
|
|
||||||
fieldType = ptr.Elem()
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := b.findBindTarget(fieldType, name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if f != nil && found != nil {
|
|
||||||
return nil, fmt.Errorf("found more than one way to bind for %s", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
if f != nil {
|
|
||||||
found = f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return found, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *builder) findBindInterfaceEmbedsTarget(iface *types.Interface, name string) (types.Object, error) {
|
|
||||||
var found types.Object
|
|
||||||
for i := 0; i < iface.NumEmbeddeds(); i++ {
|
|
||||||
embeddedType := iface.EmbeddedType(i)
|
|
||||||
|
|
||||||
f, err := b.findBindTarget(embeddedType, name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if f != nil && found != nil {
|
|
||||||
return nil, fmt.Errorf("found more than one way to bind for %s", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
if f != nil {
|
|
||||||
found = f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return found, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Field) HasDirectives() bool {
|
|
||||||
return len(f.ImplDirectives()) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Field) DirectiveObjName() string {
|
|
||||||
if f.Object.Root {
|
|
||||||
return "nil"
|
|
||||||
}
|
|
||||||
return f.GoReceiverName
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Field) ImplDirectives() []*Directive {
|
|
||||||
var d []*Directive
|
|
||||||
loc := ast.LocationFieldDefinition
|
|
||||||
if f.Object.IsInputType() {
|
|
||||||
loc = ast.LocationInputFieldDefinition
|
|
||||||
}
|
|
||||||
for i := range f.Directives {
|
|
||||||
if !f.Directives[i].Builtin &&
|
|
||||||
(f.Directives[i].IsLocation(loc, ast.LocationObject) || f.Directives[i].IsLocation(loc, ast.LocationInputObject)) {
|
|
||||||
d = append(d, f.Directives[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return d
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Field) IsReserved() bool {
|
|
||||||
return strings.HasPrefix(f.Name, "__")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Field) IsMethod() bool {
|
|
||||||
return f.GoFieldType == GoFieldMethod
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Field) IsVariable() bool {
|
|
||||||
return f.GoFieldType == GoFieldVariable
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Field) IsMap() bool {
|
|
||||||
return f.GoFieldType == GoFieldMap
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Field) IsConcurrent() bool {
|
|
||||||
if f.Object.DisableConcurrency {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return f.MethodHasContext || f.IsResolver
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Field) GoNameUnexported() string {
|
|
||||||
return templates.ToGoPrivate(f.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Field) ShortInvocation() string {
|
|
||||||
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 {
|
|
||||||
if len(f.Args) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return "field_" + f.Object.Definition.Name + "_" + f.Name + "_args"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Field) ResolverType() string {
|
|
||||||
if !f.IsResolver {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%s().%s(%s)", f.Object.Definition.Name, f.GoFieldName, f.CallArgs())
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
res += fmt.Sprintf(", obj %s", templates.CurrentImports.LookupType(f.Object.Reference()))
|
|
||||||
}
|
|
||||||
for _, arg := range f.Args {
|
|
||||||
res += fmt.Sprintf(", %s %s", arg.VarName, templates.CurrentImports.LookupType(arg.TypeReference.GO))
|
|
||||||
}
|
|
||||||
|
|
||||||
result := templates.CurrentImports.LookupType(f.TypeReference.GO)
|
|
||||||
if f.Object.Stream {
|
|
||||||
result = "<-chan " + result
|
|
||||||
}
|
|
||||||
|
|
||||||
res += fmt.Sprintf(") (%s, error)", result)
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Field) ComplexitySignature() string {
|
|
||||||
res := "func(childComplexity int"
|
|
||||||
for _, arg := range f.Args {
|
|
||||||
res += fmt.Sprintf(", %s %s", arg.VarName, templates.CurrentImports.LookupType(arg.TypeReference.GO))
|
|
||||||
}
|
|
||||||
res += ") int"
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Field) ComplexityArgs() string {
|
|
||||||
args := make([]string, len(f.Args))
|
|
||||||
for i, arg := range f.Args {
|
|
||||||
args[i] = "args[" + strconv.Quote(arg.Name) + "].(" + templates.CurrentImports.LookupType(arg.TypeReference.GO) + ")"
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.Join(args, ", ")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Field) CallArgs() string {
|
|
||||||
args := make([]string, 0, len(f.Args)+2)
|
|
||||||
|
|
||||||
if f.IsResolver {
|
|
||||||
args = append(args, "rctx")
|
|
||||||
|
|
||||||
if !f.Object.Root {
|
|
||||||
args = append(args, "obj")
|
|
||||||
}
|
|
||||||
} else if f.MethodHasContext {
|
|
||||||
args = append(args, "ctx")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, arg := range f.Args {
|
|
||||||
args = append(args, "args["+strconv.Quote(arg.Name)+"].("+templates.CurrentImports.LookupType(arg.TypeReference.GO)+")")
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.Join(args, ", ")
|
|
||||||
}
|
|
||||||
129
vendor/github.com/99designs/gqlgen/codegen/field.gotpl
generated
vendored
129
vendor/github.com/99designs/gqlgen/codegen/field.gotpl
generated
vendored
@@ -1,129 +0,0 @@
|
|||||||
{{- range $object := .Objects }}{{- range $field := $object.Fields }}
|
|
||||||
|
|
||||||
func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Context, field graphql.CollectedField{{ if not $object.Root }}, obj {{$object.Reference | ref}}{{end}}) (ret {{ if $object.Stream }}func(){{ end }}graphql.Marshaler) {
|
|
||||||
{{- $null := "graphql.Null" }}
|
|
||||||
{{- if $object.Stream }}
|
|
||||||
{{- $null = "nil" }}
|
|
||||||
{{- end }}
|
|
||||||
defer func () {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
ec.Error(ctx, ec.Recover(ctx, r))
|
|
||||||
ret = {{ $null }}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
fc := &graphql.FieldContext{
|
|
||||||
Object: {{$object.Name|quote}},
|
|
||||||
Field: field,
|
|
||||||
Args: nil,
|
|
||||||
IsMethod: {{or $field.IsMethod $field.IsResolver}},
|
|
||||||
IsResolver: {{ $field.IsResolver }},
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = graphql.WithFieldContext(ctx, fc)
|
|
||||||
{{- if $field.Args }}
|
|
||||||
rawArgs := field.ArgumentMap(ec.Variables)
|
|
||||||
args, err := ec.{{ $field.ArgsFunc }}(ctx,rawArgs)
|
|
||||||
if err != nil {
|
|
||||||
ec.Error(ctx, err)
|
|
||||||
return {{ $null }}
|
|
||||||
}
|
|
||||||
fc.Args = args
|
|
||||||
{{- end }}
|
|
||||||
{{- if $.AllDirectives.LocationDirectives "FIELD" }}
|
|
||||||
resTmp := ec._fieldMiddleware(ctx, {{if $object.Root}}nil{{else}}obj{{end}}, func(rctx context.Context) (interface{}, error) {
|
|
||||||
{{ template "field" $field }}
|
|
||||||
})
|
|
||||||
{{ else }}
|
|
||||||
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
|
||||||
{{ template "field" $field }}
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
ec.Error(ctx, err)
|
|
||||||
return {{ $null }}
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
if resTmp == nil {
|
|
||||||
{{- if $field.TypeReference.GQL.NonNull }}
|
|
||||||
if !graphql.HasFieldError(ctx, fc) {
|
|
||||||
ec.Errorf(ctx, "must not be null")
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
return {{ $null }}
|
|
||||||
}
|
|
||||||
{{- if $object.Stream }}
|
|
||||||
return func() graphql.Marshaler {
|
|
||||||
res, ok := <-resTmp.(<-chan {{$field.TypeReference.GO | ref}})
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return graphql.WriterFunc(func(w io.Writer) {
|
|
||||||
w.Write([]byte{'{'})
|
|
||||||
graphql.MarshalString(field.Alias).MarshalGQL(w)
|
|
||||||
w.Write([]byte{':'})
|
|
||||||
ec.{{ $field.TypeReference.MarshalFunc }}(ctx, field.Selections, res).MarshalGQL(w)
|
|
||||||
w.Write([]byte{'}'})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
{{- else }}
|
|
||||||
res := resTmp.({{$field.TypeReference.GO | ref}})
|
|
||||||
fc.Result = res
|
|
||||||
return ec.{{ $field.TypeReference.MarshalFunc }}(ctx, field.Selections, res)
|
|
||||||
{{- end }}
|
|
||||||
}
|
|
||||||
|
|
||||||
{{- end }}{{- end}}
|
|
||||||
|
|
||||||
{{ define "field" }}
|
|
||||||
{{- if .HasDirectives -}}
|
|
||||||
directive0 := func(rctx context.Context) (interface{}, error) {
|
|
||||||
ctx = rctx // use context from middleware stack in children
|
|
||||||
{{ template "fieldDefinition" . }}
|
|
||||||
}
|
|
||||||
{{ template "implDirectives" . }}
|
|
||||||
tmp, err := directive{{.ImplDirectives|len}}(rctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, graphql.ErrorOnPath(ctx, err)
|
|
||||||
}
|
|
||||||
if tmp == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
if data, ok := tmp.({{if .Stream}}<-chan {{end}}{{ .TypeReference.GO | ref }}) ; ok {
|
|
||||||
return data, nil
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf(`unexpected type %T from directive, should be {{if .Stream}}<-chan {{end}}{{ .TypeReference.GO }}`, tmp)
|
|
||||||
{{- else -}}
|
|
||||||
ctx = rctx // use context from middleware stack in children
|
|
||||||
{{ template "fieldDefinition" . }}
|
|
||||||
{{- end -}}
|
|
||||||
{{ end }}
|
|
||||||
|
|
||||||
{{ define "fieldDefinition" }}
|
|
||||||
{{- if .IsResolver -}}
|
|
||||||
return ec.resolvers.{{ .ShortInvocation }}
|
|
||||||
{{- else if .IsMap -}}
|
|
||||||
switch v := {{.GoReceiverName}}[{{.Name|quote}}].(type) {
|
|
||||||
case {{if .Stream}}<-chan {{end}}{{.TypeReference.GO | ref}}:
|
|
||||||
return v, nil
|
|
||||||
case {{if .Stream}}<-chan {{end}}{{.TypeReference.Elem.GO | ref}}:
|
|
||||||
return &v, nil
|
|
||||||
case nil:
|
|
||||||
return ({{.TypeReference.GO | ref}})(nil), nil
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unexpected type %T for field %s", v, {{ .Name | quote}})
|
|
||||||
}
|
|
||||||
{{- else if .IsMethod -}}
|
|
||||||
{{- if .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 }})
|
|
||||||
{{- end -}}
|
|
||||||
{{- else if .IsVariable -}}
|
|
||||||
return {{.GoReceiverName}}.{{.GoFieldName}}, nil
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
213
vendor/github.com/99designs/gqlgen/codegen/generate.go
generated
vendored
213
vendor/github.com/99designs/gqlgen/codegen/generate.go
generated
vendored
@@ -1,213 +0,0 @@
|
|||||||
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,
|
|
||||||
Data: data,
|
|
||||||
RegionTags: true,
|
|
||||||
GeneratedHeader: true,
|
|
||||||
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
|
|
||||||
}
|
|
||||||
235
vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl
generated
vendored
235
vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl
generated
vendored
@@ -1,235 +0,0 @@
|
|||||||
{{ 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" }}
|
|
||||||
|
|
||||||
|
|
||||||
{{ 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 ResolverRoot interface {
|
|
||||||
{{- range $object := .Objects -}}
|
|
||||||
{{ if $object.HasResolvers -}}
|
|
||||||
{{ucFirst $object.Name}}() {{ucFirst $object.Name}}Resolver
|
|
||||||
{{ end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- range $object := .Inputs -}}
|
|
||||||
{{ 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 }}
|
|
||||||
}
|
|
||||||
{{ 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 -}}
|
|
||||||
{{- if $field.IsResolver }}
|
|
||||||
{{- $field.GoFieldName}}{{ $field.ShortResolverDeclaration }}
|
|
||||||
{{- end }}
|
|
||||||
{{ end }}
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{ 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) 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...)
|
|
||||||
{{ end }}
|
|
||||||
72
vendor/github.com/99designs/gqlgen/codegen/input.gotpl
generated
vendored
72
vendor/github.com/99designs/gqlgen/codegen/input.gotpl
generated
vendored
@@ -1,72 +0,0 @@
|
|||||||
{{- range $input := .Inputs }}
|
|
||||||
{{- if not .HasUnmarshal }}
|
|
||||||
func (ec *executionContext) unmarshalInput{{ .Name }}(ctx context.Context, obj interface{}) ({{.Type | ref}}, error) {
|
|
||||||
var it {{.Type | ref}}
|
|
||||||
asMap := map[string]interface{}{}
|
|
||||||
for k, v := range obj.(map[string]interface{}) {
|
|
||||||
asMap[k] = v
|
|
||||||
}
|
|
||||||
{{ range $field := .Fields}}
|
|
||||||
{{- if notNil "Default" $field }}
|
|
||||||
if _, present := asMap[{{$field.Name|quote}}] ; !present {
|
|
||||||
asMap[{{$field.Name|quote}}] = {{ $field.Default | dump }}
|
|
||||||
}
|
|
||||||
{{- end}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
for k, v := range asMap {
|
|
||||||
switch k {
|
|
||||||
{{- range $field := .Fields }}
|
|
||||||
case {{$field.Name|quote}}:
|
|
||||||
var err error
|
|
||||||
|
|
||||||
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, graphql.ErrorOnPath(ctx, err)
|
|
||||||
}
|
|
||||||
if data, ok := tmp.({{ $field.TypeReference.GO | ref }}) ; ok {
|
|
||||||
{{- 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 {
|
|
||||||
err := fmt.Errorf(`unexpected type %T from directive, should be {{ $field.TypeReference.GO }}`, tmp)
|
|
||||||
return it, graphql.ErrorOnPath(ctx, err)
|
|
||||||
}
|
|
||||||
{{- else }}
|
|
||||||
{{- 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 }}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return it, nil
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
{{ end }}
|
|
||||||
87
vendor/github.com/99designs/gqlgen/codegen/interface.go
generated
vendored
87
vendor/github.com/99designs/gqlgen/codegen/interface.go
generated
vendored
@@ -1,87 +0,0 @@
|
|||||||
package codegen
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"go/types"
|
|
||||||
|
|
||||||
"github.com/vektah/gqlparser/v2/ast"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/codegen/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Interface struct {
|
|
||||||
*ast.Definition
|
|
||||||
Type types.Type
|
|
||||||
Implementors []InterfaceImplementor
|
|
||||||
InTypemap bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type InterfaceImplementor struct {
|
|
||||||
*ast.Definition
|
|
||||||
|
|
||||||
Type types.Type
|
|
||||||
TakeRef bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *builder) buildInterface(typ *ast.Definition) (*Interface, error) {
|
|
||||||
obj, err := b.Binder.DefaultUserObject(typ.Name)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
i := &Interface{
|
|
||||||
Definition: typ,
|
|
||||||
Type: obj,
|
|
||||||
InTypemap: b.Config.Models.UserDefined(typ.Name),
|
|
||||||
}
|
|
||||||
|
|
||||||
interfaceType, err := findGoInterface(i.Type)
|
|
||||||
if interfaceType == nil || err != nil {
|
|
||||||
return nil, fmt.Errorf("%s is not an interface", i.Type)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, implementor := range b.Schema.GetPossibleTypes(typ) {
|
|
||||||
obj, err := b.Binder.DefaultUserObject(implementor.Name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("%s has no backing go type", implementor.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
implementorType, err := findGoNamedType(obj)
|
|
||||||
if err != nil {
|
|
||||||
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())
|
|
||||||
}
|
|
||||||
|
|
||||||
anyValid := false
|
|
||||||
|
|
||||||
// first check if the value receiver can be nil, eg can we type switch on case Thing:
|
|
||||||
if types.Implements(implementorType, interfaceType) {
|
|
||||||
i.Implementors = append(i.Implementors, InterfaceImplementor{
|
|
||||||
Definition: implementor,
|
|
||||||
Type: obj,
|
|
||||||
TakeRef: !types.IsInterface(obj),
|
|
||||||
})
|
|
||||||
anyValid = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// then check if the pointer receiver can be nil, eg can we type switch on case *Thing:
|
|
||||||
if types.Implements(types.NewPointer(implementorType), interfaceType) {
|
|
||||||
i.Implementors = append(i.Implementors, InterfaceImplementor{
|
|
||||||
Definition: implementor,
|
|
||||||
Type: types.NewPointer(obj),
|
|
||||||
})
|
|
||||||
anyValid = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if !anyValid {
|
|
||||||
return nil, fmt.Errorf("%s does not satisfy the interface %s", implementorType.String(), i.Type.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return i, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *InterfaceImplementor) CanBeNil() bool {
|
|
||||||
return config.IsNilable(i.Type)
|
|
||||||
}
|
|
||||||
21
vendor/github.com/99designs/gqlgen/codegen/interface.gotpl
generated
vendored
21
vendor/github.com/99designs/gqlgen/codegen/interface.gotpl
generated
vendored
@@ -1,21 +0,0 @@
|
|||||||
{{- range $interface := .Interfaces }}
|
|
||||||
|
|
||||||
func (ec *executionContext) _{{$interface.Name}}(ctx context.Context, sel ast.SelectionSet, obj {{$interface.Type | ref}}) graphql.Marshaler {
|
|
||||||
switch obj := (obj).(type) {
|
|
||||||
case nil:
|
|
||||||
return graphql.Null
|
|
||||||
{{- range $implementor := $interface.Implementors }}
|
|
||||||
case {{$implementor.Type | ref}}:
|
|
||||||
{{- if $implementor.CanBeNil }}
|
|
||||||
if obj == nil {
|
|
||||||
return graphql.Null
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
return ec._{{$implementor.Name}}(ctx, sel, {{ if $implementor.TakeRef }}&{{ end }}obj)
|
|
||||||
{{- end }}
|
|
||||||
default:
|
|
||||||
panic(fmt.Errorf("unexpected type %T", obj))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{{- end }}
|
|
||||||
169
vendor/github.com/99designs/gqlgen/codegen/object.go
generated
vendored
169
vendor/github.com/99designs/gqlgen/codegen/object.go
generated
vendored
@@ -1,169 +0,0 @@
|
|||||||
package codegen
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"go/types"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"unicode"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/codegen/config"
|
|
||||||
"github.com/vektah/gqlparser/v2/ast"
|
|
||||||
)
|
|
||||||
|
|
||||||
type GoFieldType int
|
|
||||||
|
|
||||||
const (
|
|
||||||
GoFieldUndefined GoFieldType = iota
|
|
||||||
GoFieldMethod
|
|
||||||
GoFieldVariable
|
|
||||||
GoFieldMap
|
|
||||||
)
|
|
||||||
|
|
||||||
type Object struct {
|
|
||||||
*ast.Definition
|
|
||||||
|
|
||||||
Type types.Type
|
|
||||||
ResolverInterface types.Type
|
|
||||||
Root bool
|
|
||||||
Fields []*Field
|
|
||||||
Implements []*ast.Definition
|
|
||||||
DisableConcurrency bool
|
|
||||||
Stream bool
|
|
||||||
Directives []*Directive
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *builder) buildObject(typ *ast.Definition) (*Object, error) {
|
|
||||||
dirs, err := b.getDirectives(typ.Directives)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("%s: %w", typ.Name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
obj := &Object{
|
|
||||||
Definition: typ,
|
|
||||||
Root: b.Schema.Query == typ || b.Schema.Mutation == typ || b.Schema.Subscription == typ,
|
|
||||||
DisableConcurrency: typ == b.Schema.Mutation,
|
|
||||||
Stream: typ == b.Schema.Subscription,
|
|
||||||
Directives: dirs,
|
|
||||||
ResolverInterface: types.NewNamed(
|
|
||||||
types.NewTypeName(0, b.Config.Exec.Pkg(), strings.Title(typ.Name)+"Resolver", nil),
|
|
||||||
nil,
|
|
||||||
nil,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
if !obj.Root {
|
|
||||||
goObject, err := b.Binder.DefaultUserObject(typ.Name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
obj.Type = goObject
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, intf := range b.Schema.GetImplements(typ) {
|
|
||||||
obj.Implements = append(obj.Implements, b.Schema.Types[intf.Name])
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, field := range typ.Fields {
|
|
||||||
if strings.HasPrefix(field.Name, "__") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var f *Field
|
|
||||||
f, err = b.buildField(obj, field)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.Fields = append(obj.Fields, f)
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Object) Reference() types.Type {
|
|
||||||
if config.IsNilable(o.Type) {
|
|
||||||
return o.Type
|
|
||||||
}
|
|
||||||
return types.NewPointer(o.Type)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Objects []*Object
|
|
||||||
|
|
||||||
func (o *Object) Implementors() string {
|
|
||||||
satisfiedBy := strconv.Quote(o.Name)
|
|
||||||
for _, s := range o.Implements {
|
|
||||||
satisfiedBy += ", " + strconv.Quote(s.Name)
|
|
||||||
}
|
|
||||||
return "[]string{" + satisfiedBy + "}"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Object) HasResolvers() bool {
|
|
||||||
for _, f := range o.Fields {
|
|
||||||
if f.IsResolver {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Object) HasUnmarshal() bool {
|
|
||||||
if o.Type == config.MapType {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
for i := 0; i < o.Type.(*types.Named).NumMethods(); i++ {
|
|
||||||
if o.Type.(*types.Named).Method(i).Name() == "UnmarshalGQL" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Object) HasDirectives() bool {
|
|
||||||
if len(o.Directives) > 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
for _, f := range o.Fields {
|
|
||||||
if f.HasDirectives() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Object) IsConcurrent() bool {
|
|
||||||
for _, f := range o.Fields {
|
|
||||||
if f.IsConcurrent() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Object) IsReserved() bool {
|
|
||||||
return strings.HasPrefix(o.Definition.Name, "__")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Object) Description() string {
|
|
||||||
return o.Definition.Description
|
|
||||||
}
|
|
||||||
|
|
||||||
func (os Objects) ByName(name string) *Object {
|
|
||||||
for i, o := range os {
|
|
||||||
if strings.EqualFold(o.Definition.Name, name) {
|
|
||||||
return os[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ucFirst(s string) string {
|
|
||||||
if s == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
r := []rune(s)
|
|
||||||
r[0] = unicode.ToUpper(r[0])
|
|
||||||
return string(r)
|
|
||||||
}
|
|
||||||
113
vendor/github.com/99designs/gqlgen/codegen/object.gotpl
generated
vendored
113
vendor/github.com/99designs/gqlgen/codegen/object.gotpl
generated
vendored
@@ -1,113 +0,0 @@
|
|||||||
{{- range $object := .Objects }}
|
|
||||||
|
|
||||||
var {{ $object.Name|lcFirst}}Implementors = {{$object.Implementors}}
|
|
||||||
|
|
||||||
{{- if .Stream }}
|
|
||||||
func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.SelectionSet) func() graphql.Marshaler {
|
|
||||||
fields := graphql.CollectFields(ec.OperationContext, sel, {{$object.Name|lcFirst}}Implementors)
|
|
||||||
ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{
|
|
||||||
Object: {{$object.Name|quote}},
|
|
||||||
})
|
|
||||||
if len(fields) != 1 {
|
|
||||||
ec.Errorf(ctx, "must subscribe to exactly one stream")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
switch fields[0].Name {
|
|
||||||
{{- range $field := $object.Fields }}
|
|
||||||
case "{{$field.Name}}":
|
|
||||||
return ec._{{$object.Name}}_{{$field.Name}}(ctx, fields[0])
|
|
||||||
{{- end }}
|
|
||||||
default:
|
|
||||||
panic("unknown field " + strconv.Quote(fields[0].Name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{{- 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}}
|
|
||||||
out := graphql.NewFieldSet(fields)
|
|
||||||
var invalids uint32
|
|
||||||
for i, field := range fields {
|
|
||||||
{{- 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 }
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- end }}
|
|
||||||
201
vendor/github.com/99designs/gqlgen/codegen/root_.gotpl
generated
vendored
201
vendor/github.com/99designs/gqlgen/codegen/root_.gotpl
generated
vendored
@@ -1,201 +0,0 @@
|
|||||||
{{ 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...)
|
|
||||||
139
vendor/github.com/99designs/gqlgen/codegen/templates/import.go
generated
vendored
139
vendor/github.com/99designs/gqlgen/codegen/templates/import.go
generated
vendored
@@ -1,139 +0,0 @@
|
|||||||
package templates
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"go/types"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/internal/code"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Import struct {
|
|
||||||
Name string
|
|
||||||
Path string
|
|
||||||
Alias string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Imports struct {
|
|
||||||
imports []*Import
|
|
||||||
destDir string
|
|
||||||
packages *code.Packages
|
|
||||||
}
|
|
||||||
|
|
||||||
func (i *Import) String() string {
|
|
||||||
if strings.HasSuffix(i.Path, i.Alias) {
|
|
||||||
return strconv.Quote(i.Path)
|
|
||||||
}
|
|
||||||
|
|
||||||
return i.Alias + " " + strconv.Quote(i.Path)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Imports) String() string {
|
|
||||||
res := ""
|
|
||||||
for i, imp := range s.imports {
|
|
||||||
if i != 0 {
|
|
||||||
res += "\n"
|
|
||||||
}
|
|
||||||
res += imp.String()
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Imports) Reserve(path string, aliases ...string) (string, error) {
|
|
||||||
if path == "" {
|
|
||||||
panic("empty ambient import")
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we are referencing our own package we dont need an import
|
|
||||||
if code.ImportPathForDir(s.destDir) == path {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
name := s.packages.NameForPackage(path)
|
|
||||||
var alias string
|
|
||||||
if len(aliases) != 1 {
|
|
||||||
alias = name
|
|
||||||
} else {
|
|
||||||
alias = aliases[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
if existing := s.findByPath(path); existing != nil {
|
|
||||||
if existing.Alias == alias {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
return "", fmt.Errorf("ambient import already exists")
|
|
||||||
}
|
|
||||||
|
|
||||||
if alias := s.findByAlias(alias); alias != nil {
|
|
||||||
return "", fmt.Errorf("ambient import collides on an alias")
|
|
||||||
}
|
|
||||||
|
|
||||||
s.imports = append(s.imports, &Import{
|
|
||||||
Name: name,
|
|
||||||
Path: path,
|
|
||||||
Alias: alias,
|
|
||||||
})
|
|
||||||
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Imports) Lookup(path string) string {
|
|
||||||
if path == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
path = code.NormalizeVendor(path)
|
|
||||||
|
|
||||||
// if we are referencing our own package we dont need an import
|
|
||||||
if code.ImportPathForDir(s.destDir) == path {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if existing := s.findByPath(path); existing != nil {
|
|
||||||
return existing.Alias
|
|
||||||
}
|
|
||||||
|
|
||||||
imp := &Import{
|
|
||||||
Name: s.packages.NameForPackage(path),
|
|
||||||
Path: path,
|
|
||||||
}
|
|
||||||
s.imports = append(s.imports, imp)
|
|
||||||
|
|
||||||
alias := imp.Name
|
|
||||||
i := 1
|
|
||||||
for s.findByAlias(alias) != nil {
|
|
||||||
alias = imp.Name + strconv.Itoa(i)
|
|
||||||
i++
|
|
||||||
if i > 1000 {
|
|
||||||
panic(fmt.Errorf("too many collisions, last attempt was %s", alias))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
imp.Alias = alias
|
|
||||||
|
|
||||||
return imp.Alias
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Imports) LookupType(t types.Type) string {
|
|
||||||
return types.TypeString(t, func(i *types.Package) string {
|
|
||||||
return s.Lookup(i.Path())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Imports) findByPath(importPath string) *Import {
|
|
||||||
for _, imp := range s.imports {
|
|
||||||
if imp.Path == importPath {
|
|
||||||
return imp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Imports) findByAlias(alias string) *Import {
|
|
||||||
for _, imp := range s.imports {
|
|
||||||
if imp.Alias == alias {
|
|
||||||
return imp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
611
vendor/github.com/99designs/gqlgen/codegen/templates/templates.go
generated
vendored
611
vendor/github.com/99designs/gqlgen/codegen/templates/templates.go
generated
vendored
@@ -1,611 +0,0 @@
|
|||||||
package templates
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"go/types"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"reflect"
|
|
||||||
"runtime"
|
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
"unicode"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/internal/code"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/internal/imports"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CurrentImports keeps track of all the import declarations that are needed during the execution of a plugin.
|
|
||||||
// this is done with a global because subtemplates currently get called in functions. Lets aim to remove this eventually.
|
|
||||||
var CurrentImports *Imports
|
|
||||||
|
|
||||||
// Options specify various parameters to rendering a template.
|
|
||||||
type Options struct {
|
|
||||||
// PackageName is a helper that specifies the package header declaration.
|
|
||||||
// In other words, when you write the template you don't need to specify `package X`
|
|
||||||
// at the top of the file. By providing PackageName in the Options, the Render
|
|
||||||
// function will do that for you.
|
|
||||||
PackageName string
|
|
||||||
// Template is a string of the entire template that
|
|
||||||
// will be parsed and rendered. If it's empty,
|
|
||||||
// the plugin processor will look for .gotpl files
|
|
||||||
// in the same directory of where you wrote the plugin.
|
|
||||||
Template string
|
|
||||||
// Filename is the name of the file that will be
|
|
||||||
// written to the system disk once the template is rendered.
|
|
||||||
Filename string
|
|
||||||
RegionTags bool
|
|
||||||
GeneratedHeader bool
|
|
||||||
// PackageDoc is documentation written above the package line
|
|
||||||
PackageDoc string
|
|
||||||
// FileNotice is notice written below the package line
|
|
||||||
FileNotice string
|
|
||||||
// Data will be passed to the template execution.
|
|
||||||
Data interface{}
|
|
||||||
Funcs template.FuncMap
|
|
||||||
|
|
||||||
// Packages cache, you can find me on config.Config
|
|
||||||
Packages *code.Packages
|
|
||||||
}
|
|
||||||
|
|
||||||
// Render renders a gql plugin template from the given Options. Render is an
|
|
||||||
// abstraction of the text/template package that makes it easier to write gqlgen
|
|
||||||
// plugins. If Options.Template is empty, the Render function will look for `.gotpl`
|
|
||||||
// files inside the directory where you wrote the plugin.
|
|
||||||
func Render(cfg Options) error {
|
|
||||||
if CurrentImports != nil {
|
|
||||||
panic(fmt.Errorf("recursive or concurrent call to RenderToFile detected"))
|
|
||||||
}
|
|
||||||
CurrentImports = &Imports{packages: cfg.Packages, destDir: filepath.Dir(cfg.Filename)}
|
|
||||||
|
|
||||||
// load path relative to calling source file
|
|
||||||
_, callerFile, _, _ := runtime.Caller(1)
|
|
||||||
rootDir := filepath.Dir(callerFile)
|
|
||||||
|
|
||||||
funcs := Funcs()
|
|
||||||
for n, f := range cfg.Funcs {
|
|
||||||
funcs[n] = f
|
|
||||||
}
|
|
||||||
t := template.New("").Funcs(funcs)
|
|
||||||
|
|
||||||
var roots []string
|
|
||||||
if cfg.Template != "" {
|
|
||||||
var err error
|
|
||||||
t, err = t.New("template.gotpl").Parse(cfg.Template)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error with provided template: %w", err)
|
|
||||||
}
|
|
||||||
roots = append(roots, "template.gotpl")
|
|
||||||
} else {
|
|
||||||
// load all the templates in the directory
|
|
||||||
err := filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
name := filepath.ToSlash(strings.TrimPrefix(path, rootDir+string(os.PathSeparator)))
|
|
||||||
if !strings.HasSuffix(info.Name(), ".gotpl") {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// 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
|
|
||||||
}
|
|
||||||
|
|
||||||
t, err = t.New(name).Parse(string(b))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("%s: %w", cfg.Filename, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
roots = append(roots, name)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("locating templates: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// then execute all the important looking ones in order, adding them to the same file
|
|
||||||
sort.Slice(roots, func(i, j int) bool {
|
|
||||||
// important files go first
|
|
||||||
if strings.HasSuffix(roots[i], "!.gotpl") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if strings.HasSuffix(roots[j], "!.gotpl") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return roots[i] < roots[j]
|
|
||||||
})
|
|
||||||
var buf bytes.Buffer
|
|
||||||
for _, root := range roots {
|
|
||||||
if cfg.RegionTags {
|
|
||||||
buf.WriteString("\n// region " + center(70, "*", " "+root+" ") + "\n")
|
|
||||||
}
|
|
||||||
err := t.Lookup(root).Execute(&buf, cfg.Data)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("%s: %w", root, err)
|
|
||||||
}
|
|
||||||
if cfg.RegionTags {
|
|
||||||
buf.WriteString("\n// endregion " + center(70, "*", " "+root+" ") + "\n")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var result bytes.Buffer
|
|
||||||
if cfg.GeneratedHeader {
|
|
||||||
result.WriteString("// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.\n\n")
|
|
||||||
}
|
|
||||||
if cfg.PackageDoc != "" {
|
|
||||||
result.WriteString(cfg.PackageDoc + "\n")
|
|
||||||
}
|
|
||||||
result.WriteString("package ")
|
|
||||||
result.WriteString(cfg.PackageName)
|
|
||||||
result.WriteString("\n\n")
|
|
||||||
if cfg.FileNotice != "" {
|
|
||||||
result.WriteString(cfg.FileNotice)
|
|
||||||
result.WriteString("\n\n")
|
|
||||||
}
|
|
||||||
result.WriteString("import (\n")
|
|
||||||
result.WriteString(CurrentImports.String())
|
|
||||||
result.WriteString(")\n")
|
|
||||||
_, err := buf.WriteTo(&result)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
CurrentImports = nil
|
|
||||||
|
|
||||||
err = write(cfg.Filename, result.Bytes(), cfg.Packages)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg.Packages.Evict(code.ImportPathForDir(filepath.Dir(cfg.Filename)))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func center(width int, pad string, s string) string {
|
|
||||||
if len(s)+2 > width {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
lpad := (width - len(s)) / 2
|
|
||||||
rpad := width - (lpad + len(s))
|
|
||||||
return strings.Repeat(pad, lpad) + s + strings.Repeat(pad, rpad)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Funcs() template.FuncMap {
|
|
||||||
return template.FuncMap{
|
|
||||||
"ucFirst": UcFirst,
|
|
||||||
"lcFirst": LcFirst,
|
|
||||||
"quote": strconv.Quote,
|
|
||||||
"rawQuote": rawQuote,
|
|
||||||
"dump": Dump,
|
|
||||||
"ref": ref,
|
|
||||||
"ts": TypeIdentifier,
|
|
||||||
"call": Call,
|
|
||||||
"prefixLines": prefixLines,
|
|
||||||
"notNil": notNil,
|
|
||||||
"reserveImport": CurrentImports.Reserve,
|
|
||||||
"lookupImport": CurrentImports.Lookup,
|
|
||||||
"go": ToGo,
|
|
||||||
"goPrivate": ToGoPrivate,
|
|
||||||
"add": func(a, b int) int {
|
|
||||||
return a + b
|
|
||||||
},
|
|
||||||
"render": func(filename string, tpldata interface{}) (*bytes.Buffer, error) {
|
|
||||||
return render(resolveName(filename, 0), tpldata)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func UcFirst(s string) string {
|
|
||||||
if s == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
r := []rune(s)
|
|
||||||
r[0] = unicode.ToUpper(r[0])
|
|
||||||
return string(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func LcFirst(s string) string {
|
|
||||||
if s == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
r := []rune(s)
|
|
||||||
r[0] = unicode.ToLower(r[0])
|
|
||||||
return string(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isDelimiter(c rune) bool {
|
|
||||||
return c == '-' || c == '_' || unicode.IsSpace(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ref(p types.Type) string {
|
|
||||||
return CurrentImports.LookupType(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
var pkgReplacer = strings.NewReplacer(
|
|
||||||
"/", "ᚋ",
|
|
||||||
".", "ᚗ",
|
|
||||||
"-", "ᚑ",
|
|
||||||
"~", "א",
|
|
||||||
)
|
|
||||||
|
|
||||||
func TypeIdentifier(t types.Type) string {
|
|
||||||
res := ""
|
|
||||||
for {
|
|
||||||
switch it := t.(type) {
|
|
||||||
case *types.Pointer:
|
|
||||||
t.Underlying()
|
|
||||||
res += "ᚖ"
|
|
||||||
t = it.Elem()
|
|
||||||
case *types.Slice:
|
|
||||||
res += "ᚕ"
|
|
||||||
t = it.Elem()
|
|
||||||
case *types.Named:
|
|
||||||
res += pkgReplacer.Replace(it.Obj().Pkg().Path())
|
|
||||||
res += "ᚐ"
|
|
||||||
res += it.Obj().Name()
|
|
||||||
return res
|
|
||||||
case *types.Basic:
|
|
||||||
res += it.Name()
|
|
||||||
return res
|
|
||||||
case *types.Map:
|
|
||||||
res += "map"
|
|
||||||
return res
|
|
||||||
case *types.Interface:
|
|
||||||
res += "interface"
|
|
||||||
return res
|
|
||||||
default:
|
|
||||||
panic(fmt.Errorf("unexpected type %T", it))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Call(p *types.Func) string {
|
|
||||||
pkg := CurrentImports.Lookup(p.Pkg().Path())
|
|
||||||
|
|
||||||
if pkg != "" {
|
|
||||||
pkg += "."
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.Type() != nil {
|
|
||||||
// make sure the returned type is listed in our imports.
|
|
||||||
ref(p.Type().(*types.Signature).Results().At(0).Type())
|
|
||||||
}
|
|
||||||
|
|
||||||
return pkg + p.Name()
|
|
||||||
}
|
|
||||||
|
|
||||||
func ToGo(name string) string {
|
|
||||||
if name == "_" {
|
|
||||||
return "_"
|
|
||||||
}
|
|
||||||
runes := make([]rune, 0, len(name))
|
|
||||||
|
|
||||||
wordWalker(name, func(info *wordInfo) {
|
|
||||||
word := info.Word
|
|
||||||
if info.MatchCommonInitial {
|
|
||||||
word = strings.ToUpper(word)
|
|
||||||
} else if !info.HasCommonInitial {
|
|
||||||
if strings.ToUpper(word) == word || strings.ToLower(word) == word {
|
|
||||||
// FOO or foo → Foo
|
|
||||||
// FOo → FOo
|
|
||||||
word = UcFirst(strings.ToLower(word))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
runes = append(runes, []rune(word)...)
|
|
||||||
})
|
|
||||||
|
|
||||||
return string(runes)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ToGoPrivate(name string) string {
|
|
||||||
if name == "_" {
|
|
||||||
return "_"
|
|
||||||
}
|
|
||||||
runes := make([]rune, 0, len(name))
|
|
||||||
|
|
||||||
first := true
|
|
||||||
wordWalker(name, func(info *wordInfo) {
|
|
||||||
word := info.Word
|
|
||||||
switch {
|
|
||||||
case first:
|
|
||||||
if strings.ToUpper(word) == word || strings.ToLower(word) == word {
|
|
||||||
// ID → id, CAMEL → camel
|
|
||||||
word = strings.ToLower(info.Word)
|
|
||||||
} else {
|
|
||||||
// ITicket → iTicket
|
|
||||||
word = LcFirst(info.Word)
|
|
||||||
}
|
|
||||||
first = false
|
|
||||||
case info.MatchCommonInitial:
|
|
||||||
word = strings.ToUpper(word)
|
|
||||||
case !info.HasCommonInitial:
|
|
||||||
word = UcFirst(strings.ToLower(word))
|
|
||||||
}
|
|
||||||
runes = append(runes, []rune(word)...)
|
|
||||||
})
|
|
||||||
|
|
||||||
return sanitizeKeywords(string(runes))
|
|
||||||
}
|
|
||||||
|
|
||||||
type wordInfo struct {
|
|
||||||
Word string
|
|
||||||
MatchCommonInitial bool
|
|
||||||
HasCommonInitial bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function is based on the following code.
|
|
||||||
// https://github.com/golang/lint/blob/06c8688daad7faa9da5a0c2f163a3d14aac986ca/lint.go#L679
|
|
||||||
func wordWalker(str string, f func(*wordInfo)) {
|
|
||||||
runes := []rune(strings.TrimFunc(str, isDelimiter))
|
|
||||||
w, i := 0, 0 // index of start of word, scan
|
|
||||||
hasCommonInitial := false
|
|
||||||
for i+1 <= len(runes) {
|
|
||||||
eow := false // whether we hit the end of a word
|
|
||||||
switch {
|
|
||||||
case i+1 == len(runes):
|
|
||||||
eow = true
|
|
||||||
case isDelimiter(runes[i+1]):
|
|
||||||
// underscore; shift the remainder forward over any run of underscores
|
|
||||||
eow = true
|
|
||||||
n := 1
|
|
||||||
for i+n+1 < len(runes) && isDelimiter(runes[i+n+1]) {
|
|
||||||
n++
|
|
||||||
}
|
|
||||||
|
|
||||||
// Leave at most one underscore if the underscore is between two digits
|
|
||||||
if i+n+1 < len(runes) && unicode.IsDigit(runes[i]) && unicode.IsDigit(runes[i+n+1]) {
|
|
||||||
n--
|
|
||||||
}
|
|
||||||
|
|
||||||
copy(runes[i+1:], runes[i+n+1:])
|
|
||||||
runes = runes[:len(runes)-n]
|
|
||||||
case unicode.IsLower(runes[i]) && !unicode.IsLower(runes[i+1]):
|
|
||||||
// lower->non-lower
|
|
||||||
eow = true
|
|
||||||
}
|
|
||||||
i++
|
|
||||||
|
|
||||||
// [w,i) is a word.
|
|
||||||
word := string(runes[w:i])
|
|
||||||
if !eow && commonInitialisms[word] && !unicode.IsLower(runes[i]) {
|
|
||||||
// through
|
|
||||||
// split IDFoo → ID, Foo
|
|
||||||
// but URLs → URLs
|
|
||||||
} else if !eow {
|
|
||||||
if commonInitialisms[word] {
|
|
||||||
hasCommonInitial = true
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
matchCommonInitial := false
|
|
||||||
if commonInitialisms[strings.ToUpper(word)] {
|
|
||||||
hasCommonInitial = true
|
|
||||||
matchCommonInitial = true
|
|
||||||
}
|
|
||||||
|
|
||||||
f(&wordInfo{
|
|
||||||
Word: word,
|
|
||||||
MatchCommonInitial: matchCommonInitial,
|
|
||||||
HasCommonInitial: hasCommonInitial,
|
|
||||||
})
|
|
||||||
hasCommonInitial = false
|
|
||||||
w = i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var keywords = []string{
|
|
||||||
"break",
|
|
||||||
"default",
|
|
||||||
"func",
|
|
||||||
"interface",
|
|
||||||
"select",
|
|
||||||
"case",
|
|
||||||
"defer",
|
|
||||||
"go",
|
|
||||||
"map",
|
|
||||||
"struct",
|
|
||||||
"chan",
|
|
||||||
"else",
|
|
||||||
"goto",
|
|
||||||
"package",
|
|
||||||
"switch",
|
|
||||||
"const",
|
|
||||||
"fallthrough",
|
|
||||||
"if",
|
|
||||||
"range",
|
|
||||||
"type",
|
|
||||||
"continue",
|
|
||||||
"for",
|
|
||||||
"import",
|
|
||||||
"return",
|
|
||||||
"var",
|
|
||||||
"_",
|
|
||||||
}
|
|
||||||
|
|
||||||
// sanitizeKeywords prevents collisions with go keywords for arguments to resolver functions
|
|
||||||
func sanitizeKeywords(name string) string {
|
|
||||||
for _, k := range keywords {
|
|
||||||
if name == k {
|
|
||||||
return name + "Arg"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
|
|
||||||
// commonInitialisms is a set of common initialisms.
|
|
||||||
// Only add entries that are highly unlikely to be non-initialisms.
|
|
||||||
// For instance, "ID" is fine (Freudian code is rare), but "AND" is not.
|
|
||||||
var commonInitialisms = map[string]bool{
|
|
||||||
"ACL": true,
|
|
||||||
"API": true,
|
|
||||||
"ASCII": true,
|
|
||||||
"CPU": true,
|
|
||||||
"CSS": true,
|
|
||||||
"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,
|
|
||||||
"SLA": true,
|
|
||||||
"SMTP": true,
|
|
||||||
"SQL": true,
|
|
||||||
"SSH": true,
|
|
||||||
"SVG": true,
|
|
||||||
"TCP": true,
|
|
||||||
"TLS": true,
|
|
||||||
"TTL": true,
|
|
||||||
"UDP": true,
|
|
||||||
"UI": true,
|
|
||||||
"UID": true,
|
|
||||||
"URI": true,
|
|
||||||
"URL": true,
|
|
||||||
"UTF8": true,
|
|
||||||
"UUID": true,
|
|
||||||
"VM": true,
|
|
||||||
"XML": true,
|
|
||||||
"XMPP": true,
|
|
||||||
"XSRF": true,
|
|
||||||
"XSS": true,
|
|
||||||
}
|
|
||||||
|
|
||||||
func rawQuote(s string) string {
|
|
||||||
return "`" + strings.ReplaceAll(s, "`", "`+\"`\"+`") + "`"
|
|
||||||
}
|
|
||||||
|
|
||||||
func notNil(field string, data interface{}) bool {
|
|
||||||
v := reflect.ValueOf(data)
|
|
||||||
|
|
||||||
if v.Kind() == reflect.Ptr {
|
|
||||||
v = v.Elem()
|
|
||||||
}
|
|
||||||
if v.Kind() != reflect.Struct {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
val := v.FieldByName(field)
|
|
||||||
|
|
||||||
return val.IsValid() && !val.IsNil()
|
|
||||||
}
|
|
||||||
|
|
||||||
func Dump(val interface{}) string {
|
|
||||||
switch val := val.(type) {
|
|
||||||
case int:
|
|
||||||
return strconv.Itoa(val)
|
|
||||||
case int64:
|
|
||||||
return fmt.Sprintf("%d", val)
|
|
||||||
case float64:
|
|
||||||
return fmt.Sprintf("%f", val)
|
|
||||||
case string:
|
|
||||||
return strconv.Quote(val)
|
|
||||||
case bool:
|
|
||||||
return strconv.FormatBool(val)
|
|
||||||
case nil:
|
|
||||||
return "nil"
|
|
||||||
case []interface{}:
|
|
||||||
var parts []string
|
|
||||||
for _, part := range val {
|
|
||||||
parts = append(parts, Dump(part))
|
|
||||||
}
|
|
||||||
return "[]interface{}{" + strings.Join(parts, ",") + "}"
|
|
||||||
case map[string]interface{}:
|
|
||||||
buf := bytes.Buffer{}
|
|
||||||
buf.WriteString("map[string]interface{}{")
|
|
||||||
var keys []string
|
|
||||||
for key := range val {
|
|
||||||
keys = append(keys, key)
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
|
|
||||||
for _, key := range keys {
|
|
||||||
data := val[key]
|
|
||||||
|
|
||||||
buf.WriteString(strconv.Quote(key))
|
|
||||||
buf.WriteString(":")
|
|
||||||
buf.WriteString(Dump(data))
|
|
||||||
buf.WriteString(",")
|
|
||||||
}
|
|
||||||
buf.WriteString("}")
|
|
||||||
return buf.String()
|
|
||||||
default:
|
|
||||||
panic(fmt.Errorf("unsupported type %T", val))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func prefixLines(prefix, s string) string {
|
|
||||||
return prefix + strings.ReplaceAll(s, "\n", "\n"+prefix)
|
|
||||||
}
|
|
||||||
|
|
||||||
func resolveName(name string, skip int) string {
|
|
||||||
if name[0] == '.' {
|
|
||||||
// load path relative to calling source file
|
|
||||||
_, callerFile, _, _ := runtime.Caller(skip + 1)
|
|
||||||
return filepath.Join(filepath.Dir(callerFile), name[1:])
|
|
||||||
}
|
|
||||||
|
|
||||||
// load path relative to this directory
|
|
||||||
_, callerFile, _, _ := runtime.Caller(0)
|
|
||||||
return filepath.Join(filepath.Dir(callerFile), name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func render(filename string, tpldata interface{}) (*bytes.Buffer, error) {
|
|
||||||
t := template.New("").Funcs(Funcs())
|
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(filename)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
t, err = t.New(filepath.Base(filename)).Parse(string(b))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
return buf, t.Execute(buf, tpldata)
|
|
||||||
}
|
|
||||||
|
|
||||||
func write(filename string, b []byte, packages *code.Packages) error {
|
|
||||||
err := os.MkdirAll(filepath.Dir(filename), 0o755)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to create directory: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
formatted, err := imports.Prune(filename, b, packages)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "gofmt failed on %s: %s\n", filepath.Base(filename), err.Error())
|
|
||||||
formatted = b
|
|
||||||
}
|
|
||||||
|
|
||||||
err = ioutil.WriteFile(filename, formatted, 0o644)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to write %s: %w", filename, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
32
vendor/github.com/99designs/gqlgen/codegen/type.go
generated
vendored
32
vendor/github.com/99designs/gqlgen/codegen/type.go
generated
vendored
@@ -1,32 +0,0 @@
|
|||||||
package codegen
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/codegen/config"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (b *builder) buildTypes() map[string]*config.TypeReference {
|
|
||||||
ret := map[string]*config.TypeReference{}
|
|
||||||
for _, ref := range b.Binder.References {
|
|
||||||
processType(ret, ref)
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
func processType(ret map[string]*config.TypeReference, ref *config.TypeReference) {
|
|
||||||
key := ref.UniquenessKey()
|
|
||||||
if existing, found := ret[key]; found {
|
|
||||||
// Simplistic check of content which is obviously different.
|
|
||||||
existingGQL := fmt.Sprintf("%v", existing.GQL)
|
|
||||||
newGQL := fmt.Sprintf("%v", ref.GQL)
|
|
||||||
if existingGQL != newGQL {
|
|
||||||
panic(fmt.Sprintf("non-unique key \"%s\", trying to replace %s with %s", key, existingGQL, newGQL))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret[key] = ref
|
|
||||||
|
|
||||||
if ref.IsSlice() || ref.IsPtrToSlice() || ref.IsPtrToPtr() {
|
|
||||||
processType(ret, ref.Elem())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
192
vendor/github.com/99designs/gqlgen/codegen/type.gotpl
generated
vendored
192
vendor/github.com/99designs/gqlgen/codegen/type.gotpl
generated
vendored
@@ -1,192 +0,0 @@
|
|||||||
{{- 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) (not $type.IsPtrToPtr) }}
|
|
||||||
if v == nil { return nil, nil }
|
|
||||||
{{- end }}
|
|
||||||
{{- 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 {
|
|
||||||
vSlice = graphql.CoerceList(v)
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
res := make([]{{$type.GO.Elem | ref}}, len(vSlice))
|
|
||||||
for i := range vSlice {
|
|
||||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i))
|
|
||||||
res[i], err = ec.{{ $type.Elem.UnmarshalFunc }}(ctx, vSlice[i])
|
|
||||||
if err != nil {
|
|
||||||
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 }}
|
|
||||||
{{- 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}}
|
|
||||||
{{- 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.ErrorOnPath(ctx, err)
|
|
||||||
{{- else if and (not $type.IsTargetNilable) $type.IsNilable }}
|
|
||||||
return &res, graphql.ErrorOnPath(ctx, err)
|
|
||||||
{{- else}}
|
|
||||||
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 and $type.IsNilable $type.Elem }}
|
|
||||||
var res = new({{ $type.Elem.GO | ref }})
|
|
||||||
{{- else}}
|
|
||||||
var res {{ $type.GO | ref }}
|
|
||||||
{{- end }}
|
|
||||||
{{- 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.ErrorOnPath(ctx, err)
|
|
||||||
{{- else}}
|
|
||||||
return res, graphql.ErrorOnPath(ctx, err)
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{ with $type.MarshalFunc }}
|
|
||||||
func (ec *executionContext) {{ . }}(ctx context.Context, sel ast.SelectionSet, v {{ $type.GO | ref }}) graphql.Marshaler {
|
|
||||||
{{- 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
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
ret := make(graphql.Array, len(v))
|
|
||||||
{{- if not $type.IsScalar }}
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
isLen1 := len(v) == 1
|
|
||||||
if !isLen1 {
|
|
||||||
wg.Add(len(v))
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
for i := range v {
|
|
||||||
{{- if not $type.IsScalar }}
|
|
||||||
i := i
|
|
||||||
fc := &graphql.FieldContext{
|
|
||||||
Index: &i,
|
|
||||||
Result: &v[i],
|
|
||||||
}
|
|
||||||
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 !isLen1 {
|
|
||||||
defer wg.Done()
|
|
||||||
}
|
|
||||||
ret[i] = ec.{{ $type.Elem.MarshalFunc }}(ctx, sel, v[i])
|
|
||||||
}
|
|
||||||
if isLen1 {
|
|
||||||
f(i)
|
|
||||||
} else {
|
|
||||||
go f(i)
|
|
||||||
}
|
|
||||||
{{ else }}
|
|
||||||
ret[i] = ec.{{ $type.Elem.MarshalFunc }}(ctx, sel, v[i])
|
|
||||||
{{- 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 {
|
|
||||||
{{- if $type.GQL.NonNull }}
|
|
||||||
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
|
||||||
ec.Errorf(ctx, "must not be null")
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
return graphql.Null
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
{{- if $type.IsMarshaler }}
|
|
||||||
{{- 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) }}
|
|
||||||
{{- $v = "&v" }}
|
|
||||||
{{- 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 }}
|
|
||||||
if res == graphql.Null {
|
|
||||||
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
|
||||||
ec.Errorf(ctx, "must not be null")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
{{- if $type.IsContext }}
|
|
||||||
return graphql.WrapContextMarshaler(ctx, res)
|
|
||||||
{{- else }}
|
|
||||||
return res
|
|
||||||
{{- end }}
|
|
||||||
{{- else }}
|
|
||||||
return ec._{{$type.Definition.Name}}(ctx, sel, {{ if not $type.IsNilable}}&{{end}} v)
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
46
vendor/github.com/99designs/gqlgen/codegen/util.go
generated
vendored
46
vendor/github.com/99designs/gqlgen/codegen/util.go
generated
vendored
@@ -1,46 +0,0 @@
|
|||||||
package codegen
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"go/types"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func findGoNamedType(def types.Type) (*types.Named, error) {
|
|
||||||
if def == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
namedType, ok := def.(*types.Named)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("expected %s to be a named type, instead found %T\n", def.String(), def)
|
|
||||||
}
|
|
||||||
|
|
||||||
return namedType, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func findGoInterface(def types.Type) (*types.Interface, error) {
|
|
||||||
if def == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
namedType, err := findGoNamedType(def)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if namedType == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
underlying, ok := namedType.Underlying().(*types.Interface)
|
|
||||||
if !ok {
|
|
||||||
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.ReplaceAll(source, "_", "")
|
|
||||||
target = strings.ReplaceAll(target, "_", "")
|
|
||||||
return strings.EqualFold(source, target)
|
|
||||||
}
|
|
||||||
109
vendor/github.com/99designs/gqlgen/complexity/complexity.go
generated
vendored
109
vendor/github.com/99designs/gqlgen/complexity/complexity.go
generated
vendored
@@ -1,109 +0,0 @@
|
|||||||
package complexity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/99designs/gqlgen/graphql"
|
|
||||||
"github.com/vektah/gqlparser/v2/ast"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Calculate(es graphql.ExecutableSchema, op *ast.OperationDefinition, vars map[string]interface{}) int {
|
|
||||||
walker := complexityWalker{
|
|
||||||
es: es,
|
|
||||||
schema: es.Schema(),
|
|
||||||
vars: vars,
|
|
||||||
}
|
|
||||||
return walker.selectionSetComplexity(op.SelectionSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
type complexityWalker struct {
|
|
||||||
es graphql.ExecutableSchema
|
|
||||||
schema *ast.Schema
|
|
||||||
vars map[string]interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cw complexityWalker) selectionSetComplexity(selectionSet ast.SelectionSet) int {
|
|
||||||
var complexity int
|
|
||||||
for _, selection := range selectionSet {
|
|
||||||
switch s := selection.(type) {
|
|
||||||
case *ast.Field:
|
|
||||||
fieldDefinition := cw.schema.Types[s.Definition.Type.Name()]
|
|
||||||
|
|
||||||
if fieldDefinition.Name == "__Schema" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var childComplexity int
|
|
||||||
switch fieldDefinition.Kind {
|
|
||||||
case ast.Object, ast.Interface, ast.Union:
|
|
||||||
childComplexity = cw.selectionSetComplexity(s.SelectionSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
args := s.ArgumentMap(cw.vars)
|
|
||||||
var fieldComplexity int
|
|
||||||
if s.ObjectDefinition.Kind == ast.Interface {
|
|
||||||
fieldComplexity = cw.interfaceFieldComplexity(s.ObjectDefinition, s.Name, childComplexity, args)
|
|
||||||
} else {
|
|
||||||
fieldComplexity = cw.fieldComplexity(s.ObjectDefinition.Name, s.Name, childComplexity, args)
|
|
||||||
}
|
|
||||||
complexity = safeAdd(complexity, fieldComplexity)
|
|
||||||
|
|
||||||
case *ast.FragmentSpread:
|
|
||||||
complexity = safeAdd(complexity, cw.selectionSetComplexity(s.Definition.SelectionSet))
|
|
||||||
|
|
||||||
case *ast.InlineFragment:
|
|
||||||
complexity = safeAdd(complexity, cw.selectionSetComplexity(s.SelectionSet))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return complexity
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cw complexityWalker) interfaceFieldComplexity(def *ast.Definition, field string, childComplexity int, args map[string]interface{}) int {
|
|
||||||
// Interfaces don't have their own separate field costs, so they have to assume the worst case.
|
|
||||||
// We iterate over all implementors and choose the most expensive one.
|
|
||||||
maxComplexity := 0
|
|
||||||
implementors := cw.schema.GetPossibleTypes(def)
|
|
||||||
for _, t := range implementors {
|
|
||||||
fieldComplexity := cw.fieldComplexity(t.Name, field, childComplexity, args)
|
|
||||||
if fieldComplexity > maxComplexity {
|
|
||||||
maxComplexity = fieldComplexity
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return maxComplexity
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cw complexityWalker) fieldComplexity(object, field string, childComplexity int, args map[string]interface{}) int {
|
|
||||||
if customComplexity, ok := cw.es.Complexity(object, field, childComplexity, args); ok && customComplexity >= childComplexity {
|
|
||||||
return customComplexity
|
|
||||||
}
|
|
||||||
// default complexity calculation
|
|
||||||
return safeAdd(1, childComplexity)
|
|
||||||
}
|
|
||||||
|
|
||||||
const maxInt = int(^uint(0) >> 1)
|
|
||||||
|
|
||||||
// safeAdd is a saturating add of a and b that ignores negative operands.
|
|
||||||
// If a + b would overflow through normal Go addition,
|
|
||||||
// it returns the maximum integer value instead.
|
|
||||||
//
|
|
||||||
// Adding complexities with this function prevents attackers from intentionally
|
|
||||||
// overflowing the complexity calculation to allow overly-complex queries.
|
|
||||||
//
|
|
||||||
// It also helps mitigate the impact of custom complexities that accidentally
|
|
||||||
// return negative values.
|
|
||||||
func safeAdd(a, b int) int {
|
|
||||||
// Ignore negative operands.
|
|
||||||
if a < 0 {
|
|
||||||
if b < 0 {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
} else if b < 0 {
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
c := a + b
|
|
||||||
if c < a {
|
|
||||||
// Set c to maximum integer instead of overflowing.
|
|
||||||
c = maxInt
|
|
||||||
}
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
19
vendor/github.com/99designs/gqlgen/graphql/any.go
generated
vendored
19
vendor/github.com/99designs/gqlgen/graphql/any.go
generated
vendored
@@ -1,19 +0,0 @@
|
|||||||
package graphql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
func MarshalAny(v interface{}) Marshaler {
|
|
||||||
return WriterFunc(func(w io.Writer) {
|
|
||||||
err := json.NewEncoder(w).Encode(v)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func UnmarshalAny(v interface{}) (interface{}, error) {
|
|
||||||
return v, nil
|
|
||||||
}
|
|
||||||
27
vendor/github.com/99designs/gqlgen/graphql/bool.go
generated
vendored
27
vendor/github.com/99designs/gqlgen/graphql/bool.go
generated
vendored
@@ -1,27 +0,0 @@
|
|||||||
package graphql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func MarshalBoolean(b bool) Marshaler {
|
|
||||||
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) {
|
|
||||||
switch v := v.(type) {
|
|
||||||
case string:
|
|
||||||
return strings.ToLower(v) == "true", nil
|
|
||||||
case int:
|
|
||||||
return v != 0, nil
|
|
||||||
case bool:
|
|
||||||
return v, nil
|
|
||||||
default:
|
|
||||||
return false, fmt.Errorf("%T is not a bool", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
29
vendor/github.com/99designs/gqlgen/graphql/cache.go
generated
vendored
29
vendor/github.com/99designs/gqlgen/graphql/cache.go
generated
vendored
@@ -1,29 +0,0 @@
|
|||||||
package graphql
|
|
||||||
|
|
||||||
import "context"
|
|
||||||
|
|
||||||
// Cache is a shared store for APQ and query AST caching
|
|
||||||
type Cache interface {
|
|
||||||
// Get looks up a key's value from the cache.
|
|
||||||
Get(ctx context.Context, key string) (value interface{}, ok bool)
|
|
||||||
|
|
||||||
// Add adds a value to the cache.
|
|
||||||
Add(ctx context.Context, key string, value interface{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// MapCache is the simplest implementation of a cache, because it can not evict it should only be used in tests
|
|
||||||
type MapCache map[string]interface{}
|
|
||||||
|
|
||||||
// Get looks up a key's value from the cache.
|
|
||||||
func (m MapCache) Get(ctx context.Context, key string) (value interface{}, ok bool) {
|
|
||||||
v, ok := m[key]
|
|
||||||
return v, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add adds a value to the cache.
|
|
||||||
func (m MapCache) Add(ctx context.Context, key string, value interface{}) { m[key] = value }
|
|
||||||
|
|
||||||
type NoCache struct{}
|
|
||||||
|
|
||||||
func (n NoCache) Get(ctx context.Context, key string) (value interface{}, ok bool) { return nil, false }
|
|
||||||
func (n NoCache) Add(ctx context.Context, key string, value interface{}) {}
|
|
||||||
56
vendor/github.com/99designs/gqlgen/graphql/coercion.go
generated
vendored
56
vendor/github.com/99designs/gqlgen/graphql/coercion.go
generated
vendored
@@ -1,56 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
94
vendor/github.com/99designs/gqlgen/graphql/context_field.go
generated
vendored
94
vendor/github.com/99designs/gqlgen/graphql/context_field.go
generated
vendored
@@ -1,94 +0,0 @@
|
|||||||
package graphql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/vektah/gqlparser/v2/ast"
|
|
||||||
)
|
|
||||||
|
|
||||||
type key string
|
|
||||||
|
|
||||||
const resolverCtx key = "resolver_context"
|
|
||||||
|
|
||||||
// Deprecated: Use FieldContext instead
|
|
||||||
type ResolverContext = FieldContext
|
|
||||||
|
|
||||||
type FieldContext struct {
|
|
||||||
Parent *FieldContext
|
|
||||||
// The name of the type this field belongs to
|
|
||||||
Object string
|
|
||||||
// These are the args after processing, they can be mutated in middleware to change what the resolver will get.
|
|
||||||
Args map[string]interface{}
|
|
||||||
// The raw field
|
|
||||||
Field CollectedField
|
|
||||||
// The index of array in path.
|
|
||||||
Index *int
|
|
||||||
// The result object of resolver
|
|
||||||
Result interface{}
|
|
||||||
// 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 {
|
|
||||||
// When field execution started
|
|
||||||
Started time.Time
|
|
||||||
|
|
||||||
// When argument marshaling finished
|
|
||||||
ArgumentsCompleted time.Time
|
|
||||||
|
|
||||||
// When the field completed running all middleware. Not available inside field middleware!
|
|
||||||
Completed time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *FieldContext) Path() ast.Path {
|
|
||||||
var path ast.Path
|
|
||||||
for it := r; it != nil; it = it.Parent {
|
|
||||||
if it.Index != nil {
|
|
||||||
path = append(path, ast.PathIndex(*it.Index))
|
|
||||||
} else if it.Field.Field != nil {
|
|
||||||
path = append(path, ast.PathName(it.Field.Alias))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// because we are walking up the chain, all the elements are backwards, do an inplace flip.
|
|
||||||
for i := len(path)/2 - 1; i >= 0; i-- {
|
|
||||||
opp := len(path) - 1 - i
|
|
||||||
path[i], path[opp] = path[opp], path[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use GetFieldContext instead
|
|
||||||
func GetResolverContext(ctx context.Context) *ResolverContext {
|
|
||||||
return GetFieldContext(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetFieldContext(ctx context.Context) *FieldContext {
|
|
||||||
if val, ok := ctx.Value(resolverCtx).(*FieldContext); ok {
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func WithFieldContext(ctx context.Context, rc *FieldContext) context.Context {
|
|
||||||
rc.Parent = GetFieldContext(ctx)
|
|
||||||
return context.WithValue(ctx, resolverCtx, rc)
|
|
||||||
}
|
|
||||||
|
|
||||||
func equalPath(a ast.Path, b ast.Path) bool {
|
|
||||||
if len(a) != len(b) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < len(a); i++ {
|
|
||||||
if a[i] != b[i] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
115
vendor/github.com/99designs/gqlgen/graphql/context_operation.go
generated
vendored
115
vendor/github.com/99designs/gqlgen/graphql/context_operation.go
generated
vendored
@@ -1,115 +0,0 @@
|
|||||||
package graphql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/vektah/gqlparser/v2/ast"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Deprecated: Please update all references to OperationContext instead
|
|
||||||
type RequestContext = OperationContext
|
|
||||||
|
|
||||||
type OperationContext struct {
|
|
||||||
RawQuery string
|
|
||||||
Variables map[string]interface{}
|
|
||||||
OperationName string
|
|
||||||
Doc *ast.QueryDocument
|
|
||||||
|
|
||||||
Operation *ast.OperationDefinition
|
|
||||||
DisableIntrospection bool
|
|
||||||
RecoverFunc RecoverFunc
|
|
||||||
ResolverMiddleware FieldMiddleware
|
|
||||||
RootResolverMiddleware RootFieldMiddleware
|
|
||||||
|
|
||||||
Stats Stats
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *OperationContext) Validate(ctx context.Context) error {
|
|
||||||
if c.Doc == nil {
|
|
||||||
return errors.New("field 'Doc'is required")
|
|
||||||
}
|
|
||||||
if c.RawQuery == "" {
|
|
||||||
return errors.New("field 'RawQuery' is required")
|
|
||||||
}
|
|
||||||
if c.Variables == nil {
|
|
||||||
c.Variables = make(map[string]interface{})
|
|
||||||
}
|
|
||||||
if c.ResolverMiddleware == nil {
|
|
||||||
return errors.New("field 'ResolverMiddleware' is required")
|
|
||||||
}
|
|
||||||
if c.RootResolverMiddleware == nil {
|
|
||||||
return errors.New("field 'RootResolverMiddleware' is required")
|
|
||||||
}
|
|
||||||
if c.RecoverFunc == nil {
|
|
||||||
c.RecoverFunc = DefaultRecover
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
const operationCtx key = "operation_context"
|
|
||||||
|
|
||||||
// Deprecated: Please update all references to GetOperationContext instead
|
|
||||||
func GetRequestContext(ctx context.Context) *RequestContext {
|
|
||||||
return GetOperationContext(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetOperationContext(ctx context.Context) *OperationContext {
|
|
||||||
if val, ok := ctx.Value(operationCtx).(*OperationContext); ok && val != nil {
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
panic("missing operation context")
|
|
||||||
}
|
|
||||||
|
|
||||||
func WithOperationContext(ctx context.Context, rc *OperationContext) context.Context {
|
|
||||||
return context.WithValue(ctx, operationCtx, rc)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasOperationContext checks if the given context is part of an ongoing operation
|
|
||||||
//
|
|
||||||
// Some errors can happen outside of an operation, eg json unmarshal errors.
|
|
||||||
func HasOperationContext(ctx context.Context) bool {
|
|
||||||
_, ok := ctx.Value(operationCtx).(*OperationContext)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is just a convenient wrapper method for CollectFields
|
|
||||||
func CollectFieldsCtx(ctx context.Context, satisfies []string) []CollectedField {
|
|
||||||
resctx := GetFieldContext(ctx)
|
|
||||||
return CollectFields(GetOperationContext(ctx), resctx.Field.Selections, satisfies)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CollectAllFields returns a slice of all GraphQL field names that were selected for the current resolver context.
|
|
||||||
// The slice will contain the unique set of all field names requested regardless of fragment type conditions.
|
|
||||||
func CollectAllFields(ctx context.Context) []string {
|
|
||||||
resctx := GetFieldContext(ctx)
|
|
||||||
collected := CollectFields(GetOperationContext(ctx), resctx.Field.Selections, nil)
|
|
||||||
uniq := make([]string, 0, len(collected))
|
|
||||||
Next:
|
|
||||||
for _, f := range collected {
|
|
||||||
for _, name := range uniq {
|
|
||||||
if name == f.Name {
|
|
||||||
continue Next
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uniq = append(uniq, f.Name)
|
|
||||||
}
|
|
||||||
return uniq
|
|
||||||
}
|
|
||||||
|
|
||||||
// Errorf sends an error string to the client, passing it through the formatter.
|
|
||||||
// Deprecated: use graphql.AddErrorf(ctx, err) instead
|
|
||||||
func (c *OperationContext) Errorf(ctx context.Context, format string, args ...interface{}) {
|
|
||||||
AddErrorf(ctx, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error sends an error to the client, passing it through the formatter.
|
|
||||||
// Deprecated: use graphql.AddError(ctx, err) instead
|
|
||||||
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
77
vendor/github.com/99designs/gqlgen/graphql/context_path.go
generated
vendored
@@ -1,77 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
153
vendor/github.com/99designs/gqlgen/graphql/context_response.go
generated
vendored
153
vendor/github.com/99designs/gqlgen/graphql/context_response.go
generated
vendored
@@ -1,153 +0,0 @@
|
|||||||
package graphql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
|
||||||
)
|
|
||||||
|
|
||||||
type responseContext struct {
|
|
||||||
errorPresenter ErrorPresenterFunc
|
|
||||||
recover RecoverFunc
|
|
||||||
|
|
||||||
errors gqlerror.List
|
|
||||||
errorsMu sync.Mutex
|
|
||||||
|
|
||||||
extensions map[string]interface{}
|
|
||||||
extensionsMu sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
const resultCtx key = "result_context"
|
|
||||||
|
|
||||||
func getResponseContext(ctx context.Context) *responseContext {
|
|
||||||
val, ok := ctx.Value(resultCtx).(*responseContext)
|
|
||||||
if !ok {
|
|
||||||
panic("missing response context")
|
|
||||||
}
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
|
|
||||||
func WithResponseContext(ctx context.Context, presenterFunc ErrorPresenterFunc, recoverFunc RecoverFunc) context.Context {
|
|
||||||
return context.WithValue(ctx, resultCtx, &responseContext{
|
|
||||||
errorPresenter: presenterFunc,
|
|
||||||
recover: recoverFunc,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddErrorf writes a formatted error to the client, first passing it through the error presenter.
|
|
||||||
func AddErrorf(ctx context.Context, format string, args ...interface{}) {
|
|
||||||
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, presentedError)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Recover(ctx context.Context, err interface{}) (userMessage error) {
|
|
||||||
c := getResponseContext(ctx)
|
|
||||||
return ErrorOnPath(ctx, c.recover(ctx, err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasFieldError returns true if the given field has already errored
|
|
||||||
func HasFieldError(ctx context.Context, rctx *FieldContext) bool {
|
|
||||||
c := getResponseContext(ctx)
|
|
||||||
|
|
||||||
c.errorsMu.Lock()
|
|
||||||
defer c.errorsMu.Unlock()
|
|
||||||
|
|
||||||
if len(c.errors) == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
path := rctx.Path()
|
|
||||||
for _, err := range c.errors {
|
|
||||||
if equalPath(err.Path, path) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFieldErrors returns a list of errors that occurred in the given field
|
|
||||||
func GetFieldErrors(ctx context.Context, rctx *FieldContext) gqlerror.List {
|
|
||||||
c := getResponseContext(ctx)
|
|
||||||
|
|
||||||
c.errorsMu.Lock()
|
|
||||||
defer c.errorsMu.Unlock()
|
|
||||||
|
|
||||||
if len(c.errors) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
path := rctx.Path()
|
|
||||||
var errs gqlerror.List
|
|
||||||
for _, err := range c.errors {
|
|
||||||
if equalPath(err.Path, path) {
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errs
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetErrors(ctx context.Context) gqlerror.List {
|
|
||||||
resCtx := getResponseContext(ctx)
|
|
||||||
resCtx.errorsMu.Lock()
|
|
||||||
defer resCtx.errorsMu.Unlock()
|
|
||||||
|
|
||||||
if len(resCtx.errors) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
errs := resCtx.errors
|
|
||||||
cpy := make(gqlerror.List, len(errs))
|
|
||||||
for i := range errs {
|
|
||||||
errCpy := *errs[i]
|
|
||||||
cpy[i] = &errCpy
|
|
||||||
}
|
|
||||||
return cpy
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterExtension allows you to add a new extension into the graphql response
|
|
||||||
func RegisterExtension(ctx context.Context, key string, value interface{}) {
|
|
||||||
c := getResponseContext(ctx)
|
|
||||||
c.extensionsMu.Lock()
|
|
||||||
defer c.extensionsMu.Unlock()
|
|
||||||
|
|
||||||
if c.extensions == nil {
|
|
||||||
c.extensions = make(map[string]interface{})
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := c.extensions[key]; ok {
|
|
||||||
panic(fmt.Errorf("extension already registered for key %s", key))
|
|
||||||
}
|
|
||||||
|
|
||||||
c.extensions[key] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetExtensions returns any extensions registered in the current result context
|
|
||||||
func GetExtensions(ctx context.Context) map[string]interface{} {
|
|
||||||
ext := getResponseContext(ctx).extensions
|
|
||||||
if ext == nil {
|
|
||||||
return map[string]interface{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ext
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetExtension(ctx context.Context, name string) interface{} {
|
|
||||||
ext := getResponseContext(ctx).extensions
|
|
||||||
if ext == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return ext[name]
|
|
||||||
}
|
|
||||||
25
vendor/github.com/99designs/gqlgen/graphql/context_root_field.go
generated
vendored
25
vendor/github.com/99designs/gqlgen/graphql/context_root_field.go
generated
vendored
@@ -1,25 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
||||||
51
vendor/github.com/99designs/gqlgen/graphql/errcode/codes.go
generated
vendored
51
vendor/github.com/99designs/gqlgen/graphql/errcode/codes.go
generated
vendored
@@ -1,51 +0,0 @@
|
|||||||
package errcode
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
ValidationFailed = "GRAPHQL_VALIDATION_FAILED"
|
|
||||||
ParseFailed = "GRAPHQL_PARSE_FAILED"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ErrorKind int
|
|
||||||
|
|
||||||
const (
|
|
||||||
// issues with graphql (validation, parsing). 422s in http, GQL_ERROR in websocket
|
|
||||||
KindProtocol ErrorKind = iota
|
|
||||||
// user errors, 200s in http, GQL_DATA in websocket
|
|
||||||
KindUser
|
|
||||||
)
|
|
||||||
|
|
||||||
var codeType = map[string]ErrorKind{
|
|
||||||
ValidationFailed: KindProtocol,
|
|
||||||
ParseFailed: KindProtocol,
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterErrorType should be called by extensions that want to customize the http status codes for errors they return
|
|
||||||
func RegisterErrorType(code string, kind ErrorKind) {
|
|
||||||
codeType[code] = kind
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the error code on a given graphql error extension
|
|
||||||
func Set(err *gqlerror.Error, value string) {
|
|
||||||
if err.Extensions == nil {
|
|
||||||
err.Extensions = map[string]interface{}{}
|
|
||||||
}
|
|
||||||
|
|
||||||
err.Extensions["code"] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the kind of the first non User error, defaults to User if no errors have a custom extension
|
|
||||||
func GetErrorKind(errs gqlerror.List) ErrorKind {
|
|
||||||
for _, err := range errs {
|
|
||||||
if code, ok := err.Extensions["code"].(string); ok {
|
|
||||||
if kind, ok := codeType[code]; ok && kind != KindUser {
|
|
||||||
return kind
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return KindUser
|
|
||||||
}
|
|
||||||
32
vendor/github.com/99designs/gqlgen/graphql/error.go
generated
vendored
32
vendor/github.com/99designs/gqlgen/graphql/error.go
generated
vendored
@@ -1,32 +0,0 @@
|
|||||||
package graphql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ErrorPresenterFunc func(ctx context.Context, err error) *gqlerror.Error
|
|
||||||
|
|
||||||
func DefaultErrorPresenter(ctx context.Context, err error) *gqlerror.Error {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
162
vendor/github.com/99designs/gqlgen/graphql/executable_schema.go
generated
vendored
162
vendor/github.com/99designs/gqlgen/graphql/executable_schema.go
generated
vendored
@@ -1,162 +0,0 @@
|
|||||||
//go:generate go run github.com/matryer/moq -out executable_schema_mock.go . ExecutableSchema
|
|
||||||
|
|
||||||
package graphql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/vektah/gqlparser/v2/ast"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ExecutableSchema interface {
|
|
||||||
Schema() *ast.Schema
|
|
||||||
|
|
||||||
Complexity(typeName, fieldName string, childComplexity int, args map[string]interface{}) (int, bool)
|
|
||||||
Exec(ctx context.Context) ResponseHandler
|
|
||||||
}
|
|
||||||
|
|
||||||
// CollectFields returns the set of fields from an ast.SelectionSet where all collected fields satisfy at least one of the GraphQL types
|
|
||||||
// passed through satisfies. Providing an empty or nil slice for satisfies will return collect all fields regardless of fragment
|
|
||||||
// type conditions.
|
|
||||||
func CollectFields(reqCtx *OperationContext, selSet ast.SelectionSet, satisfies []string) []CollectedField {
|
|
||||||
return collectFields(reqCtx, selSet, satisfies, map[string]bool{})
|
|
||||||
}
|
|
||||||
|
|
||||||
func collectFields(reqCtx *OperationContext, selSet ast.SelectionSet, satisfies []string, visited map[string]bool) []CollectedField {
|
|
||||||
groupedFields := make([]CollectedField, 0, len(selSet))
|
|
||||||
|
|
||||||
for _, sel := range selSet {
|
|
||||||
switch sel := sel.(type) {
|
|
||||||
case *ast.Field:
|
|
||||||
if !shouldIncludeNode(sel.Directives, reqCtx.Variables) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
if len(satisfies) > 0 && !instanceOf(sel.TypeCondition, satisfies) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, childField := range collectFields(reqCtx, sel.SelectionSet, satisfies, visited) {
|
|
||||||
f := getOrCreateAndAppendField(&groupedFields, childField.Name, childField.Alias, childField.ObjectDefinition, func() CollectedField { return childField })
|
|
||||||
f.Selections = append(f.Selections, childField.Selections...)
|
|
||||||
}
|
|
||||||
|
|
||||||
case *ast.FragmentSpread:
|
|
||||||
if !shouldIncludeNode(sel.Directives, reqCtx.Variables) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fragmentName := sel.Name
|
|
||||||
if _, seen := visited[fragmentName]; seen {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
visited[fragmentName] = true
|
|
||||||
|
|
||||||
fragment := reqCtx.Doc.Fragments.ForName(fragmentName)
|
|
||||||
if fragment == nil {
|
|
||||||
// should never happen, validator has already run
|
|
||||||
panic(fmt.Errorf("missing fragment %s", fragmentName))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(satisfies) > 0 && !instanceOf(fragment.TypeCondition, satisfies) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, childField := range collectFields(reqCtx, fragment.SelectionSet, satisfies, visited) {
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return groupedFields
|
|
||||||
}
|
|
||||||
|
|
||||||
type CollectedField struct {
|
|
||||||
*ast.Field
|
|
||||||
|
|
||||||
Selections ast.SelectionSet
|
|
||||||
}
|
|
||||||
|
|
||||||
func instanceOf(val string, satisfies []string) bool {
|
|
||||||
for _, s := range satisfies {
|
|
||||||
if val == s {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func getOrCreateAndAppendField(c *[]CollectedField, name string, alias string, objectDefinition *ast.Definition, creator func() CollectedField) *CollectedField {
|
|
||||||
for i, cf := range *c {
|
|
||||||
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]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
f := creator()
|
|
||||||
|
|
||||||
*c = append(*c, f)
|
|
||||||
return &(*c)[len(*c)-1]
|
|
||||||
}
|
|
||||||
|
|
||||||
func shouldIncludeNode(directives ast.DirectiveList, variables map[string]interface{}) bool {
|
|
||||||
if len(directives) == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
skip, include := false, true
|
|
||||||
|
|
||||||
if d := directives.ForName("skip"); d != nil {
|
|
||||||
skip = resolveIfArgument(d, variables)
|
|
||||||
}
|
|
||||||
|
|
||||||
if d := directives.ForName("include"); d != nil {
|
|
||||||
include = resolveIfArgument(d, variables)
|
|
||||||
}
|
|
||||||
|
|
||||||
return !skip && include
|
|
||||||
}
|
|
||||||
|
|
||||||
func resolveIfArgument(d *ast.Directive, variables map[string]interface{}) bool {
|
|
||||||
arg := d.Arguments.ForName("if")
|
|
||||||
if arg == nil {
|
|
||||||
panic(fmt.Sprintf("%s: argument 'if' not defined", d.Name))
|
|
||||||
}
|
|
||||||
value, err := arg.Value.Value(variables)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
ret, ok := value.(bool)
|
|
||||||
if !ok {
|
|
||||||
panic(fmt.Sprintf("%s: argument 'if' is not a boolean", d.Name))
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
172
vendor/github.com/99designs/gqlgen/graphql/executable_schema_mock.go
generated
vendored
172
vendor/github.com/99designs/gqlgen/graphql/executable_schema_mock.go
generated
vendored
@@ -1,172 +0,0 @@
|
|||||||
// Code generated by moq; DO NOT EDIT.
|
|
||||||
// github.com/matryer/moq
|
|
||||||
|
|
||||||
package graphql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"github.com/vektah/gqlparser/v2/ast"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
//
|
|
||||||
// // 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.
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
type ExecutableSchemaMock struct {
|
|
||||||
// ComplexityFunc mocks the Complexity method.
|
|
||||||
ComplexityFunc func(typeName string, fieldName string, childComplexity int, args map[string]interface{}) (int, bool)
|
|
||||||
|
|
||||||
// ExecFunc mocks the Exec method.
|
|
||||||
ExecFunc func(ctx context.Context) ResponseHandler
|
|
||||||
|
|
||||||
// SchemaFunc mocks the Schema method.
|
|
||||||
SchemaFunc func() *ast.Schema
|
|
||||||
|
|
||||||
// calls tracks calls to the methods.
|
|
||||||
calls struct {
|
|
||||||
// Complexity holds details about calls to the Complexity method.
|
|
||||||
Complexity []struct {
|
|
||||||
// TypeName is the typeName argument value.
|
|
||||||
TypeName string
|
|
||||||
// FieldName is the fieldName argument value.
|
|
||||||
FieldName string
|
|
||||||
// ChildComplexity is the childComplexity argument value.
|
|
||||||
ChildComplexity int
|
|
||||||
// Args is the args argument value.
|
|
||||||
Args map[string]interface{}
|
|
||||||
}
|
|
||||||
// Exec holds details about calls to the Exec method.
|
|
||||||
Exec []struct {
|
|
||||||
// Ctx is the ctx argument value.
|
|
||||||
Ctx context.Context
|
|
||||||
}
|
|
||||||
// Schema holds details about calls to the Schema method.
|
|
||||||
Schema []struct {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lockComplexity sync.RWMutex
|
|
||||||
lockExec sync.RWMutex
|
|
||||||
lockSchema sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// Complexity calls ComplexityFunc.
|
|
||||||
func (mock *ExecutableSchemaMock) Complexity(typeName string, fieldName string, childComplexity int, args map[string]interface{}) (int, bool) {
|
|
||||||
if mock.ComplexityFunc == nil {
|
|
||||||
panic("ExecutableSchemaMock.ComplexityFunc: method is nil but ExecutableSchema.Complexity was just called")
|
|
||||||
}
|
|
||||||
callInfo := struct {
|
|
||||||
TypeName string
|
|
||||||
FieldName string
|
|
||||||
ChildComplexity int
|
|
||||||
Args map[string]interface{}
|
|
||||||
}{
|
|
||||||
TypeName: typeName,
|
|
||||||
FieldName: fieldName,
|
|
||||||
ChildComplexity: childComplexity,
|
|
||||||
Args: args,
|
|
||||||
}
|
|
||||||
mock.lockComplexity.Lock()
|
|
||||||
mock.calls.Complexity = append(mock.calls.Complexity, callInfo)
|
|
||||||
mock.lockComplexity.Unlock()
|
|
||||||
return mock.ComplexityFunc(typeName, fieldName, childComplexity, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ComplexityCalls gets all the calls that were made to Complexity.
|
|
||||||
// Check the length with:
|
|
||||||
// len(mockedExecutableSchema.ComplexityCalls())
|
|
||||||
func (mock *ExecutableSchemaMock) ComplexityCalls() []struct {
|
|
||||||
TypeName string
|
|
||||||
FieldName string
|
|
||||||
ChildComplexity int
|
|
||||||
Args map[string]interface{}
|
|
||||||
} {
|
|
||||||
var calls []struct {
|
|
||||||
TypeName string
|
|
||||||
FieldName string
|
|
||||||
ChildComplexity int
|
|
||||||
Args map[string]interface{}
|
|
||||||
}
|
|
||||||
mock.lockComplexity.RLock()
|
|
||||||
calls = mock.calls.Complexity
|
|
||||||
mock.lockComplexity.RUnlock()
|
|
||||||
return calls
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exec calls ExecFunc.
|
|
||||||
func (mock *ExecutableSchemaMock) Exec(ctx context.Context) ResponseHandler {
|
|
||||||
if mock.ExecFunc == nil {
|
|
||||||
panic("ExecutableSchemaMock.ExecFunc: method is nil but ExecutableSchema.Exec was just called")
|
|
||||||
}
|
|
||||||
callInfo := struct {
|
|
||||||
Ctx context.Context
|
|
||||||
}{
|
|
||||||
Ctx: ctx,
|
|
||||||
}
|
|
||||||
mock.lockExec.Lock()
|
|
||||||
mock.calls.Exec = append(mock.calls.Exec, callInfo)
|
|
||||||
mock.lockExec.Unlock()
|
|
||||||
return mock.ExecFunc(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExecCalls gets all the calls that were made to Exec.
|
|
||||||
// Check the length with:
|
|
||||||
// len(mockedExecutableSchema.ExecCalls())
|
|
||||||
func (mock *ExecutableSchemaMock) ExecCalls() []struct {
|
|
||||||
Ctx context.Context
|
|
||||||
} {
|
|
||||||
var calls []struct {
|
|
||||||
Ctx context.Context
|
|
||||||
}
|
|
||||||
mock.lockExec.RLock()
|
|
||||||
calls = mock.calls.Exec
|
|
||||||
mock.lockExec.RUnlock()
|
|
||||||
return calls
|
|
||||||
}
|
|
||||||
|
|
||||||
// Schema calls SchemaFunc.
|
|
||||||
func (mock *ExecutableSchemaMock) Schema() *ast.Schema {
|
|
||||||
if mock.SchemaFunc == nil {
|
|
||||||
panic("ExecutableSchemaMock.SchemaFunc: method is nil but ExecutableSchema.Schema was just called")
|
|
||||||
}
|
|
||||||
callInfo := struct {
|
|
||||||
}{}
|
|
||||||
mock.lockSchema.Lock()
|
|
||||||
mock.calls.Schema = append(mock.calls.Schema, callInfo)
|
|
||||||
mock.lockSchema.Unlock()
|
|
||||||
return mock.SchemaFunc()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SchemaCalls gets all the calls that were made to Schema.
|
|
||||||
// Check the length with:
|
|
||||||
// len(mockedExecutableSchema.SchemaCalls())
|
|
||||||
func (mock *ExecutableSchemaMock) SchemaCalls() []struct {
|
|
||||||
} {
|
|
||||||
var calls []struct {
|
|
||||||
}
|
|
||||||
mock.lockSchema.RLock()
|
|
||||||
calls = mock.calls.Schema
|
|
||||||
mock.lockSchema.RUnlock()
|
|
||||||
return calls
|
|
||||||
}
|
|
||||||
192
vendor/github.com/99designs/gqlgen/graphql/executor/executor.go
generated
vendored
192
vendor/github.com/99designs/gqlgen/graphql/executor/executor.go
generated
vendored
@@ -1,192 +0,0 @@
|
|||||||
package executor
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/graphql"
|
|
||||||
"github.com/99designs/gqlgen/graphql/errcode"
|
|
||||||
"github.com/vektah/gqlparser/v2/ast"
|
|
||||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
|
||||||
"github.com/vektah/gqlparser/v2/parser"
|
|
||||||
"github.com/vektah/gqlparser/v2/validator"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Executor executes graphql queries against a schema.
|
|
||||||
type Executor struct {
|
|
||||||
es graphql.ExecutableSchema
|
|
||||||
extensions []graphql.HandlerExtension
|
|
||||||
ext extensions
|
|
||||||
|
|
||||||
errorPresenter graphql.ErrorPresenterFunc
|
|
||||||
recoverFunc graphql.RecoverFunc
|
|
||||||
queryCache graphql.Cache
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ graphql.GraphExecutor = &Executor{}
|
|
||||||
|
|
||||||
// New creates a new Executor with the given schema, and a default error and
|
|
||||||
// recovery callbacks, and no query cache or extensions.
|
|
||||||
func New(es graphql.ExecutableSchema) *Executor {
|
|
||||||
e := &Executor{
|
|
||||||
es: es,
|
|
||||||
errorPresenter: graphql.DefaultErrorPresenter,
|
|
||||||
recoverFunc: graphql.DefaultRecover,
|
|
||||||
queryCache: graphql.NoCache{},
|
|
||||||
ext: processExtensions(nil),
|
|
||||||
}
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Executor) CreateOperationContext(ctx context.Context, params *graphql.RawParams) (*graphql.OperationContext, gqlerror.List) {
|
|
||||||
rc := &graphql.OperationContext{
|
|
||||||
DisableIntrospection: true,
|
|
||||||
RecoverFunc: e.recoverFunc,
|
|
||||||
ResolverMiddleware: e.ext.fieldMiddleware,
|
|
||||||
RootResolverMiddleware: e.ext.rootFieldMiddleware,
|
|
||||||
Stats: graphql.Stats{
|
|
||||||
Read: params.ReadTime,
|
|
||||||
OperationStart: graphql.GetStartTime(ctx),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
ctx = graphql.WithOperationContext(ctx, rc)
|
|
||||||
|
|
||||||
for _, p := range e.ext.operationParameterMutators {
|
|
||||||
if err := p.MutateOperationParameters(ctx, params); err != nil {
|
|
||||||
return rc, gqlerror.List{err}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rc.RawQuery = params.Query
|
|
||||||
rc.OperationName = params.OperationName
|
|
||||||
|
|
||||||
var listErr gqlerror.List
|
|
||||||
rc.Doc, listErr = e.parseQuery(ctx, &rc.Stats, params.Query)
|
|
||||||
if len(listErr) != 0 {
|
|
||||||
return rc, listErr
|
|
||||||
}
|
|
||||||
|
|
||||||
rc.Operation = rc.Doc.Operations.ForName(params.OperationName)
|
|
||||||
if rc.Operation == nil {
|
|
||||||
return rc, gqlerror.List{gqlerror.Errorf("operation %s not found", params.OperationName)}
|
|
||||||
}
|
|
||||||
|
|
||||||
var err *gqlerror.Error
|
|
||||||
rc.Variables, err = validator.VariableValues(e.es.Schema(), rc.Operation, params.Variables)
|
|
||||||
if err != nil {
|
|
||||||
errcode.Set(err, errcode.ValidationFailed)
|
|
||||||
return rc, gqlerror.List{err}
|
|
||||||
}
|
|
||||||
rc.Stats.Validation.End = graphql.Now()
|
|
||||||
|
|
||||||
for _, p := range e.ext.operationContextMutators {
|
|
||||||
if err := p.MutateOperationContext(ctx, rc); err != nil {
|
|
||||||
return rc, gqlerror.List{err}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Executor) DispatchOperation(ctx context.Context, rc *graphql.OperationContext) (graphql.ResponseHandler, context.Context) {
|
|
||||||
ctx = graphql.WithOperationContext(ctx, rc)
|
|
||||||
|
|
||||||
var innerCtx context.Context
|
|
||||||
res := e.ext.operationMiddleware(ctx, func(ctx context.Context) graphql.ResponseHandler {
|
|
||||||
innerCtx = ctx
|
|
||||||
|
|
||||||
tmpResponseContext := graphql.WithResponseContext(ctx, e.errorPresenter, e.recoverFunc)
|
|
||||||
responses := e.es.Exec(tmpResponseContext)
|
|
||||||
if errs := graphql.GetErrors(tmpResponseContext); errs != nil {
|
|
||||||
return graphql.OneShot(&graphql.Response{Errors: errs})
|
|
||||||
}
|
|
||||||
|
|
||||||
return func(ctx context.Context) *graphql.Response {
|
|
||||||
ctx = graphql.WithResponseContext(ctx, e.errorPresenter, e.recoverFunc)
|
|
||||||
resp := e.ext.responseMiddleware(ctx, func(ctx context.Context) *graphql.Response {
|
|
||||||
resp := responses(ctx)
|
|
||||||
if resp == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
resp.Errors = append(resp.Errors, graphql.GetErrors(ctx)...)
|
|
||||||
resp.Extensions = graphql.GetExtensions(ctx)
|
|
||||||
return resp
|
|
||||||
})
|
|
||||||
if resp == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return res, innerCtx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Executor) DispatchError(ctx context.Context, list gqlerror.List) *graphql.Response {
|
|
||||||
ctx = graphql.WithResponseContext(ctx, e.errorPresenter, e.recoverFunc)
|
|
||||||
for _, gErr := range list {
|
|
||||||
graphql.AddError(ctx, gErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp := e.ext.responseMiddleware(ctx, func(ctx context.Context) *graphql.Response {
|
|
||||||
resp := &graphql.Response{
|
|
||||||
Errors: list,
|
|
||||||
}
|
|
||||||
resp.Extensions = graphql.GetExtensions(ctx)
|
|
||||||
return resp
|
|
||||||
})
|
|
||||||
|
|
||||||
return resp
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Executor) PresentRecoveredError(ctx context.Context, err interface{}) *gqlerror.Error {
|
|
||||||
return e.errorPresenter(ctx, e.recoverFunc(ctx, err))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Executor) SetQueryCache(cache graphql.Cache) {
|
|
||||||
e.queryCache = cache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Executor) SetErrorPresenter(f graphql.ErrorPresenterFunc) {
|
|
||||||
e.errorPresenter = f
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Executor) SetRecoverFunc(f graphql.RecoverFunc) {
|
|
||||||
e.recoverFunc = f
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseQuery decodes the incoming query and validates it, pulling from cache if present.
|
|
||||||
//
|
|
||||||
// NOTE: This should NOT look at variables, they will change per request. It should only parse and validate
|
|
||||||
// the raw query string.
|
|
||||||
func (e *Executor) parseQuery(ctx context.Context, stats *graphql.Stats, query string) (*ast.QueryDocument, gqlerror.List) {
|
|
||||||
stats.Parsing.Start = graphql.Now()
|
|
||||||
|
|
||||||
if doc, ok := e.queryCache.Get(ctx, query); ok {
|
|
||||||
now := graphql.Now()
|
|
||||||
|
|
||||||
stats.Parsing.End = now
|
|
||||||
stats.Validation.Start = now
|
|
||||||
return doc.(*ast.QueryDocument), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
doc, err := parser.ParseQuery(&ast.Source{Input: query})
|
|
||||||
if err != nil {
|
|
||||||
errcode.Set(err, errcode.ParseFailed)
|
|
||||||
return nil, gqlerror.List{err}
|
|
||||||
}
|
|
||||||
stats.Parsing.End = graphql.Now()
|
|
||||||
|
|
||||||
stats.Validation.Start = graphql.Now()
|
|
||||||
listErr := validator.Validate(e.es.Schema(), doc)
|
|
||||||
if len(listErr) != 0 {
|
|
||||||
for _, e := range listErr {
|
|
||||||
errcode.Set(e, errcode.ValidationFailed)
|
|
||||||
}
|
|
||||||
return nil, listErr
|
|
||||||
}
|
|
||||||
|
|
||||||
e.queryCache.Add(ctx, query, doc)
|
|
||||||
|
|
||||||
return doc, nil
|
|
||||||
}
|
|
||||||
195
vendor/github.com/99designs/gqlgen/graphql/executor/extensions.go
generated
vendored
195
vendor/github.com/99designs/gqlgen/graphql/executor/extensions.go
generated
vendored
@@ -1,195 +0,0 @@
|
|||||||
package executor
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/graphql"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Use adds the given extension to this Executor.
|
|
||||||
func (e *Executor) Use(extension graphql.HandlerExtension) {
|
|
||||||
if err := extension.Validate(e.es); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch extension.(type) {
|
|
||||||
case graphql.OperationParameterMutator,
|
|
||||||
graphql.OperationContextMutator,
|
|
||||||
graphql.OperationInterceptor,
|
|
||||||
graphql.RootFieldInterceptor,
|
|
||||||
graphql.FieldInterceptor,
|
|
||||||
graphql.ResponseInterceptor:
|
|
||||||
e.extensions = append(e.extensions, extension)
|
|
||||||
e.ext = processExtensions(e.extensions)
|
|
||||||
|
|
||||||
default:
|
|
||||||
panic(fmt.Errorf("cannot Use %T as a gqlgen handler extension because it does not implement any extension hooks", extension))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AroundFields is a convenience method for creating an extension that only implements field middleware
|
|
||||||
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))
|
|
||||||
}
|
|
||||||
|
|
||||||
// AroundResponses is a convenience method for creating an extension that only implements response middleware
|
|
||||||
func (e *Executor) AroundResponses(f graphql.ResponseMiddleware) {
|
|
||||||
e.Use(aroundRespFunc(f))
|
|
||||||
}
|
|
||||||
|
|
||||||
type extensions struct {
|
|
||||||
operationMiddleware graphql.OperationMiddleware
|
|
||||||
responseMiddleware graphql.ResponseMiddleware
|
|
||||||
rootFieldMiddleware graphql.RootFieldMiddleware
|
|
||||||
fieldMiddleware graphql.FieldMiddleware
|
|
||||||
operationParameterMutators []graphql.OperationParameterMutator
|
|
||||||
operationContextMutators []graphql.OperationContextMutator
|
|
||||||
}
|
|
||||||
|
|
||||||
func processExtensions(exts []graphql.HandlerExtension) extensions {
|
|
||||||
e := extensions{
|
|
||||||
operationMiddleware: func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler {
|
|
||||||
return next(ctx)
|
|
||||||
},
|
|
||||||
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)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// this loop goes backwards so the first extension is the outer most middleware and runs first.
|
|
||||||
for i := len(exts) - 1; i >= 0; i-- {
|
|
||||||
p := exts[i]
|
|
||||||
if p, ok := p.(graphql.OperationInterceptor); ok {
|
|
||||||
previous := e.operationMiddleware
|
|
||||||
e.operationMiddleware = func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler {
|
|
||||||
return p.InterceptOperation(ctx, func(ctx context.Context) graphql.ResponseHandler {
|
|
||||||
return previous(ctx, next)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if p, ok := p.(graphql.ResponseInterceptor); ok {
|
|
||||||
previous := e.responseMiddleware
|
|
||||||
e.responseMiddleware = func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
|
|
||||||
return p.InterceptResponse(ctx, func(ctx context.Context) *graphql.Response {
|
|
||||||
return previous(ctx, next)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
return p.InterceptField(ctx, func(ctx context.Context) (res interface{}, err error) {
|
|
||||||
return previous(ctx, next)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, p := range exts {
|
|
||||||
if p, ok := p.(graphql.OperationParameterMutator); ok {
|
|
||||||
e.operationParameterMutators = append(e.operationParameterMutators, p)
|
|
||||||
}
|
|
||||||
|
|
||||||
if p, ok := p.(graphql.OperationContextMutator); ok {
|
|
||||||
e.operationContextMutators = append(e.operationContextMutators, p)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
type aroundOpFunc func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler
|
|
||||||
|
|
||||||
func (r aroundOpFunc) ExtensionName() string {
|
|
||||||
return "InlineOperationFunc"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r aroundOpFunc) Validate(schema graphql.ExecutableSchema) error {
|
|
||||||
if r == nil {
|
|
||||||
return fmt.Errorf("OperationFunc can not be nil")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r aroundOpFunc) InterceptOperation(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler {
|
|
||||||
return r(ctx, next)
|
|
||||||
}
|
|
||||||
|
|
||||||
type aroundRespFunc func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response
|
|
||||||
|
|
||||||
func (r aroundRespFunc) ExtensionName() string {
|
|
||||||
return "InlineResponseFunc"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r aroundRespFunc) Validate(schema graphql.ExecutableSchema) error {
|
|
||||||
if r == nil {
|
|
||||||
return fmt.Errorf("ResponseFunc can not be nil")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r aroundRespFunc) InterceptResponse(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
|
|
||||||
return r(ctx, next)
|
|
||||||
}
|
|
||||||
|
|
||||||
type aroundFieldFunc func(ctx context.Context, next graphql.Resolver) (res interface{}, err error)
|
|
||||||
|
|
||||||
func (f aroundFieldFunc) ExtensionName() string {
|
|
||||||
return "InlineFieldFunc"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f aroundFieldFunc) Validate(schema graphql.ExecutableSchema) error {
|
|
||||||
if f == nil {
|
|
||||||
return fmt.Errorf("FieldFunc can not be nil")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
63
vendor/github.com/99designs/gqlgen/graphql/fieldset.go
generated
vendored
63
vendor/github.com/99designs/gqlgen/graphql/fieldset.go
generated
vendored
@@ -1,63 +0,0 @@
|
|||||||
package graphql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FieldSet struct {
|
|
||||||
fields []CollectedField
|
|
||||||
Values []Marshaler
|
|
||||||
delayed []delayedResult
|
|
||||||
}
|
|
||||||
|
|
||||||
type delayedResult struct {
|
|
||||||
i int
|
|
||||||
f func() Marshaler
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewFieldSet(fields []CollectedField) *FieldSet {
|
|
||||||
return &FieldSet{
|
|
||||||
fields: fields,
|
|
||||||
Values: make([]Marshaler, len(fields)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *FieldSet) Concurrently(i int, f func() Marshaler) {
|
|
||||||
m.delayed = append(m.delayed, delayedResult{i: i, f: f})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *FieldSet) Dispatch() {
|
|
||||||
if len(m.delayed) == 1 {
|
|
||||||
// only one concurrent task, no need to spawn a goroutine or deal create waitgroups
|
|
||||||
d := m.delayed[0]
|
|
||||||
m.Values[d.i] = d.f()
|
|
||||||
} else if len(m.delayed) > 1 {
|
|
||||||
// more than one concurrent task, use the main goroutine to do one, only spawn goroutines for the others
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
for _, d := range m.delayed[1:] {
|
|
||||||
wg.Add(1)
|
|
||||||
go func(d delayedResult) {
|
|
||||||
m.Values[d.i] = d.f()
|
|
||||||
wg.Done()
|
|
||||||
}(d)
|
|
||||||
}
|
|
||||||
|
|
||||||
m.Values[m.delayed[0].i] = m.delayed[0].f()
|
|
||||||
wg.Wait()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *FieldSet) MarshalGQL(writer io.Writer) {
|
|
||||||
writer.Write(openBrace)
|
|
||||||
for i, field := range m.fields {
|
|
||||||
if i != 0 {
|
|
||||||
writer.Write(comma)
|
|
||||||
}
|
|
||||||
writeQuotedString(writer, field.Alias)
|
|
||||||
writer.Write(colon)
|
|
||||||
m.Values[i].MarshalGQL(writer)
|
|
||||||
}
|
|
||||||
writer.Write(closeBrace)
|
|
||||||
}
|
|
||||||
47
vendor/github.com/99designs/gqlgen/graphql/float.go
generated
vendored
47
vendor/github.com/99designs/gqlgen/graphql/float.go
generated
vendored
@@ -1,47 +0,0 @@
|
|||||||
package graphql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"math"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
func MarshalFloat(f float64) Marshaler {
|
|
||||||
return WriterFunc(func(w io.Writer) {
|
|
||||||
io.WriteString(w, fmt.Sprintf("%g", f))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func UnmarshalFloat(v interface{}) (float64, error) {
|
|
||||||
switch v := v.(type) {
|
|
||||||
case string:
|
|
||||||
return strconv.ParseFloat(v, 64)
|
|
||||||
case int:
|
|
||||||
return float64(v), nil
|
|
||||||
case int64:
|
|
||||||
return float64(v), nil
|
|
||||||
case float64:
|
|
||||||
return v, nil
|
|
||||||
case json.Number:
|
|
||||||
return strconv.ParseFloat(string(v), 64)
|
|
||||||
default:
|
|
||||||
return 0, fmt.Errorf("%T is not an float", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
130
vendor/github.com/99designs/gqlgen/graphql/handler.go
generated
vendored
130
vendor/github.com/99designs/gqlgen/graphql/handler.go
generated
vendored
@@ -1,130 +0,0 @@
|
|||||||
package graphql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
OperationMiddleware func(ctx context.Context, next OperationHandler) ResponseHandler
|
|
||||||
OperationHandler func(ctx context.Context) ResponseHandler
|
|
||||||
|
|
||||||
ResponseHandler func(ctx context.Context) *Response
|
|
||||||
ResponseMiddleware func(ctx context.Context, next ResponseHandler) *Response
|
|
||||||
|
|
||||||
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"`
|
|
||||||
Variables map[string]interface{} `json:"variables"`
|
|
||||||
Extensions map[string]interface{} `json:"extensions"`
|
|
||||||
|
|
||||||
ReadTime TraceTiming `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
GraphExecutor interface {
|
|
||||||
CreateOperationContext(ctx context.Context, params *RawParams) (*OperationContext, gqlerror.List)
|
|
||||||
DispatchOperation(ctx context.Context, rc *OperationContext) (ResponseHandler, context.Context)
|
|
||||||
DispatchError(ctx context.Context, list gqlerror.List) *Response
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandlerExtension adds functionality to the http handler. See the list of possible hook points below
|
|
||||||
// Its important to understand the lifecycle of a graphql request and the terminology we use in gqlgen
|
|
||||||
// before working with these
|
|
||||||
//
|
|
||||||
// +--- REQUEST POST /graphql --------------------------------------------+
|
|
||||||
// | +- OPERATION query OpName { viewer { name } } -----------------------+ |
|
|
||||||
// | | RESPONSE { "data": { "viewer": { "name": "bob" } } } | |
|
|
||||||
// | +- OPERATION subscription OpName2 { chat { message } } --------------+ |
|
|
||||||
// | | RESPONSE { "data": { "chat": { "message": "hello" } } } | |
|
|
||||||
// | | RESPONSE { "data": { "chat": { "message": "byee" } } } | |
|
|
||||||
// | +--------------------------------------------------------------------+ |
|
|
||||||
// +------------------------------------------------------------------------+
|
|
||||||
HandlerExtension interface {
|
|
||||||
// ExtensionName should be a CamelCase string version of the extension which may be shown in stats and logging.
|
|
||||||
ExtensionName() string
|
|
||||||
// Validate is called when adding an extension to the server, it allows validation against the servers schema.
|
|
||||||
Validate(schema ExecutableSchema) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// OperationParameterMutator is called before creating a request context. allows manipulating the raw query
|
|
||||||
// on the way in.
|
|
||||||
OperationParameterMutator interface {
|
|
||||||
MutateOperationParameters(ctx context.Context, request *RawParams) *gqlerror.Error
|
|
||||||
}
|
|
||||||
|
|
||||||
// OperationContextMutator is called after creating the request context, but before executing the root resolver.
|
|
||||||
OperationContextMutator interface {
|
|
||||||
MutateOperationContext(ctx context.Context, rc *OperationContext) *gqlerror.Error
|
|
||||||
}
|
|
||||||
|
|
||||||
// OperationInterceptor is called for each incoming query, for basic requests the writer will be invoked once,
|
|
||||||
// for subscriptions it will be invoked multiple times.
|
|
||||||
OperationInterceptor interface {
|
|
||||||
InterceptOperation(ctx context.Context, next OperationHandler) ResponseHandler
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResponseInterceptor is called around each graphql operation response. This can be called many times for a single
|
|
||||||
// operation the case of subscriptions.
|
|
||||||
ResponseInterceptor interface {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transport provides support for different wire level encodings of graphql requests, eg Form, Get, Post, Websocket
|
|
||||||
Transport interface {
|
|
||||||
Supports(r *http.Request) bool
|
|
||||||
Do(w http.ResponseWriter, r *http.Request, exec GraphExecutor)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
type Status int
|
|
||||||
|
|
||||||
func (p *RawParams) AddUpload(upload Upload, key, path string) *gqlerror.Error {
|
|
||||||
if !strings.HasPrefix(path, "variables.") {
|
|
||||||
return gqlerror.Errorf("invalid operations paths for key %s", key)
|
|
||||||
}
|
|
||||||
|
|
||||||
var ptr interface{} = p.Variables
|
|
||||||
parts := strings.Split(path, ".")
|
|
||||||
|
|
||||||
// skip the first part (variables) because we started there
|
|
||||||
for i, p := range parts[1:] {
|
|
||||||
last := i == len(parts)-2
|
|
||||||
if ptr == nil {
|
|
||||||
return gqlerror.Errorf("path is missing \"variables.\" prefix, key: %s, path: %s", key, path)
|
|
||||||
}
|
|
||||||
if index, parseNbrErr := strconv.Atoi(p); parseNbrErr == nil {
|
|
||||||
if last {
|
|
||||||
ptr.([]interface{})[index] = upload
|
|
||||||
} else {
|
|
||||||
ptr = ptr.([]interface{})[index]
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if last {
|
|
||||||
ptr.(map[string]interface{})[p] = upload
|
|
||||||
} else {
|
|
||||||
ptr = ptr.(map[string]interface{})[p]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
114
vendor/github.com/99designs/gqlgen/graphql/handler/extension/apq.go
generated
vendored
114
vendor/github.com/99designs/gqlgen/graphql/handler/extension/apq.go
generated
vendored
@@ -1,114 +0,0 @@
|
|||||||
package extension
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/sha256"
|
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/graphql/errcode"
|
|
||||||
|
|
||||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/graphql"
|
|
||||||
"github.com/mitchellh/mapstructure"
|
|
||||||
)
|
|
||||||
|
|
||||||
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
|
|
||||||
// hash in the next request.
|
|
||||||
// see https://github.com/apollographql/apollo-link-persisted-queries
|
|
||||||
type AutomaticPersistedQuery struct {
|
|
||||||
Cache graphql.Cache
|
|
||||||
}
|
|
||||||
|
|
||||||
type ApqStats struct {
|
|
||||||
// The hash of the incoming query
|
|
||||||
Hash string
|
|
||||||
|
|
||||||
// SentQuery is true if the incoming request sent the full query
|
|
||||||
SentQuery bool
|
|
||||||
}
|
|
||||||
|
|
||||||
const apqExtension = "APQ"
|
|
||||||
|
|
||||||
var _ interface {
|
|
||||||
graphql.OperationParameterMutator
|
|
||||||
graphql.HandlerExtension
|
|
||||||
} = AutomaticPersistedQuery{}
|
|
||||||
|
|
||||||
func (a AutomaticPersistedQuery) ExtensionName() string {
|
|
||||||
return "AutomaticPersistedQuery"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a AutomaticPersistedQuery) Validate(schema graphql.ExecutableSchema) error {
|
|
||||||
if a.Cache == nil {
|
|
||||||
return fmt.Errorf("AutomaticPersistedQuery.Cache can not be nil")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a AutomaticPersistedQuery) MutateOperationParameters(ctx context.Context, rawParams *graphql.RawParams) *gqlerror.Error {
|
|
||||||
if rawParams.Extensions["persistedQuery"] == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var extension struct {
|
|
||||||
Sha256 string `mapstructure:"sha256Hash"`
|
|
||||||
Version int64 `mapstructure:"version"`
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := mapstructure.Decode(rawParams.Extensions["persistedQuery"], &extension); err != nil {
|
|
||||||
return gqlerror.Errorf("invalid APQ extension data")
|
|
||||||
}
|
|
||||||
|
|
||||||
if extension.Version != 1 {
|
|
||||||
return gqlerror.Errorf("unsupported APQ version")
|
|
||||||
}
|
|
||||||
|
|
||||||
fullQuery := false
|
|
||||||
if rawParams.Query == "" {
|
|
||||||
// client sent optimistic query hash without query string, get it from the cache
|
|
||||||
query, ok := a.Cache.Get(ctx, extension.Sha256)
|
|
||||||
if !ok {
|
|
||||||
err := gqlerror.Errorf(errPersistedQueryNotFound)
|
|
||||||
errcode.Set(err, errPersistedQueryNotFoundCode)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rawParams.Query = query.(string)
|
|
||||||
} else {
|
|
||||||
// client sent optimistic query hash with query string, verify and store it
|
|
||||||
if computeQueryHash(rawParams.Query) != extension.Sha256 {
|
|
||||||
return gqlerror.Errorf("provided APQ hash does not match query")
|
|
||||||
}
|
|
||||||
a.Cache.Add(ctx, extension.Sha256, rawParams.Query)
|
|
||||||
fullQuery = true
|
|
||||||
}
|
|
||||||
|
|
||||||
graphql.GetOperationContext(ctx).Stats.SetExtension(apqExtension, &ApqStats{
|
|
||||||
Hash: extension.Sha256,
|
|
||||||
SentQuery: fullQuery,
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetApqStats(ctx context.Context) *ApqStats {
|
|
||||||
rc := graphql.GetOperationContext(ctx)
|
|
||||||
if rc == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
s, _ := rc.Stats.GetExtension(apqExtension).(*ApqStats)
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func computeQueryHash(query string) string {
|
|
||||||
b := sha256.Sum256([]byte(query))
|
|
||||||
return hex.EncodeToString(b[:])
|
|
||||||
}
|
|
||||||
88
vendor/github.com/99designs/gqlgen/graphql/handler/extension/complexity.go
generated
vendored
88
vendor/github.com/99designs/gqlgen/graphql/handler/extension/complexity.go
generated
vendored
@@ -1,88 +0,0 @@
|
|||||||
package extension
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/complexity"
|
|
||||||
"github.com/99designs/gqlgen/graphql"
|
|
||||||
"github.com/99designs/gqlgen/graphql/errcode"
|
|
||||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
|
||||||
)
|
|
||||||
|
|
||||||
const errComplexityLimit = "COMPLEXITY_LIMIT_EXCEEDED"
|
|
||||||
|
|
||||||
// ComplexityLimit allows you to define a limit on query complexity
|
|
||||||
//
|
|
||||||
// If a query is submitted that exceeds the limit, a 422 status code will be returned.
|
|
||||||
type ComplexityLimit struct {
|
|
||||||
Func func(ctx context.Context, rc *graphql.OperationContext) int
|
|
||||||
|
|
||||||
es graphql.ExecutableSchema
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ interface {
|
|
||||||
graphql.OperationContextMutator
|
|
||||||
graphql.HandlerExtension
|
|
||||||
} = &ComplexityLimit{}
|
|
||||||
|
|
||||||
const complexityExtension = "ComplexityLimit"
|
|
||||||
|
|
||||||
type ComplexityStats struct {
|
|
||||||
// The calculated complexity for this request
|
|
||||||
Complexity int
|
|
||||||
|
|
||||||
// The complexity limit for this request returned by the extension func
|
|
||||||
ComplexityLimit int
|
|
||||||
}
|
|
||||||
|
|
||||||
// FixedComplexityLimit sets a complexity limit that does not change
|
|
||||||
func FixedComplexityLimit(limit int) *ComplexityLimit {
|
|
||||||
return &ComplexityLimit{
|
|
||||||
Func: func(ctx context.Context, rc *graphql.OperationContext) int {
|
|
||||||
return limit
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c ComplexityLimit) ExtensionName() string {
|
|
||||||
return complexityExtension
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *ComplexityLimit) Validate(schema graphql.ExecutableSchema) error {
|
|
||||||
if c.Func == nil {
|
|
||||||
return fmt.Errorf("ComplexityLimit func can not be nil")
|
|
||||||
}
|
|
||||||
c.es = schema
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c ComplexityLimit) MutateOperationContext(ctx context.Context, rc *graphql.OperationContext) *gqlerror.Error {
|
|
||||||
op := rc.Doc.Operations.ForName(rc.OperationName)
|
|
||||||
complexity := complexity.Calculate(c.es, op, rc.Variables)
|
|
||||||
|
|
||||||
limit := c.Func(ctx, rc)
|
|
||||||
|
|
||||||
rc.Stats.SetExtension(complexityExtension, &ComplexityStats{
|
|
||||||
Complexity: complexity,
|
|
||||||
ComplexityLimit: limit,
|
|
||||||
})
|
|
||||||
|
|
||||||
if complexity > limit {
|
|
||||||
err := gqlerror.Errorf("operation has complexity %d, which exceeds the limit of %d", complexity, limit)
|
|
||||||
errcode.Set(err, errComplexityLimit)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetComplexityStats(ctx context.Context) *ComplexityStats {
|
|
||||||
rc := graphql.GetOperationContext(ctx)
|
|
||||||
if rc == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
s, _ := rc.Stats.GetExtension(complexityExtension).(*ComplexityStats)
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
29
vendor/github.com/99designs/gqlgen/graphql/handler/extension/introspection.go
generated
vendored
29
vendor/github.com/99designs/gqlgen/graphql/handler/extension/introspection.go
generated
vendored
@@ -1,29 +0,0 @@
|
|||||||
package extension
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/graphql"
|
|
||||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
|
||||||
)
|
|
||||||
|
|
||||||
// EnableIntrospection enables clients to reflect all of the types available on the graph.
|
|
||||||
type Introspection struct{}
|
|
||||||
|
|
||||||
var _ interface {
|
|
||||||
graphql.OperationContextMutator
|
|
||||||
graphql.HandlerExtension
|
|
||||||
} = Introspection{}
|
|
||||||
|
|
||||||
func (c Introspection) ExtensionName() string {
|
|
||||||
return "Introspection"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Introspection) Validate(schema graphql.ExecutableSchema) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Introspection) MutateOperationContext(ctx context.Context, rc *graphql.OperationContext) *gqlerror.Error {
|
|
||||||
rc.DisableIntrospection = false
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
32
vendor/github.com/99designs/gqlgen/graphql/handler/lru/lru.go
generated
vendored
32
vendor/github.com/99designs/gqlgen/graphql/handler/lru/lru.go
generated
vendored
@@ -1,32 +0,0 @@
|
|||||||
package lru
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/graphql"
|
|
||||||
lru "github.com/hashicorp/golang-lru"
|
|
||||||
)
|
|
||||||
|
|
||||||
type LRU struct {
|
|
||||||
lru *lru.Cache
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ graphql.Cache = &LRU{}
|
|
||||||
|
|
||||||
func New(size int) *LRU {
|
|
||||||
cache, err := lru.New(size)
|
|
||||||
if err != nil {
|
|
||||||
// An error is only returned for non-positive cache size
|
|
||||||
// and we already checked for that.
|
|
||||||
panic("unexpected error creating cache: " + err.Error())
|
|
||||||
}
|
|
||||||
return &LRU{cache}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l LRU) Get(ctx context.Context, key string) (value interface{}, ok bool) {
|
|
||||||
return l.lru.Get(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l LRU) Add(ctx context.Context, key string, value interface{}) {
|
|
||||||
l.lru.Add(key, value)
|
|
||||||
}
|
|
||||||
185
vendor/github.com/99designs/gqlgen/graphql/handler/server.go
generated
vendored
185
vendor/github.com/99designs/gqlgen/graphql/handler/server.go
generated
vendored
@@ -1,185 +0,0 @@
|
|||||||
package handler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/graphql"
|
|
||||||
"github.com/99designs/gqlgen/graphql/executor"
|
|
||||||
"github.com/99designs/gqlgen/graphql/handler/extension"
|
|
||||||
"github.com/99designs/gqlgen/graphql/handler/lru"
|
|
||||||
"github.com/99designs/gqlgen/graphql/handler/transport"
|
|
||||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
Server struct {
|
|
||||||
transports []graphql.Transport
|
|
||||||
exec *executor.Executor
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func New(es graphql.ExecutableSchema) *Server {
|
|
||||||
return &Server{
|
|
||||||
exec: executor.New(es),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDefaultServer(es graphql.ExecutableSchema) *Server {
|
|
||||||
srv := New(es)
|
|
||||||
|
|
||||||
srv.AddTransport(transport.Websocket{
|
|
||||||
KeepAlivePingInterval: 10 * time.Second,
|
|
||||||
})
|
|
||||||
srv.AddTransport(transport.Options{})
|
|
||||||
srv.AddTransport(transport.GET{})
|
|
||||||
srv.AddTransport(transport.POST{})
|
|
||||||
srv.AddTransport(transport.MultipartForm{})
|
|
||||||
|
|
||||||
srv.SetQueryCache(lru.New(1000))
|
|
||||||
|
|
||||||
srv.Use(extension.Introspection{})
|
|
||||||
srv.Use(extension.AutomaticPersistedQuery{
|
|
||||||
Cache: lru.New(100),
|
|
||||||
})
|
|
||||||
|
|
||||||
return srv
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) AddTransport(transport graphql.Transport) {
|
|
||||||
s.transports = append(s.transports, transport)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) SetErrorPresenter(f graphql.ErrorPresenterFunc) {
|
|
||||||
s.exec.SetErrorPresenter(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) SetRecoverFunc(f graphql.RecoverFunc) {
|
|
||||||
s.exec.SetRecoverFunc(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) SetQueryCache(cache graphql.Cache) {
|
|
||||||
s.exec.SetQueryCache(cache)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) Use(extension graphql.HandlerExtension) {
|
|
||||||
s.exec.Use(extension)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AroundFields is a convenience method for creating an extension that only implements field middleware
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AroundResponses is a convenience method for creating an extension that only implements response middleware
|
|
||||||
func (s *Server) AroundResponses(f graphql.ResponseMiddleware) {
|
|
||||||
s.exec.AroundResponses(f)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) getTransport(r *http.Request) graphql.Transport {
|
|
||||||
for _, t := range s.transports {
|
|
||||||
if t.Supports(r) {
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
defer func() {
|
|
||||||
if err := recover(); err != nil {
|
|
||||||
err := s.exec.PresentRecoveredError(r.Context(), err)
|
|
||||||
resp := &graphql.Response{Errors: []*gqlerror.Error{err}}
|
|
||||||
b, _ := json.Marshal(resp)
|
|
||||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
|
||||||
w.Write(b)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
r = r.WithContext(graphql.StartOperationTrace(r.Context()))
|
|
||||||
|
|
||||||
transport := s.getTransport(r)
|
|
||||||
if transport == nil {
|
|
||||||
sendErrorf(w, http.StatusBadRequest, "transport not supported")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
transport.Do(w, r, s.exec)
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendError(w http.ResponseWriter, code int, errors ...*gqlerror.Error) {
|
|
||||||
w.WriteHeader(code)
|
|
||||||
b, err := json.Marshal(&graphql.Response{Errors: errors})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
w.Write(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendErrorf(w http.ResponseWriter, code int, format string, args ...interface{}) {
|
|
||||||
sendError(w, code, &gqlerror.Error{Message: fmt.Sprintf(format, args...)})
|
|
||||||
}
|
|
||||||
|
|
||||||
type OperationFunc func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler
|
|
||||||
|
|
||||||
func (r OperationFunc) ExtensionName() string {
|
|
||||||
return "InlineOperationFunc"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r OperationFunc) Validate(schema graphql.ExecutableSchema) error {
|
|
||||||
if r == nil {
|
|
||||||
return fmt.Errorf("OperationFunc can not be nil")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r OperationFunc) InterceptOperation(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler {
|
|
||||||
return r(ctx, next)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResponseFunc func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response
|
|
||||||
|
|
||||||
func (r ResponseFunc) ExtensionName() string {
|
|
||||||
return "InlineResponseFunc"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r ResponseFunc) Validate(schema graphql.ExecutableSchema) error {
|
|
||||||
if r == nil {
|
|
||||||
return fmt.Errorf("ResponseFunc can not be nil")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r ResponseFunc) InterceptResponse(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
|
|
||||||
return r(ctx, next)
|
|
||||||
}
|
|
||||||
|
|
||||||
type FieldFunc func(ctx context.Context, next graphql.Resolver) (res interface{}, err error)
|
|
||||||
|
|
||||||
func (f FieldFunc) ExtensionName() string {
|
|
||||||
return "InlineFieldFunc"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f FieldFunc) Validate(schema graphql.ExecutableSchema) error {
|
|
||||||
if f == nil {
|
|
||||||
return fmt.Errorf("FieldFunc can not be nil")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f FieldFunc) InterceptField(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
|
|
||||||
return f(ctx, next)
|
|
||||||
}
|
|
||||||
26
vendor/github.com/99designs/gqlgen/graphql/handler/transport/error.go
generated
vendored
26
vendor/github.com/99designs/gqlgen/graphql/handler/transport/error.go
generated
vendored
@@ -1,26 +0,0 @@
|
|||||||
package transport
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/graphql"
|
|
||||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SendError sends a best effort error to a raw response writer. It assumes the client can understand the standard
|
|
||||||
// json error response
|
|
||||||
func SendError(w http.ResponseWriter, code int, errors ...*gqlerror.Error) {
|
|
||||||
w.WriteHeader(code)
|
|
||||||
b, err := json.Marshal(&graphql.Response{Errors: errors})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
w.Write(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SendErrorf wraps SendError to add formatted messages
|
|
||||||
func SendErrorf(w http.ResponseWriter, code int, format string, args ...interface{}) {
|
|
||||||
SendError(w, code, &gqlerror.Error{Message: fmt.Sprintf(format, args...)})
|
|
||||||
}
|
|
||||||
208
vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_form.go
generated
vendored
208
vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_form.go
generated
vendored
@@ -1,208 +0,0 @@
|
|||||||
package transport
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"mime"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/graphql"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MultipartForm the Multipart request spec https://github.com/jaydenseric/graphql-multipart-request-spec
|
|
||||||
type MultipartForm struct {
|
|
||||||
// MaxUploadSize sets the maximum number of bytes used to parse a request body
|
|
||||||
// as multipart/form-data.
|
|
||||||
MaxUploadSize int64
|
|
||||||
|
|
||||||
// MaxMemory defines 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.
|
|
||||||
MaxMemory int64
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ graphql.Transport = MultipartForm{}
|
|
||||||
|
|
||||||
func (f MultipartForm) Supports(r *http.Request) bool {
|
|
||||||
if r.Header.Get("Upgrade") != "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
mediaType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return r.Method == "POST" && mediaType == "multipart/form-data"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f MultipartForm) maxUploadSize() int64 {
|
|
||||||
if f.MaxUploadSize == 0 {
|
|
||||||
return 32 << 20
|
|
||||||
}
|
|
||||||
return f.MaxUploadSize
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f MultipartForm) maxMemory() int64 {
|
|
||||||
if f.MaxMemory == 0 {
|
|
||||||
return 32 << 20
|
|
||||||
}
|
|
||||||
return f.MaxMemory
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f MultipartForm) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
|
|
||||||
start := graphql.Now()
|
|
||||||
|
|
||||||
var err error
|
|
||||||
if r.ContentLength > f.maxUploadSize() {
|
|
||||||
writeJsonError(w, "failed to parse multipart form, request body too large")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
r.Body = http.MaxBytesReader(w, r.Body, f.maxUploadSize())
|
|
||||||
if err = r.ParseMultipartForm(f.maxMemory()); err != nil {
|
|
||||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
|
||||||
if strings.Contains(err.Error(), "request body too large") {
|
|
||||||
writeJsonError(w, "failed to parse multipart form, request body too large")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
writeJsonError(w, "failed to parse multipart form")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer r.Body.Close()
|
|
||||||
|
|
||||||
var params graphql.RawParams
|
|
||||||
|
|
||||||
if err = jsonDecode(strings.NewReader(r.Form.Get("operations")), ¶ms); err != nil {
|
|
||||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
|
||||||
writeJsonError(w, "operations form field could not be decoded")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
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")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var upload graphql.Upload
|
|
||||||
for key, paths := range uploadsMap {
|
|
||||||
if len(paths) == 0 {
|
|
||||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
|
||||||
writeJsonErrorf(w, "invalid empty operations paths list for key %s", key)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
file, header, err := r.FormFile(key)
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
|
||||||
writeJsonErrorf(w, "failed to get key %s from form", key)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
if len(paths) == 1 {
|
|
||||||
upload = graphql.Upload{
|
|
||||||
File: file,
|
|
||||||
Size: header.Size,
|
|
||||||
Filename: header.Filename,
|
|
||||||
ContentType: header.Header.Get("Content-Type"),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := params.AddUpload(upload, key, paths[0]); err != nil {
|
|
||||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
|
||||||
writeJsonGraphqlError(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if r.ContentLength < f.maxMemory() {
|
|
||||||
fileBytes, err := ioutil.ReadAll(file)
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
|
||||||
writeJsonErrorf(w, "failed to read file for key %s", key)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, path := range paths {
|
|
||||||
upload = graphql.Upload{
|
|
||||||
File: &bytesReader{s: &fileBytes, i: 0, prevRune: -1},
|
|
||||||
Size: header.Size,
|
|
||||||
Filename: header.Filename,
|
|
||||||
ContentType: header.Header.Get("Content-Type"),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := params.AddUpload(upload, key, path); err != nil {
|
|
||||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
|
||||||
writeJsonGraphqlError(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tmpFile, err := ioutil.TempFile(os.TempDir(), "gqlgen-")
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
|
||||||
writeJsonErrorf(w, "failed to create temp file for key %s", key)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
tmpName := tmpFile.Name()
|
|
||||||
defer func() {
|
|
||||||
_ = os.Remove(tmpName)
|
|
||||||
}()
|
|
||||||
_, err = io.Copy(tmpFile, file)
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
|
||||||
if err := tmpFile.Close(); err != nil {
|
|
||||||
writeJsonErrorf(w, "failed to copy to temp file and close temp file for key %s", key)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
writeJsonErrorf(w, "failed to copy to temp file for key %s", key)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := tmpFile.Close(); err != nil {
|
|
||||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
|
||||||
writeJsonErrorf(w, "failed to close temp file for key %s", key)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, path := range paths {
|
|
||||||
pathTmpFile, err := os.Open(tmpName)
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
|
||||||
writeJsonErrorf(w, "failed to open temp file for key %s", key)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer pathTmpFile.Close()
|
|
||||||
upload = graphql.Upload{
|
|
||||||
File: pathTmpFile,
|
|
||||||
Size: header.Size,
|
|
||||||
Filename: header.Filename,
|
|
||||||
ContentType: header.Header.Get("Content-Type"),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := params.AddUpload(upload, key, path); err != nil {
|
|
||||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
|
||||||
writeJsonGraphqlError(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
params.ReadTime = graphql.TraceTiming{
|
|
||||||
Start: start,
|
|
||||||
End: graphql.Now(),
|
|
||||||
}
|
|
||||||
|
|
||||||
rc, gerr := exec.CreateOperationContext(r.Context(), ¶ms)
|
|
||||||
if gerr != nil {
|
|
||||||
resp := exec.DispatchError(graphql.WithOperationContext(r.Context(), rc), gerr)
|
|
||||||
w.WriteHeader(statusFor(gerr))
|
|
||||||
writeJson(w, resp)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
responses, ctx := exec.DispatchOperation(r.Context(), rc)
|
|
||||||
writeJson(w, responses(ctx))
|
|
||||||
}
|
|
||||||
87
vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_get.go
generated
vendored
87
vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_get.go
generated
vendored
@@ -1,87 +0,0 @@
|
|||||||
package transport
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/graphql"
|
|
||||||
"github.com/99designs/gqlgen/graphql/errcode"
|
|
||||||
"github.com/vektah/gqlparser/v2/ast"
|
|
||||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GET implements the GET side of the default HTTP transport
|
|
||||||
// defined in https://github.com/APIs-guru/graphql-over-http#get
|
|
||||||
type GET struct{}
|
|
||||||
|
|
||||||
var _ graphql.Transport = GET{}
|
|
||||||
|
|
||||||
func (h GET) Supports(r *http.Request) bool {
|
|
||||||
if r.Header.Get("Upgrade") != "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return r.Method == "GET"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h GET) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
|
|
||||||
raw := &graphql.RawParams{
|
|
||||||
Query: r.URL.Query().Get("query"),
|
|
||||||
OperationName: r.URL.Query().Get("operationName"),
|
|
||||||
}
|
|
||||||
raw.ReadTime.Start = graphql.Now()
|
|
||||||
|
|
||||||
if variables := r.URL.Query().Get("variables"); variables != "" {
|
|
||||||
if err := jsonDecode(strings.NewReader(variables), &raw.Variables); err != nil {
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
writeJsonError(w, "variables could not be decoded")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if extensions := r.URL.Query().Get("extensions"); extensions != "" {
|
|
||||||
if err := jsonDecode(strings.NewReader(extensions), &raw.Extensions); err != nil {
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
writeJsonError(w, "extensions could not be decoded")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
raw.ReadTime.End = graphql.Now()
|
|
||||||
|
|
||||||
rc, err := exec.CreateOperationContext(r.Context(), raw)
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(statusFor(err))
|
|
||||||
resp := exec.DispatchError(graphql.WithOperationContext(r.Context(), rc), err)
|
|
||||||
writeJson(w, resp)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
op := rc.Doc.Operations.ForName(rc.OperationName)
|
|
||||||
if op.Operation != ast.Query {
|
|
||||||
w.WriteHeader(http.StatusNotAcceptable)
|
|
||||||
writeJsonError(w, "GET requests only allow query operations")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
responses, ctx := exec.DispatchOperation(r.Context(), rc)
|
|
||||||
writeJson(w, responses(ctx))
|
|
||||||
}
|
|
||||||
|
|
||||||
func jsonDecode(r io.Reader, val interface{}) error {
|
|
||||||
dec := json.NewDecoder(r)
|
|
||||||
dec.UseNumber()
|
|
||||||
return dec.Decode(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
func statusFor(errs gqlerror.List) int {
|
|
||||||
switch errcode.GetErrorKind(errs) {
|
|
||||||
case errcode.KindProtocol:
|
|
||||||
return http.StatusUnprocessableEntity
|
|
||||||
default:
|
|
||||||
return http.StatusOK
|
|
||||||
}
|
|
||||||
}
|
|
||||||
53
vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_post.go
generated
vendored
53
vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_post.go
generated
vendored
@@ -1,53 +0,0 @@
|
|||||||
package transport
|
|
||||||
|
|
||||||
import (
|
|
||||||
"mime"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/graphql"
|
|
||||||
)
|
|
||||||
|
|
||||||
// POST implements the POST side of the default HTTP transport
|
|
||||||
// defined in https://github.com/APIs-guru/graphql-over-http#post
|
|
||||||
type POST struct{}
|
|
||||||
|
|
||||||
var _ graphql.Transport = POST{}
|
|
||||||
|
|
||||||
func (h POST) Supports(r *http.Request) bool {
|
|
||||||
if r.Header.Get("Upgrade") != "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
mediaType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return r.Method == "POST" && mediaType == "application/json"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h POST) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
|
|
||||||
var params *graphql.RawParams
|
|
||||||
start := graphql.Now()
|
|
||||||
if err := jsonDecode(r.Body, ¶ms); err != nil {
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
writeJsonErrorf(w, "json body could not be decoded: "+err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
params.ReadTime = graphql.TraceTiming{
|
|
||||||
Start: start,
|
|
||||||
End: graphql.Now(),
|
|
||||||
}
|
|
||||||
|
|
||||||
rc, err := exec.CreateOperationContext(r.Context(), params)
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(statusFor(err))
|
|
||||||
resp := exec.DispatchError(graphql.WithOperationContext(r.Context(), rc), err)
|
|
||||||
writeJson(w, resp)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
responses, ctx := exec.DispatchOperation(r.Context(), rc)
|
|
||||||
writeJson(w, responses(ctx))
|
|
||||||
}
|
|
||||||
26
vendor/github.com/99designs/gqlgen/graphql/handler/transport/options.go
generated
vendored
26
vendor/github.com/99designs/gqlgen/graphql/handler/transport/options.go
generated
vendored
@@ -1,26 +0,0 @@
|
|||||||
package transport
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/graphql"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Options responds to http OPTIONS and HEAD requests
|
|
||||||
type Options struct{}
|
|
||||||
|
|
||||||
var _ graphql.Transport = Options{}
|
|
||||||
|
|
||||||
func (o Options) Supports(r *http.Request) bool {
|
|
||||||
return r.Method == "HEAD" || r.Method == "OPTIONS"
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o Options) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) {
|
|
||||||
switch r.Method {
|
|
||||||
case http.MethodOptions:
|
|
||||||
w.Header().Set("Allow", "OPTIONS, GET, POST")
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
case http.MethodHead:
|
|
||||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
25
vendor/github.com/99designs/gqlgen/graphql/handler/transport/reader.go
generated
vendored
25
vendor/github.com/99designs/gqlgen/graphql/handler/transport/reader.go
generated
vendored
@@ -1,25 +0,0 @@
|
|||||||
package transport
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
type bytesReader struct {
|
|
||||||
s *[]byte
|
|
||||||
i int64 // current reading index
|
|
||||||
prevRune int // index of previous rune; or < 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *bytesReader) Read(b []byte) (n int, err error) {
|
|
||||||
if r.s == nil {
|
|
||||||
return 0, errors.New("byte slice pointer is nil")
|
|
||||||
}
|
|
||||||
if r.i >= int64(len(*r.s)) {
|
|
||||||
return 0, io.EOF
|
|
||||||
}
|
|
||||||
r.prevRune = -1
|
|
||||||
n = copy(b, (*r.s)[r.i:])
|
|
||||||
r.i += int64(n)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
30
vendor/github.com/99designs/gqlgen/graphql/handler/transport/util.go
generated
vendored
30
vendor/github.com/99designs/gqlgen/graphql/handler/transport/util.go
generated
vendored
@@ -1,30 +0,0 @@
|
|||||||
package transport
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/graphql"
|
|
||||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
|
||||||
)
|
|
||||||
|
|
||||||
func writeJson(w io.Writer, response *graphql.Response) {
|
|
||||||
b, err := json.Marshal(response)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
w.Write(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeJsonError(w io.Writer, msg string) {
|
|
||||||
writeJson(w, &graphql.Response{Errors: gqlerror.List{{Message: msg}}})
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeJsonErrorf(w io.Writer, format string, args ...interface{}) {
|
|
||||||
writeJson(w, &graphql.Response{Errors: gqlerror.List{{Message: fmt.Sprintf(format, args...)}}})
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeJsonGraphqlError(w io.Writer, err ...*gqlerror.Error) {
|
|
||||||
writeJson(w, &graphql.Response{Errors: err})
|
|
||||||
}
|
|
||||||
415
vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket.go
generated
vendored
415
vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket.go
generated
vendored
@@ -1,415 +0,0 @@
|
|||||||
package transport
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/graphql"
|
|
||||||
"github.com/99designs/gqlgen/graphql/errcode"
|
|
||||||
"github.com/gorilla/websocket"
|
|
||||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
|
||||||
)
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
return r.Header.Get("Upgrade") != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t Websocket) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) {
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
|
|
||||||
if !conn.init() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
|
||||||
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 m.t {
|
|
||||||
case initMessageType:
|
|
||||||
if len(m.payload) > 0 {
|
|
||||||
c.initPayload = make(InitPayload)
|
|
||||||
err := json.Unmarshal(m.payload, &c.initPayload)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.InitFunc != nil {
|
|
||||||
ctx, err := c.InitFunc(c.ctx, c.initPayload)
|
|
||||||
if err != nil {
|
|
||||||
c.sendConnectionError(err.Error())
|
|
||||||
c.close(websocket.CloseNormalClosure, "terminated")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
c.ctx = ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
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", m.t)
|
|
||||||
c.close(websocket.CloseProtocolError, "unexpected message")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *wsConnection) write(msg *message) {
|
|
||||||
c.mu.Lock()
|
|
||||||
c.handlePossibleError(c.me.Send(msg))
|
|
||||||
c.mu.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *wsConnection) run() {
|
|
||||||
// We create a cancellation that will shutdown the keep-alive when we leave
|
|
||||||
// this function.
|
|
||||||
ctx, cancel := context.WithCancel(c.ctx)
|
|
||||||
defer func() {
|
|
||||||
cancel()
|
|
||||||
c.close(websocket.CloseAbnormalClosure, "unexpected closure")
|
|
||||||
}()
|
|
||||||
|
|
||||||
// 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()
|
|
||||||
|
|
||||||
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()
|
|
||||||
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 m.t {
|
|
||||||
case startMessageType:
|
|
||||||
c.subscribe(start, &m)
|
|
||||||
case stopMessageType:
|
|
||||||
c.mu.Lock()
|
|
||||||
closer := c.active[m.id]
|
|
||||||
c.mu.Unlock()
|
|
||||||
if closer != nil {
|
|
||||||
closer()
|
|
||||||
}
|
|
||||||
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", m.t)
|
|
||||||
c.close(websocket.CloseProtocolError, "unexpected message")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *wsConnection) keepAlive(ctx context.Context) {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
c.keepAliveTicker.Stop()
|
|
||||||
return
|
|
||||||
case <-c.keepAliveTicker.C:
|
|
||||||
c.write(&message{t: keepAliveMessageType})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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(msg.payload), ¶ms); err != nil {
|
|
||||||
c.sendError(msg.id, &gqlerror.Error{Message: "invalid json"})
|
|
||||||
c.complete(msg.id)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
params.ReadTime = graphql.TraceTiming{
|
|
||||||
Start: start,
|
|
||||||
End: graphql.Now(),
|
|
||||||
}
|
|
||||||
|
|
||||||
rc, err := c.exec.CreateOperationContext(ctx, params)
|
|
||||||
if err != nil {
|
|
||||||
resp := c.exec.DispatchError(graphql.WithOperationContext(ctx, rc), err)
|
|
||||||
switch errcode.GetErrorKind(err) {
|
|
||||||
case errcode.KindProtocol:
|
|
||||||
c.sendError(msg.id, resp.Errors...)
|
|
||||||
default:
|
|
||||||
c.sendResponse(msg.id, &graphql.Response{Errors: err})
|
|
||||||
}
|
|
||||||
|
|
||||||
c.complete(msg.id)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = graphql.WithOperationContext(ctx, rc)
|
|
||||||
|
|
||||||
if c.initPayload != nil {
|
|
||||||
ctx = withInitPayload(ctx, c.initPayload)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
|
||||||
c.mu.Lock()
|
|
||||||
c.active[msg.id] = cancel
|
|
||||||
c.mu.Unlock()
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
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)
|
|
||||||
if response == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
c.sendResponse(msg.id, response)
|
|
||||||
}
|
|
||||||
c.complete(msg.id)
|
|
||||||
|
|
||||||
c.mu.Lock()
|
|
||||||
delete(c.active, msg.id)
|
|
||||||
c.mu.Unlock()
|
|
||||||
cancel()
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *wsConnection) sendResponse(id string, response *graphql.Response) {
|
|
||||||
b, err := json.Marshal(response)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
c.write(&message{
|
|
||||||
payload: b,
|
|
||||||
id: id,
|
|
||||||
t: dataMessageType,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *wsConnection) complete(id string) {
|
|
||||||
c.write(&message{id: id, t: completeMessageType})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *wsConnection) sendError(id string, errors ...*gqlerror.Error) {
|
|
||||||
errs := make([]error, len(errors))
|
|
||||||
for i, err := range errors {
|
|
||||||
errs[i] = err
|
|
||||||
}
|
|
||||||
b, err := json.Marshal(errs)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
c.write(&message{t: errorMessageType, id: id, payload: b})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *wsConnection) sendConnectionError(format string, args ...interface{}) {
|
|
||||||
b, err := json.Marshal(&gqlerror.Error{Message: fmt.Sprintf(format, args...)})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.write(&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
22
vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket_close_reason.go
generated
vendored
@@ -1,22 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
@@ -1,149 +0,0 @@
|
|||||||
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
171
vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket_graphqlws.go
generated
vendored
@@ -1,171 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
57
vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket_init.go
generated
vendored
57
vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket_init.go
generated
vendored
@@ -1,57 +0,0 @@
|
|||||||
package transport
|
|
||||||
|
|
||||||
import "context"
|
|
||||||
|
|
||||||
type key string
|
|
||||||
|
|
||||||
const (
|
|
||||||
initpayload key = "ws_initpayload_context"
|
|
||||||
)
|
|
||||||
|
|
||||||
// InitPayload is a structure that is parsed from the websocket init message payload. TO use
|
|
||||||
// request headers for non-websocket, instead wrap the graphql handler in a middleware.
|
|
||||||
type InitPayload map[string]interface{}
|
|
||||||
|
|
||||||
// GetString safely gets a string value from the payload. It returns an empty string if the
|
|
||||||
// payload is nil or the value isn't set.
|
|
||||||
func (p InitPayload) GetString(key string) string {
|
|
||||||
if p == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if value, ok := p[key]; ok {
|
|
||||||
res, _ := value.(string)
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// Authorization is a short hand for getting the Authorization header from the
|
|
||||||
// payload.
|
|
||||||
func (p InitPayload) Authorization() string {
|
|
||||||
if value := p.GetString("Authorization"); value != "" {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
if value := p.GetString("authorization"); value != "" {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func withInitPayload(ctx context.Context, payload InitPayload) context.Context {
|
|
||||||
return context.WithValue(ctx, initpayload, payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetInitPayload gets a map of the data sent with the connection_init message, which is used by
|
|
||||||
// graphql clients as a stand-in for HTTP headers.
|
|
||||||
func GetInitPayload(ctx context.Context) InitPayload {
|
|
||||||
payload, ok := ctx.Value(initpayload).(InitPayload)
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return payload
|
|
||||||
}
|
|
||||||
116
vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket_subprotocol.go
generated
vendored
116
vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket_subprotocol.go
generated
vendored
@@ -1,116 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
58
vendor/github.com/99designs/gqlgen/graphql/id.go
generated
vendored
58
vendor/github.com/99designs/gqlgen/graphql/id.go
generated
vendored
@@ -1,58 +0,0 @@
|
|||||||
package graphql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
func MarshalID(s string) Marshaler {
|
|
||||||
return MarshalString(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func UnmarshalID(v interface{}) (string, error) {
|
|
||||||
switch v := v.(type) {
|
|
||||||
case string:
|
|
||||||
return v, nil
|
|
||||||
case json.Number:
|
|
||||||
return string(v), nil
|
|
||||||
case int:
|
|
||||||
return strconv.Itoa(v), nil
|
|
||||||
case int64:
|
|
||||||
return strconv.FormatInt(v, 10), nil
|
|
||||||
case float64:
|
|
||||||
return fmt.Sprintf("%f", v), nil
|
|
||||||
case bool:
|
|
||||||
if v {
|
|
||||||
return "true", nil
|
|
||||||
} else {
|
|
||||||
return "false", nil
|
|
||||||
}
|
|
||||||
case nil:
|
|
||||||
return "null", nil
|
|
||||||
default:
|
|
||||||
return "", fmt.Errorf("%T is not a string", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func MarshalIntID(i int) Marshaler {
|
|
||||||
return WriterFunc(func(w io.Writer) {
|
|
||||||
writeQuotedString(w, strconv.Itoa(i))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func UnmarshalIntID(v interface{}) (int, error) {
|
|
||||||
switch v := v.(type) {
|
|
||||||
case string:
|
|
||||||
return strconv.Atoi(v)
|
|
||||||
case int:
|
|
||||||
return v, nil
|
|
||||||
case int64:
|
|
||||||
return int(v), nil
|
|
||||||
case json.Number:
|
|
||||||
return strconv.Atoi(string(v))
|
|
||||||
default:
|
|
||||||
return 0, fmt.Errorf("%T is not an int", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
79
vendor/github.com/99designs/gqlgen/graphql/int.go
generated
vendored
79
vendor/github.com/99designs/gqlgen/graphql/int.go
generated
vendored
@@ -1,79 +0,0 @@
|
|||||||
package graphql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
func MarshalInt(i int) Marshaler {
|
|
||||||
return WriterFunc(func(w io.Writer) {
|
|
||||||
io.WriteString(w, strconv.Itoa(i))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func UnmarshalInt(v interface{}) (int, error) {
|
|
||||||
switch v := v.(type) {
|
|
||||||
case string:
|
|
||||||
return strconv.Atoi(v)
|
|
||||||
case int:
|
|
||||||
return v, nil
|
|
||||||
case int64:
|
|
||||||
return int(v), nil
|
|
||||||
case json.Number:
|
|
||||||
return strconv.Atoi(string(v))
|
|
||||||
default:
|
|
||||||
return 0, fmt.Errorf("%T is not an int", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func MarshalInt64(i int64) Marshaler {
|
|
||||||
return WriterFunc(func(w io.Writer) {
|
|
||||||
io.WriteString(w, strconv.FormatInt(i, 10))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func UnmarshalInt64(v interface{}) (int64, error) {
|
|
||||||
switch v := v.(type) {
|
|
||||||
case string:
|
|
||||||
return strconv.ParseInt(v, 10, 64)
|
|
||||||
case int:
|
|
||||||
return int64(v), nil
|
|
||||||
case int64:
|
|
||||||
return v, nil
|
|
||||||
case json.Number:
|
|
||||||
return strconv.ParseInt(string(v), 10, 64)
|
|
||||||
default:
|
|
||||||
return 0, fmt.Errorf("%T is not an int", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func MarshalInt32(i int32) Marshaler {
|
|
||||||
return WriterFunc(func(w io.Writer) {
|
|
||||||
io.WriteString(w, strconv.FormatInt(int64(i), 10))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func UnmarshalInt32(v interface{}) (int32, error) {
|
|
||||||
switch v := v.(type) {
|
|
||||||
case string:
|
|
||||||
iv, err := strconv.ParseInt(v, 10, 32)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return int32(iv), nil
|
|
||||||
case int:
|
|
||||||
return int32(v), nil
|
|
||||||
case int64:
|
|
||||||
return int32(v), nil
|
|
||||||
case json.Number:
|
|
||||||
iv, err := strconv.ParseInt(string(v), 10, 32)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return int32(iv), nil
|
|
||||||
default:
|
|
||||||
return 0, fmt.Errorf("%T is not an int", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
101
vendor/github.com/99designs/gqlgen/graphql/introspection/introspection.go
generated
vendored
101
vendor/github.com/99designs/gqlgen/graphql/introspection/introspection.go
generated
vendored
@@ -1,101 +0,0 @@
|
|||||||
// introspection implements the spec defined in https://github.com/facebook/graphql/blob/master/spec/Section%204%20--%20Introspection.md#schema-introspection
|
|
||||||
package introspection
|
|
||||||
|
|
||||||
import "github.com/vektah/gqlparser/v2/ast"
|
|
||||||
|
|
||||||
type (
|
|
||||||
Directive struct {
|
|
||||||
Name string
|
|
||||||
description string
|
|
||||||
Locations []string
|
|
||||||
Args []InputValue
|
|
||||||
IsRepeatable bool
|
|
||||||
}
|
|
||||||
|
|
||||||
EnumValue struct {
|
|
||||||
Name string
|
|
||||||
description string
|
|
||||||
deprecation *ast.Directive
|
|
||||||
}
|
|
||||||
|
|
||||||
Field struct {
|
|
||||||
Name string
|
|
||||||
description string
|
|
||||||
Type *Type
|
|
||||||
Args []InputValue
|
|
||||||
deprecation *ast.Directive
|
|
||||||
}
|
|
||||||
|
|
||||||
InputValue struct {
|
|
||||||
Name string
|
|
||||||
description string
|
|
||||||
DefaultValue *string
|
|
||||||
Type *Type
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *EnumValue) DeprecationReason() *string {
|
|
||||||
if f.deprecation == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
reason := f.deprecation.Arguments.ForName("reason")
|
|
||||||
if reason == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *Field) DeprecationReason() *string {
|
|
||||||
if f.deprecation == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
reason := f.deprecation.Arguments.ForName("reason")
|
|
||||||
if reason == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
106
vendor/github.com/99designs/gqlgen/graphql/introspection/query.go
generated
vendored
106
vendor/github.com/99designs/gqlgen/graphql/introspection/query.go
generated
vendored
@@ -1,106 +0,0 @@
|
|||||||
package introspection
|
|
||||||
|
|
||||||
// Query is the query generated by graphiql to determine type information
|
|
||||||
const Query = `
|
|
||||||
query IntrospectionQuery {
|
|
||||||
__schema {
|
|
||||||
description
|
|
||||||
queryType {
|
|
||||||
name
|
|
||||||
}
|
|
||||||
mutationType {
|
|
||||||
name
|
|
||||||
}
|
|
||||||
subscriptionType {
|
|
||||||
name
|
|
||||||
}
|
|
||||||
types {
|
|
||||||
...FullType
|
|
||||||
}
|
|
||||||
directives {
|
|
||||||
name
|
|
||||||
description
|
|
||||||
locations
|
|
||||||
args {
|
|
||||||
...InputValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fragment FullType on __Type {
|
|
||||||
kind
|
|
||||||
name
|
|
||||||
description
|
|
||||||
specifiedByURL
|
|
||||||
fields(includeDeprecated: true) {
|
|
||||||
name
|
|
||||||
description
|
|
||||||
args {
|
|
||||||
...InputValue
|
|
||||||
}
|
|
||||||
type {
|
|
||||||
...TypeRef
|
|
||||||
}
|
|
||||||
isDeprecated
|
|
||||||
deprecationReason
|
|
||||||
}
|
|
||||||
inputFields {
|
|
||||||
...InputValue
|
|
||||||
}
|
|
||||||
interfaces {
|
|
||||||
...TypeRef
|
|
||||||
}
|
|
||||||
enumValues(includeDeprecated: true) {
|
|
||||||
name
|
|
||||||
description
|
|
||||||
isDeprecated
|
|
||||||
deprecationReason
|
|
||||||
}
|
|
||||||
possibleTypes {
|
|
||||||
...TypeRef
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fragment InputValue on __InputValue {
|
|
||||||
name
|
|
||||||
description
|
|
||||||
type {
|
|
||||||
...TypeRef
|
|
||||||
}
|
|
||||||
defaultValue
|
|
||||||
}
|
|
||||||
|
|
||||||
fragment TypeRef on __Type {
|
|
||||||
kind
|
|
||||||
name
|
|
||||||
ofType {
|
|
||||||
kind
|
|
||||||
name
|
|
||||||
ofType {
|
|
||||||
kind
|
|
||||||
name
|
|
||||||
ofType {
|
|
||||||
kind
|
|
||||||
name
|
|
||||||
ofType {
|
|
||||||
kind
|
|
||||||
name
|
|
||||||
ofType {
|
|
||||||
kind
|
|
||||||
name
|
|
||||||
ofType {
|
|
||||||
kind
|
|
||||||
name
|
|
||||||
ofType {
|
|
||||||
kind
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
93
vendor/github.com/99designs/gqlgen/graphql/introspection/schema.go
generated
vendored
93
vendor/github.com/99designs/gqlgen/graphql/introspection/schema.go
generated
vendored
@@ -1,93 +0,0 @@
|
|||||||
package introspection
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/vektah/gqlparser/v2/ast"
|
|
||||||
)
|
|
||||||
|
|
||||||
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 {
|
|
||||||
typeIndex := map[string]Type{}
|
|
||||||
typeNames := make([]string, 0, len(s.schema.Types))
|
|
||||||
for _, typ := range s.schema.Types {
|
|
||||||
if strings.HasPrefix(typ.Name, "__") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Schema) QueryType() *Type {
|
|
||||||
return WrapTypeFromDef(s.schema, s.schema.Query)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Schema) MutationType() *Type {
|
|
||||||
return WrapTypeFromDef(s.schema, s.schema.Mutation)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Schema) SubscriptionType() *Type {
|
|
||||||
return WrapTypeFromDef(s.schema, s.schema.Subscription)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Schema) Directives() []Directive {
|
|
||||||
dIndex := map[string]Directive{}
|
|
||||||
dNames := make([]string, 0, len(s.schema.Directives))
|
|
||||||
|
|
||||||
for _, d := range s.schema.Directives {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Schema) directiveFromDef(d *ast.DirectiveDefinition) Directive {
|
|
||||||
locs := make([]string, len(d.Locations))
|
|
||||||
for i, loc := range d.Locations {
|
|
||||||
locs[i] = string(loc)
|
|
||||||
}
|
|
||||||
|
|
||||||
args := make([]InputValue, len(d.Arguments))
|
|
||||||
for i, arg := range d.Arguments {
|
|
||||||
args[i] = InputValue{
|
|
||||||
Name: arg.Name,
|
|
||||||
description: arg.Description,
|
|
||||||
DefaultValue: defaultValue(arg.DefaultValue),
|
|
||||||
Type: WrapTypeFromType(s.schema, arg.Type),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Directive{
|
|
||||||
Name: d.Name,
|
|
||||||
description: d.Description,
|
|
||||||
Locations: locs,
|
|
||||||
Args: args,
|
|
||||||
IsRepeatable: d.IsRepeatable,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
191
vendor/github.com/99designs/gqlgen/graphql/introspection/type.go
generated
vendored
191
vendor/github.com/99designs/gqlgen/graphql/introspection/type.go
generated
vendored
@@ -1,191 +0,0 @@
|
|||||||
package introspection
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/vektah/gqlparser/v2/ast"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Type struct {
|
|
||||||
schema *ast.Schema
|
|
||||||
def *ast.Definition
|
|
||||||
typ *ast.Type
|
|
||||||
}
|
|
||||||
|
|
||||||
func WrapTypeFromDef(s *ast.Schema, def *ast.Definition) *Type {
|
|
||||||
if def == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &Type{schema: s, def: def}
|
|
||||||
}
|
|
||||||
|
|
||||||
func WrapTypeFromType(s *ast.Schema, typ *ast.Type) *Type {
|
|
||||||
if typ == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if !typ.NonNull && typ.NamedType != "" {
|
|
||||||
return &Type{schema: s, def: s.Types[typ.NamedType]}
|
|
||||||
}
|
|
||||||
return &Type{schema: s, typ: typ}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Type) Kind() string {
|
|
||||||
if t.typ != nil {
|
|
||||||
if t.typ.NonNull {
|
|
||||||
return "NON_NULL"
|
|
||||||
}
|
|
||||||
|
|
||||||
if t.typ.Elem != nil {
|
|
||||||
return "LIST"
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return string(t.def.Kind)
|
|
||||||
}
|
|
||||||
|
|
||||||
panic("UNKNOWN")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Type) Name() *string {
|
|
||||||
if t.def == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &t.def.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Type) Description() *string {
|
|
||||||
if t.def == nil || t.def.Description == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &t.def.Description
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Type) Fields(includeDeprecated bool) []Field {
|
|
||||||
if t.def == nil || (t.def.Kind != ast.Object && t.def.Kind != ast.Interface) {
|
|
||||||
return []Field{}
|
|
||||||
}
|
|
||||||
fields := []Field{}
|
|
||||||
for _, f := range t.def.Fields {
|
|
||||||
if strings.HasPrefix(f.Name, "__") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if !includeDeprecated && f.Directives.ForName("deprecated") != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var args []InputValue
|
|
||||||
for _, arg := range f.Arguments {
|
|
||||||
args = append(args, InputValue{
|
|
||||||
Type: WrapTypeFromType(t.schema, arg.Type),
|
|
||||||
Name: arg.Name,
|
|
||||||
description: arg.Description,
|
|
||||||
DefaultValue: defaultValue(arg.DefaultValue),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fields = append(fields, Field{
|
|
||||||
Name: f.Name,
|
|
||||||
description: f.Description,
|
|
||||||
Args: args,
|
|
||||||
Type: WrapTypeFromType(t.schema, f.Type),
|
|
||||||
deprecation: f.Directives.ForName("deprecated"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return fields
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Type) InputFields() []InputValue {
|
|
||||||
if t.def == nil || t.def.Kind != ast.InputObject {
|
|
||||||
return []InputValue{}
|
|
||||||
}
|
|
||||||
|
|
||||||
res := []InputValue{}
|
|
||||||
for _, f := range t.def.Fields {
|
|
||||||
res = append(res, InputValue{
|
|
||||||
Name: f.Name,
|
|
||||||
description: f.Description,
|
|
||||||
Type: WrapTypeFromType(t.schema, f.Type),
|
|
||||||
DefaultValue: defaultValue(f.DefaultValue),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func defaultValue(value *ast.Value) *string {
|
|
||||||
if value == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
val := value.String()
|
|
||||||
return &val
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Type) Interfaces() []Type {
|
|
||||||
if t.def == nil || t.def.Kind != ast.Object {
|
|
||||||
return []Type{}
|
|
||||||
}
|
|
||||||
|
|
||||||
res := []Type{}
|
|
||||||
for _, intf := range t.def.Interfaces {
|
|
||||||
res = append(res, *WrapTypeFromDef(t.schema, t.schema.Types[intf]))
|
|
||||||
}
|
|
||||||
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Type) PossibleTypes() []Type {
|
|
||||||
if t.def == nil || (t.def.Kind != ast.Interface && t.def.Kind != ast.Union) {
|
|
||||||
return []Type{}
|
|
||||||
}
|
|
||||||
|
|
||||||
res := []Type{}
|
|
||||||
for _, pt := range t.schema.GetPossibleTypes(t.def) {
|
|
||||||
res = append(res, *WrapTypeFromDef(t.schema, pt))
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Type) EnumValues(includeDeprecated bool) []EnumValue {
|
|
||||||
if t.def == nil || t.def.Kind != ast.Enum {
|
|
||||||
return []EnumValue{}
|
|
||||||
}
|
|
||||||
|
|
||||||
res := []EnumValue{}
|
|
||||||
for _, val := range t.def.EnumValues {
|
|
||||||
if !includeDeprecated && val.Directives.ForName("deprecated") != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
res = append(res, EnumValue{
|
|
||||||
Name: val.Name,
|
|
||||||
description: val.Description,
|
|
||||||
deprecation: val.Directives.ForName("deprecated"),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Type) OfType() *Type {
|
|
||||||
if t.typ == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if t.typ.NonNull {
|
|
||||||
// fake non null nodes
|
|
||||||
cpy := *t.typ
|
|
||||||
cpy.NonNull = false
|
|
||||||
|
|
||||||
return WrapTypeFromType(t.schema, &cpy)
|
|
||||||
}
|
|
||||||
return WrapTypeFromType(t.schema, t.typ.Elem)
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
93
vendor/github.com/99designs/gqlgen/graphql/jsonw.go
generated
vendored
93
vendor/github.com/99designs/gqlgen/graphql/jsonw.go
generated
vendored
@@ -1,93 +0,0 @@
|
|||||||
package graphql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
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}
|
|
||||||
True = &lit{trueLit}
|
|
||||||
False = &lit{falseLit}
|
|
||||||
)
|
|
||||||
|
|
||||||
type Marshaler interface {
|
|
||||||
MarshalGQL(w io.Writer)
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
writer.Write(openBracket)
|
|
||||||
for i, val := range a {
|
|
||||||
if i != 0 {
|
|
||||||
writer.Write(comma)
|
|
||||||
}
|
|
||||||
val.MarshalGQL(writer)
|
|
||||||
}
|
|
||||||
writer.Write(closeBracket)
|
|
||||||
}
|
|
||||||
|
|
||||||
type lit struct{ b []byte }
|
|
||||||
|
|
||||||
func (l lit) MarshalGQL(w io.Writer) {
|
|
||||||
w.Write(l.b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l lit) MarshalGQLContext(ctx context.Context, w io.Writer) error {
|
|
||||||
w.Write(l.b)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
24
vendor/github.com/99designs/gqlgen/graphql/map.go
generated
vendored
24
vendor/github.com/99designs/gqlgen/graphql/map.go
generated
vendored
@@ -1,24 +0,0 @@
|
|||||||
package graphql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
func MarshalMap(val map[string]interface{}) Marshaler {
|
|
||||||
return WriterFunc(func(w io.Writer) {
|
|
||||||
err := json.NewEncoder(w).Encode(val)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func UnmarshalMap(v interface{}) (map[string]interface{}, error) {
|
|
||||||
if m, ok := v.(map[string]interface{}); ok {
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, fmt.Errorf("%T is not a map", v)
|
|
||||||
}
|
|
||||||
16
vendor/github.com/99designs/gqlgen/graphql/oneshot.go
generated
vendored
16
vendor/github.com/99designs/gqlgen/graphql/oneshot.go
generated
vendored
@@ -1,16 +0,0 @@
|
|||||||
package graphql
|
|
||||||
|
|
||||||
import "context"
|
|
||||||
|
|
||||||
func OneShot(resp *Response) ResponseHandler {
|
|
||||||
var oneshot bool
|
|
||||||
|
|
||||||
return func(context context.Context) *Response {
|
|
||||||
if oneshot {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
oneshot = true
|
|
||||||
|
|
||||||
return resp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
73
vendor/github.com/99designs/gqlgen/graphql/playground/playground.go
generated
vendored
73
vendor/github.com/99designs/gqlgen/graphql/playground/playground.go
generated
vendored
@@ -1,73 +0,0 @@
|
|||||||
package playground
|
|
||||||
|
|
||||||
import (
|
|
||||||
"html/template"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
var page = template.Must(template.New("graphiql").Parse(`<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<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>
|
|
||||||
`))
|
|
||||||
|
|
||||||
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.5.16",
|
|
||||||
"cssSRI": "sha256-HADQowUuFum02+Ckkv5Yu5ygRoLllHZqg0TFZXY7NHI=",
|
|
||||||
"jsSRI": "sha256-uHp12yvpXC4PC9+6JmITxKuLYwjlW9crq9ywPE5Rxco=",
|
|
||||||
"reactSRI": "sha256-Ipu/TQ50iCCVZBUsZyNJfxrDk0E2yhaEIz0vqI+kFG8=",
|
|
||||||
"reactDOMSRI": "sha256-nbMykgB6tsOFJ7OdVmPpdqMFVk4ZsqWocT6issAPUF0=",
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
20
vendor/github.com/99designs/gqlgen/graphql/recovery.go
generated
vendored
20
vendor/github.com/99designs/gqlgen/graphql/recovery.go
generated
vendored
@@ -1,20 +0,0 @@
|
|||||||
package graphql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"runtime/debug"
|
|
||||||
|
|
||||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
|
||||||
)
|
|
||||||
|
|
||||||
type RecoverFunc func(ctx context.Context, err interface{}) (userMessage error)
|
|
||||||
|
|
||||||
func DefaultRecover(ctx context.Context, err interface{}) error {
|
|
||||||
fmt.Fprintln(os.Stderr, err)
|
|
||||||
fmt.Fprintln(os.Stderr)
|
|
||||||
debug.PrintStack()
|
|
||||||
|
|
||||||
return gqlerror.Errorf("internal system error")
|
|
||||||
}
|
|
||||||
24
vendor/github.com/99designs/gqlgen/graphql/response.go
generated
vendored
24
vendor/github.com/99designs/gqlgen/graphql/response.go
generated
vendored
@@ -1,24 +0,0 @@
|
|||||||
package graphql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Errors are intentionally serialized first based on the advice in
|
|
||||||
// https://github.com/facebook/graphql/commit/7b40390d48680b15cb93e02d46ac5eb249689876#diff-757cea6edf0288677a9eea4cfc801d87R107
|
|
||||||
// and https://github.com/facebook/graphql/pull/384
|
|
||||||
type Response struct {
|
|
||||||
Errors gqlerror.List `json:"errors,omitempty"`
|
|
||||||
Data json.RawMessage `json:"data"`
|
|
||||||
Extensions map[string]interface{} `json:"extensions,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func ErrorResponse(ctx context.Context, messagef string, args ...interface{}) *Response {
|
|
||||||
return &Response{
|
|
||||||
Errors: gqlerror.List{{Message: fmt.Sprintf(messagef, args...)}},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
7
vendor/github.com/99designs/gqlgen/graphql/root.go
generated
vendored
7
vendor/github.com/99designs/gqlgen/graphql/root.go
generated
vendored
@@ -1,7 +0,0 @@
|
|||||||
package graphql
|
|
||||||
|
|
||||||
type Query struct{}
|
|
||||||
|
|
||||||
type Mutation struct{}
|
|
||||||
|
|
||||||
type Subscription struct{}
|
|
||||||
60
vendor/github.com/99designs/gqlgen/graphql/stats.go
generated
vendored
60
vendor/github.com/99designs/gqlgen/graphql/stats.go
generated
vendored
@@ -1,60 +0,0 @@
|
|||||||
package graphql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Stats struct {
|
|
||||||
OperationStart time.Time
|
|
||||||
Read TraceTiming
|
|
||||||
Parsing TraceTiming
|
|
||||||
Validation TraceTiming
|
|
||||||
|
|
||||||
// Stats collected by handler extensions. Dont use directly, the extension should provide a type safe way to
|
|
||||||
// access this.
|
|
||||||
extension map[string]interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
type TraceTiming struct {
|
|
||||||
Start time.Time
|
|
||||||
End time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
var ctxTraceStart key = "trace_start"
|
|
||||||
|
|
||||||
// StartOperationTrace captures the current time and stores it in context. This will eventually be added to request
|
|
||||||
// context but we want to grab it as soon as possible. For transports that can only handle a single graphql query
|
|
||||||
// per http requests you dont need to call this at all, the server will do it for you. For transports that handle
|
|
||||||
// multiple (eg batching, subscriptions) this should be called before decoding each request.
|
|
||||||
func StartOperationTrace(ctx context.Context) context.Context {
|
|
||||||
return context.WithValue(ctx, ctxTraceStart, Now())
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetStartTime should only be called by the handler package, it will be set into request context
|
|
||||||
// as Stats.Start
|
|
||||||
func GetStartTime(ctx context.Context) time.Time {
|
|
||||||
t, ok := ctx.Value(ctxTraceStart).(time.Time)
|
|
||||||
if !ok {
|
|
||||||
panic(fmt.Sprintf("missing start time: %T", ctx.Value(ctxTraceStart)))
|
|
||||||
}
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Stats) SetExtension(name string, data interface{}) {
|
|
||||||
if c.extension == nil {
|
|
||||||
c.extension = map[string]interface{}{}
|
|
||||||
}
|
|
||||||
c.extension[name] = data
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Stats) GetExtension(name string) interface{} {
|
|
||||||
if c.extension == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return c.extension[name]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now is time.Now, except in tests. Then it can be whatever you want it to be.
|
|
||||||
var Now = time.Now
|
|
||||||
70
vendor/github.com/99designs/gqlgen/graphql/string.go
generated
vendored
70
vendor/github.com/99designs/gqlgen/graphql/string.go
generated
vendored
@@ -1,70 +0,0 @@
|
|||||||
package graphql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
const encodeHex = "0123456789ABCDEF"
|
|
||||||
|
|
||||||
func MarshalString(s string) Marshaler {
|
|
||||||
return WriterFunc(func(w io.Writer) {
|
|
||||||
writeQuotedString(w, s)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeQuotedString(w io.Writer, s string) {
|
|
||||||
start := 0
|
|
||||||
io.WriteString(w, `"`)
|
|
||||||
|
|
||||||
for i, c := range s {
|
|
||||||
if c < 0x20 || c == '\\' || c == '"' {
|
|
||||||
io.WriteString(w, s[start:i])
|
|
||||||
|
|
||||||
switch c {
|
|
||||||
case '\t':
|
|
||||||
io.WriteString(w, `\t`)
|
|
||||||
case '\r':
|
|
||||||
io.WriteString(w, `\r`)
|
|
||||||
case '\n':
|
|
||||||
io.WriteString(w, `\n`)
|
|
||||||
case '\\':
|
|
||||||
io.WriteString(w, `\\`)
|
|
||||||
case '"':
|
|
||||||
io.WriteString(w, `\"`)
|
|
||||||
default:
|
|
||||||
io.WriteString(w, `\u00`)
|
|
||||||
w.Write([]byte{encodeHex[c>>4], encodeHex[c&0xf]})
|
|
||||||
}
|
|
||||||
|
|
||||||
start = i + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
io.WriteString(w, s[start:])
|
|
||||||
io.WriteString(w, `"`)
|
|
||||||
}
|
|
||||||
|
|
||||||
func UnmarshalString(v interface{}) (string, error) {
|
|
||||||
switch v := v.(type) {
|
|
||||||
case string:
|
|
||||||
return v, nil
|
|
||||||
case int:
|
|
||||||
return strconv.Itoa(v), nil
|
|
||||||
case int64:
|
|
||||||
return strconv.FormatInt(v, 10), nil
|
|
||||||
case float64:
|
|
||||||
return fmt.Sprintf("%f", v), nil
|
|
||||||
case bool:
|
|
||||||
if v {
|
|
||||||
return "true", nil
|
|
||||||
} else {
|
|
||||||
return "false", nil
|
|
||||||
}
|
|
||||||
case nil:
|
|
||||||
return "null", nil
|
|
||||||
default:
|
|
||||||
return "", fmt.Errorf("%T is not a string", v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
25
vendor/github.com/99designs/gqlgen/graphql/time.go
generated
vendored
25
vendor/github.com/99designs/gqlgen/graphql/time.go
generated
vendored
@@ -1,25 +0,0 @@
|
|||||||
package graphql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func MarshalTime(t time.Time) Marshaler {
|
|
||||||
if t.IsZero() {
|
|
||||||
return Null
|
|
||||||
}
|
|
||||||
|
|
||||||
return WriterFunc(func(w io.Writer) {
|
|
||||||
io.WriteString(w, strconv.Quote(t.Format(time.RFC3339Nano)))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func UnmarshalTime(v interface{}) (time.Time, error) {
|
|
||||||
if tmpStr, ok := v.(string); ok {
|
|
||||||
return time.Parse(time.RFC3339Nano, tmpStr)
|
|
||||||
}
|
|
||||||
return time.Time{}, errors.New("time should be RFC3339Nano formatted string")
|
|
||||||
}
|
|
||||||
81
vendor/github.com/99designs/gqlgen/graphql/uint.go
generated
vendored
81
vendor/github.com/99designs/gqlgen/graphql/uint.go
generated
vendored
@@ -1,81 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user