Support Go 1.18: Upgrade gqlgen to v0.17.2 (#2443)

* Upgrade gqlgen to v0.17.2

This enables builds on Go 1.18. github.com/vektah/gqlparser is upgraded
to the newest version too.

Getting this to work is a bit of a hazzle. I had to first remove
vendoring from the repository, perform the upgrade and then re-introduce
the vendor directory. I think gqlgens analysis went wrong for some
reason on the upgrade. It would seem a clean-room installation fixed it.

* Bump project to 1.18

* Update all packages, address gqlgenc breaking changes

* Let `go mod tidy` handle the go.mod file

* Upgrade linter to 1.45.2

* Introduce v1.45.2 of the linter

The linter now correctly warns on `strings.Title` because it isn't
unicode-aware. Fix this by using the suggested fix from x/text/cases
to produce unicode-aware strings.

The mapping isn't entirely 1-1 as this new approach has a larger iface:
it spans all of unicode rather than just ASCII. It coincides for ASCII
however, so things should be largely the same.

* Ready ourselves for errchkjson and contextcheck.

* Revert dockerfile golang version changes for now

Co-authored-by: Kermie <kermie@isinthe.house>
Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
This commit is contained in:
SmallCoccinelle
2022-04-02 09:08:14 +02:00
committed by GitHub
parent e5c4241180
commit 45f700d6ea
516 changed files with 43496 additions and 10015 deletions

View File

@@ -36,7 +36,7 @@ jobs:
uses: golangci/golangci-lint-action@v2 uses: golangci/golangci-lint-action@v2
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: v1.42.1 version: v1.45.2
# Optional: working directory, useful for monorepos # Optional: working directory, useful for monorepos
# working-directory: somedir # working-directory: somedir

View File

@@ -18,7 +18,9 @@ linters:
- unused - unused
- varcheck - varcheck
# Linters added by the stash project. # Linters added by the stash project.
# - contextcheck
- dogsled - dogsled
# - errchkjson
- errorlint - errorlint
# - exhaustive # - exhaustive
- exportloopref - exportloopref

View File

@@ -1,6 +1,8 @@
model: model:
package: graphql
filename: ./pkg/scraper/stashbox/graphql/generated_models.go filename: ./pkg/scraper/stashbox/graphql/generated_models.go
client: client:
package: graphql
filename: ./pkg/scraper/stashbox/graphql/generated_client.go filename: ./pkg/scraper/stashbox/graphql/generated_client.go
models: models:
Date: Date:
@@ -11,3 +13,6 @@ endpoint:
url: https://stashdb.org/graphql url: https://stashdb.org/graphql
query: query:
- "./graphql/stash-box/*.graphql" - "./graphql/stash-box/*.graphql"
generate:
clientV2: false
clientInterfaceName: "StashBoxGraphQLClient"

51
go.mod
View File

@@ -1,8 +1,8 @@
module github.com/stashapp/stash module github.com/stashapp/stash
require ( require (
github.com/99designs/gqlgen v0.12.2 github.com/99designs/gqlgen v0.17.2
github.com/Yamashou/gqlgenc v0.0.0-20200902035953-4dbef3551953 github.com/Yamashou/gqlgenc v0.0.6
github.com/anacrolix/dms v1.2.2 github.com/anacrolix/dms v1.2.2
github.com/antchfx/htmlquery v1.2.5-0.20211125074323-810ee8082758 github.com/antchfx/htmlquery v1.2.5-0.20211125074323-810ee8082758
github.com/chromedp/cdproto v0.0.0-20210622022015-fe1827b46b84 github.com/chromedp/cdproto v0.0.0-20210622022015-fe1827b46b84
@@ -16,10 +16,9 @@ require (
github.com/gorilla/securecookie v1.1.1 github.com/gorilla/securecookie v1.1.1
github.com/gorilla/sessions v1.2.0 github.com/gorilla/sessions v1.2.0
github.com/gorilla/websocket v1.4.2 github.com/gorilla/websocket v1.4.2
github.com/h2non/filetype v1.0.8
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
github.com/jmoiron/sqlx v1.3.1 github.com/jmoiron/sqlx v1.3.1
github.com/json-iterator/go v1.1.11 github.com/json-iterator/go v1.1.12
github.com/mattn/go-sqlite3 v1.14.6 github.com/mattn/go-sqlite3 v1.14.6
github.com/natefinch/pie v0.0.0-20170715172608-9a0d72014007 github.com/natefinch/pie v0.0.0-20170715172608-9a0d72014007
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8
@@ -28,20 +27,20 @@ require (
github.com/rs/cors v1.6.0 github.com/rs/cors v1.6.0
github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f
github.com/sirupsen/logrus v1.8.1 github.com/sirupsen/logrus v1.8.1
github.com/spf13/afero v1.6.0 // indirect github.com/spf13/afero v1.8.2 // indirect
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.9.0 github.com/spf13/viper v1.10.1
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
github.com/tidwall/gjson v1.9.3 github.com/tidwall/gjson v1.9.3
github.com/tidwall/pretty v1.2.0 // indirect github.com/tidwall/pretty v1.2.0 // indirect
github.com/vektra/mockery/v2 v2.2.1 github.com/vektra/mockery/v2 v2.10.0
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb
golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9 golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e golang.org/x/sys v0.0.0-20220329152356-43be30ef3008
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
golang.org/x/text v0.3.7 golang.org/x/text v0.3.7
golang.org/x/tools v0.1.5 // indirect golang.org/x/tools v0.1.10 // indirect
gopkg.in/sourcemap.v1 v1.0.5 // indirect gopkg.in/sourcemap.v1 v1.0.5 // indirect
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
) )
@@ -50,19 +49,20 @@ require (
github.com/apenwarr/fixconsole v0.0.0-20191012055117-5a9f6489cc29 github.com/apenwarr/fixconsole v0.0.0-20191012055117-5a9f6489cc29
github.com/go-chi/httplog v0.2.1 github.com/go-chi/httplog v0.2.1
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4
github.com/hashicorp/golang-lru v0.5.4
github.com/kermieisinthehouse/gosx-notifier v0.1.1 github.com/kermieisinthehouse/gosx-notifier v0.1.1
github.com/kermieisinthehouse/systray v1.2.4 github.com/kermieisinthehouse/systray v1.2.4
github.com/lucasb-eyer/go-colorful v1.2.0 github.com/lucasb-eyer/go-colorful v1.2.0
github.com/vearutop/statigz v1.1.6 github.com/vearutop/statigz v1.1.6
github.com/vektah/gqlparser/v2 v2.0.1 github.com/vektah/gqlparser/v2 v2.4.1
) )
require ( require (
github.com/agnivade/levenshtein v1.1.0 // indirect github.com/agnivade/levenshtein v1.1.1 // indirect
github.com/antchfx/xpath v1.2.0 // indirect github.com/antchfx/xpath v1.2.0 // indirect
github.com/apenwarr/w32 v0.0.0-20190407065021-aa00fece76ab // indirect github.com/apenwarr/w32 v0.0.0-20190407065021-aa00fece76ab // indirect
github.com/chromedp/sysutil v1.0.0 // indirect github.com/chromedp/sysutil v1.0.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/go-chi/chi/v5 v5.0.0 // indirect github.com/go-chi/chi/v5 v5.0.0 // indirect
@@ -72,37 +72,34 @@ require (
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-multierror v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.0 // indirect
github.com/hashicorp/golang-lru v0.5.1 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/magiconair/properties v1.8.5 // indirect github.com/magiconair/properties v1.8.6 // indirect
github.com/mailru/easyjson v0.7.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007 // indirect github.com/matryer/moq v0.2.6 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.4.2 // indirect github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
github.com/pelletier/go-toml v1.9.4 // indirect github.com/pelletier/go-toml v1.9.4 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rs/zerolog v1.18.1-0.20200514152719-663cbb4c8469 // indirect github.com/rs/zerolog v1.26.1 // indirect
github.com/russross/blackfriday/v2 v2.0.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
github.com/spf13/cast v1.4.1 // indirect github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/cobra v1.0.0 // indirect github.com/spf13/cobra v1.4.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/stretchr/objx v0.2.0 // indirect github.com/stretchr/objx v0.2.0 // indirect
github.com/subosito/gotenv v1.2.0 // indirect github.com/subosito/gotenv v1.2.0 // indirect
github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/match v1.1.1 // indirect
github.com/urfave/cli/v2 v2.1.1 // indirect github.com/urfave/cli/v2 v2.4.0 // indirect
github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e // indirect
go.uber.org/atomic v1.7.0 // indirect go.uber.org/atomic v1.7.0 // indirect
golang.org/x/mod v0.4.2 // indirect golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/ini.v1 v1.63.2 // indirect gopkg.in/ini.v1 v1.66.4 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
) )

320
go.sum
View File

@@ -3,6 +3,7 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
@@ -15,6 +16,7 @@ cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOY
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
@@ -23,6 +25,10 @@ cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSU
cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM=
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
@@ -31,8 +37,7 @@ cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4g
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY=
cloud.google.com/go/firestore v1.6.0/go.mod h1:afJwI0vaXwAG54kI7A//lP/lSPDkQORQuMkv56TxEPU=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
@@ -43,9 +48,10 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/99designs/gqlgen v0.12.2 h1:aOdpsiCycFtCnAv8CAI1exnKrIDHMqtMzQoXeTziY4o= github.com/99designs/gqlgen v0.17.2 h1:yczvlwMsfcVu/JtejqfrLwXuSP0yZFhmcss3caEvHw8=
github.com/99designs/gqlgen v0.12.2/go.mod h1:7zdGo6ry9u1YBp/qlb2uxSU5Mt2jQKLcBETQiKk+Bxo= github.com/99designs/gqlgen v0.17.2/go.mod h1:K5fzLKwtph+FFgh9j7nFbRUdBKvTcGnsta51fsMTn3o=
github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k= github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k=
github.com/Azure/azure-storage-blob-go v0.13.0/go.mod h1:pA9kNqtjUeQF2zOSu4s//nUdBD+e64lEuc4sVnuOfNs= github.com/Azure/azure-storage-blob-go v0.13.0/go.mod h1:pA9kNqtjUeQF2zOSu4s//nUdBD+e64lEuc4sVnuOfNs=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
@@ -59,17 +65,20 @@ github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBp
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/ClickHouse/clickhouse-go v1.4.3/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI= github.com/ClickHouse/clickhouse-go v1.4.3/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w= github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w=
github.com/Yamashou/gqlgenc v0.0.0-20200902035953-4dbef3551953 h1:+iPJDL28FxZhEdtJ9qykrMt/oDiOvlzTa0zV06nUcFM= github.com/Yamashou/gqlgenc v0.0.6 h1:wfMTtuVSrX2N1z5/ssecxx+E7l1fa0FOq5mwFW47oY4=
github.com/Yamashou/gqlgenc v0.0.0-20200902035953-4dbef3551953/go.mod h1:kaTsk10p2hJWwrB2t7vMsk1lXj9KAHaDYRtJQiB+Ick= github.com/Yamashou/gqlgenc v0.0.6/go.mod h1:WOXjogecRGpD1WKgxnnyHJo0/Dxn44p/LNRoE6mtFQo=
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
github.com/agnivade/levenshtein v1.0.3/go.mod h1:4SFRZbbXWLF4MU1T9Qg0pGgH3Pjs+t6ie5efyrwRJXs=
github.com/agnivade/levenshtein v1.1.0 h1:n6qGwyHG61v3ABce1rPVZklEYRT8NFpCMrpZdBUbYGM=
github.com/agnivade/levenshtein v1.1.0/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= github.com/agnivade/levenshtein v1.1.0/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8=
github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/anacrolix/dms v1.2.2 h1:0mk2/DXNqa5KDDbaLgFPf3oMV6VCGdFNh3d/gt4oafM= github.com/anacrolix/dms v1.2.2 h1:0mk2/DXNqa5KDDbaLgFPf3oMV6VCGdFNh3d/gt4oafM=
github.com/anacrolix/dms v1.2.2/go.mod h1:msPKAoppoNRfrYplJqx63FZ+VipDZ4Xsj3KzIQxyU7k= github.com/anacrolix/dms v1.2.2/go.mod h1:msPKAoppoNRfrYplJqx63FZ+VipDZ4Xsj3KzIQxyU7k=
github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c= github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c=
@@ -95,8 +104,8 @@ github.com/apenwarr/w32 v0.0.0-20190407065021-aa00fece76ab/go.mod h1:nfFtvHn2Hgs
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
@@ -127,10 +136,10 @@ github.com/aws/smithy-go v1.3.1/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAm
github.com/aws/smithy-go v1.4.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= github.com/aws/smithy-go v1.4.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k=
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4= github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/bool64/dev v0.1.41 h1:L554LCQZc3d7mtcdPUgDbSrCVbr48/30zgu0VuC/FTA= github.com/bool64/dev v0.1.41 h1:L554LCQZc3d7mtcdPUgDbSrCVbr48/30zgu0VuC/FTA=
github.com/bool64/dev v0.1.41/go.mod h1:cTHiTDNc8EewrQPy3p1obNilpMpdmlUesDkFTF2zRWU= github.com/bool64/dev v0.1.41/go.mod h1:cTHiTDNc8EewrQPy3p1obNilpMpdmlUesDkFTF2zRWU=
@@ -138,7 +147,10 @@ github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2w
github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo= github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chromedp/cdproto v0.0.0-20210526005521-9e51b9051fd0/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U= github.com/chromedp/cdproto v0.0.0-20210526005521-9e51b9051fd0/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
github.com/chromedp/cdproto v0.0.0-20210622022015-fe1827b46b84 h1:Xxl4imt7LA3SbkrlIH5mm+mbzsv0tpHomLASTPINlvQ= github.com/chromedp/cdproto v0.0.0-20210622022015-fe1827b46b84 h1:Xxl4imt7LA3SbkrlIH5mm+mbzsv0tpHomLASTPINlvQ=
github.com/chromedp/cdproto v0.0.0-20210622022015-fe1827b46b84/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U= github.com/chromedp/cdproto v0.0.0-20210622022015-fe1827b46b84/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
@@ -149,29 +161,32 @@ github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moA
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80= github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/cockroachdb/cockroach-go/v2 v2.1.1/go.mod h1:7NtUnP6eK+l6k483WSYNrq3Kb23bWV10IRV1TyeSpwM= github.com/cockroachdb/cockroach-go/v2 v2.1.1/go.mod h1:7NtUnP6eK+l6k483WSYNrq3Kb23bWV10IRV1TyeSpwM=
github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/corona10/goimagehash v1.0.3 h1:NZM518aKLmoNluluhfHGxT3LGOnrojrxhGn63DR/CZA= github.com/corona10/goimagehash v1.0.3 h1:NZM518aKLmoNluluhfHGxT3LGOnrojrxhGn63DR/CZA=
github.com/corona10/goimagehash v1.0.3/go.mod h1:VkvE0mLn84L4aF8vCb6mafVajEb6QYMHl2ZJLn0mOGI= github.com/corona10/goimagehash v1.0.3/go.mod h1:VkvE0mLn84L4aF8vCb6mafVajEb6QYMHl2ZJLn0mOGI=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -179,8 +194,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g=
github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
github.com/dhui/dktest v0.3.4/go.mod h1:4m4n6lmXlmVfESth7mzdcv8nBI5mOb5UROPqjM02csU= github.com/dhui/dktest v0.3.4/go.mod h1:4m4n6lmXlmVfESth7mzdcv8nBI5mOb5UROPqjM02csU=
@@ -201,9 +214,13 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@@ -215,7 +232,6 @@ github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui72
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
github.com/go-chi/chi v3.3.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/chi v4.0.2+incompatible h1:maB6vn6FqCxrpz4FqWdh4+lwpyZIQS7YEAUcHlgXVRs= github.com/go-chi/chi v4.0.2+incompatible h1:maB6vn6FqCxrpz4FqWdh4+lwpyZIQS7YEAUcHlgXVRs=
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/chi/v5 v5.0.0 h1:DBPx88FjZJH3FsICfDAfIfnb7XxKIYVGG6lOPlhENAg= github.com/go-chi/chi/v5 v5.0.0 h1:DBPx88FjZJH3FsICfDAfIfnb7XxKIYVGG6lOPlhENAg=
@@ -226,6 +242,7 @@ github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
@@ -269,9 +286,7 @@ github.com/gocql/gocql v0.0.0-20190301043612-f6df8288f9b4/go.mod h1:4Fw1eo5iaEhD
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v4 v4.0.0 h1:RAqyYixv1p7uEnocuy8P1nru5wprCh/MH2BIlW5z5/o= github.com/golang-jwt/jwt/v4 v4.0.0 h1:RAqyYixv1p7uEnocuy8P1nru5wprCh/MH2BIlW5z5/o=
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
@@ -279,7 +294,6 @@ github.com/golang-migrate/migrate/v4 v4.15.0-beta.1 h1:3iUwrd6V9oIzNc6TQdp4SLYNj
github.com/golang-migrate/migrate/v4 v4.15.0-beta.1/go.mod h1:QOmbm9b62AcsxBz7VbwJf+3mqgAyVrdKx7AQ8T9m5og= github.com/golang-migrate/migrate/v4 v4.15.0-beta.1/go.mod h1:QOmbm9b62AcsxBz7VbwJf+3mqgAyVrdKx7AQ8T9m5og=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -350,6 +364,7 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
@@ -362,12 +377,11 @@ github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/mux v1.6.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
@@ -375,50 +389,48 @@ github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyC
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ= github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ=
github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/h2non/filetype v1.0.8 h1:le8gpf+FQA0/DlDABbtisA1KiTS0Xi+YSC/E8yY3Y14=
github.com/h2non/filetype v1.0.8/go.mod h1:isekKqOuhMj+s/7r3rIeTErIRy4Rub5uBWHfvMusLMU=
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
github.com/hashicorp/consul/api v1.10.1/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo=
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
@@ -477,16 +489,16 @@ github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhB
github.com/jmoiron/sqlx v1.3.1 h1:aLN7YINNZ7cYOPK3QC83dbM6KT0NMqVMw961TqrejlE= github.com/jmoiron/sqlx v1.3.1 h1:aLN7YINNZ7cYOPK3QC83dbM6KT0NMqVMw961TqrejlE=
github.com/jmoiron/sqlx v1.3.1/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= github.com/jmoiron/sqlx v1.3.1/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
github.com/k0kubun/pp v2.3.0+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= github.com/k0kubun/pp v2.3.0+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg=
@@ -496,11 +508,9 @@ github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0Lh
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kermieisinthehouse/gosx-notifier v0.1.1 h1:lVXyKsa1c1RUkckp3KayloNLoI//fUwVYye3RPSPtEw= github.com/kermieisinthehouse/gosx-notifier v0.1.1 h1:lVXyKsa1c1RUkckp3KayloNLoI//fUwVYye3RPSPtEw=
github.com/kermieisinthehouse/gosx-notifier v0.1.1/go.mod h1:xyWT07azFtUOcHl96qMVvKhvKzsMcS7rKTHQyv8WTho= github.com/kermieisinthehouse/gosx-notifier v0.1.1/go.mod h1:xyWT07azFtUOcHl96qMVvKhvKzsMcS7rKTHQyv8WTho=
github.com/kermieisinthehouse/systray v1.2.3 h1:tawLahcam/Ccs/F2n6EOQo8qJnSTD2hLzOYqTGsUsbA=
github.com/kermieisinthehouse/systray v1.2.3/go.mod h1:axh6C/jNuSyC0QGtidZJURc9h+h41HNoMySoLVrhVR4=
github.com/kermieisinthehouse/systray v1.2.4 h1:pdH5vnl+KKjRrVCRU4g/2W1/0HVzuuJ6WXHlPPHYY6s= github.com/kermieisinthehouse/systray v1.2.4 h1:pdH5vnl+KKjRrVCRU4g/2W1/0HVzuuJ6WXHlPPHYY6s=
github.com/kermieisinthehouse/systray v1.2.4/go.mod h1:axh6C/jNuSyC0QGtidZJURc9h+h41HNoMySoLVrhVR4= github.com/kermieisinthehouse/systray v1.2.4/go.mod h1:axh6C/jNuSyC0QGtidZJURc9h+h41HNoMySoLVrhVR4=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kevinmbeaulieu/eq-go v1.0.0/go.mod h1:G3S8ajA56gKBZm4UB9AOyoOS37JO3roToPzKNM8dtdM=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
@@ -525,25 +535,28 @@ github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.0 h1:Zx5DJFEYQXio93kgXnQ09fXNiUKsqv4OUEu2UtGcB1E= github.com/lib/pq v1.10.0 h1:Zx5DJFEYQXio93kgXnQ09fXNiUKsqv4OUEu2UtGcB1E=
github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/logrusorgru/aurora/v3 v3.0.0/go.mod h1:vsR12bk5grlLvLXAYrBsb5Oc/N+LxAlxggSjiwMnCUc=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
github.com/markbates/pkger v0.15.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= github.com/markbates/pkger v0.15.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI=
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007 h1:reVOUXwnhsYv/8UqjvhrMOu5CNT9UapHFLbQ2JcXsmg= github.com/matryer/moq v0.2.3/go.mod h1:9RtPYjTnH1bSBIkpvtHkFN7nbWAnO7oRpdJkEIn6UtE=
github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= github.com/matryer/moq v0.2.6 h1:X4+LF09udTsi2P+Z+1UhSb4p3K8IyiF7KSNFDR9M3M0=
github.com/matryer/moq v0.2.6/go.mod h1:kITsx543GOENm48TUAQyJ9+SAvFSr7iGQXPoth/VUBk=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E= github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
@@ -553,32 +566,31 @@ github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2y
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo= github.com/mitchellh/mapstructure v1.2.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
@@ -594,17 +606,14 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWb
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM=
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
@@ -621,27 +630,29 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E= github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7Kyl5E=
github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo= github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo=
github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac h1:kYPjbEN6YPYWWHI6ky1J813KzIq/8+Wg4TO4xU7A/KU= github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac h1:kYPjbEN6YPYWWHI6ky1J813KzIq/8+Wg4TO4xU7A/KU=
github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY= github.com/robertkrimen/otto v0.0.0-20200922221731-ef014fd054ac/go.mod h1:xvqspoSXJTIpemEonrMDFq6XzwHYYgToXWj5eRX1OtY=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
@@ -649,19 +660,21 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI= github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI=
github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/rs/zerolog v1.18.0/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF5+I=
github.com/rs/zerolog v1.18.1-0.20200514152719-663cbb4c8469 h1:DuXsEWHUTO5lsxxzKM4KUKGDIOi7nawNDs6d+AiulEA=
github.com/rs/zerolog v1.18.1-0.20200514152719-663cbb4c8469/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo= github.com/rs/zerolog v1.18.1-0.20200514152719-663cbb4c8469/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/rs/zerolog v1.26.1 h1:/ihwxqH+4z8UxyI70wM1z9yCvkWcfz/a3mj48k/Zngc=
github.com/rs/zerolog v1.26.1/go.mod h1:/wSSJWX7lVrsOwlbyTRSOJvqRlc+WjWlfes+CiJ+tmc=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8= github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8=
github.com/sagikazarmark/crypt v0.1.0/go.mod h1:B/mN0msZuINBtQ1zZLEQcegFJJf9vnYIR88KRMEuODE= github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
@@ -669,10 +682,7 @@ github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhr
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f h1:tygelZueB1EtXkPI6mQ4o9DQ0+FKW41hTbunoXZCTqk= github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f h1:tygelZueB1EtXkPI6mQ4o9DQ0+FKW41hTbunoXZCTqk=
github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f/go.mod h1:AuYgA5Kyo4c7HfUmvRGs/6rGlMMV/6B1bVnB9JxJEEg= github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f/go.mod h1:AuYgA5Kyo4c7HfUmvRGs/6rGlMMV/6B1bVnB9JxJEEg=
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
@@ -683,29 +693,27 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/snowflakedb/gosnowflake v1.4.3/go.mod h1:1kyg2XEduwti88V11PKRHImhXLK5WpGiayY6lFNYb98= github.com/snowflakedb/gosnowflake v1.4.3/go.mod h1:1kyg2XEduwti88V11PKRHImhXLK5WpGiayY6lFNYb98=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/afero v1.8.0/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo=
github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA=
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4=
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.10.1 h1:nuJZuYpG7gTj/XqiUwg8bA0cp1+M2mC3J4g5luUYBKk=
github.com/spf13/viper v1.9.0 h1:yR6EXjTp0y0cLN8OZg1CRZmOBdI88UcGkhgyJhu6nZk= github.com/spf13/viper v1.10.1/go.mod h1:IGlFPqhNAPKRxohIzWpI5QEy4kuI7tcl5WvR+8qy1rU=
github.com/spf13/viper v1.9.0/go.mod h1:+i6ajR7OX2XaiBkrcZJFK21htRk7eDeLg7+O6bhUPP4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
@@ -729,39 +737,35 @@ github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhV
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k= github.com/urfave/cli/v2 v2.4.0 h1:m2pxjjDFgDxSPtO8WSdbndj17Wu2y8vOT86wE/tjr+I=
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/urfave/cli/v2 v2.4.0/go.mod h1:NX9W0zmTvedE5oDoOMs2RTC8RvdK98NTYZE5LbaEYPg=
github.com/vearutop/statigz v1.1.6 h1:si1zvulh/6P4S/SjFticuKQ8/EgQISglaRuycj8PWso= github.com/vearutop/statigz v1.1.6 h1:si1zvulh/6P4S/SjFticuKQ8/EgQISglaRuycj8PWso=
github.com/vearutop/statigz v1.1.6/go.mod h1:czAv7iXgPv/s+xsgXpVEhhD0NSOQ4wZPgmM/n7LANDI= github.com/vearutop/statigz v1.1.6/go.mod h1:czAv7iXgPv/s+xsgXpVEhhD0NSOQ4wZPgmM/n7LANDI=
github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e h1:+w0Zm/9gaWpEAyDlU1eKOuk5twTjAjuevXqcJJw8hrg= github.com/vektah/gqlparser/v2 v2.4.0/go.mod h1:flJWIR04IMQPGz+BXLrORkrARBxv/rtyIAFvd/MceW0=
github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U= github.com/vektah/gqlparser/v2 v2.4.1 h1:QOyEn8DAPMUMARGMeshKDkDgNmVoEaEGiDB0uWxcSlQ=
github.com/vektah/gqlparser v1.3.1 h1:8b0IcD3qZKWJQHSzynbDlrtP3IxVydZ2DZepCGofqfU= github.com/vektah/gqlparser/v2 v2.4.1/go.mod h1:flJWIR04IMQPGz+BXLrORkrARBxv/rtyIAFvd/MceW0=
github.com/vektah/gqlparser v1.3.1/go.mod h1:bkVf0FX+Stjg/MHnm8mEyubuaArhNEqfQhF+OTiAL74= github.com/vektra/mockery/v2 v2.10.0 h1:MiiQWxwdq7/ET6dCXLaJzSGEN17k758H7JHS9kOdiks=
github.com/vektah/gqlparser/v2 v2.0.1 h1:xgl5abVnsd4hkN9rk65OJID9bfcLSMuTaTcZj777q1o= github.com/vektra/mockery/v2 v2.10.0/go.mod h1:m/WO2UzWzqgVX3nvqpRQq70I4Z7jbSCRhdmkgtp+Ab4=
github.com/vektah/gqlparser/v2 v2.0.1/go.mod h1:SyUiHgLATUR8BiYURfTirrTcGpcE+4XkV2se04Px1Ms=
github.com/vektra/mockery/v2 v2.2.1 h1:EYgPvxyYkm/0JKs62qlVc9pO+ljb8biPbDWabk5/PmI=
github.com/vektra/mockery/v2 v2.2.1/go.mod h1:rBZUbbhMbiSX1WlCGsOgAi6xjuJGxB7KKbnoL0XNYW8=
github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs= github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE= gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs=
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
go.mongodb.org/mongo-driver v1.7.0/go.mod h1:Q4oFMbo1+MSNqICAdYMlC/zSTrwCogR4R8NzkI+yfU8= go.mongodb.org/mongo-driver v1.7.0/go.mod h1:Q4oFMbo1+MSNqICAdYMlC/zSTrwCogR4R8NzkI+yfU8=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
@@ -800,9 +804,15 @@ golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215165025-cf75a172585e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 h1:S25/rfnfsMVgORT4/J61MJ7rdyseOZOyvLIrZEZ7s6s=
golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -840,8 +850,11 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -849,8 +862,6 @@ golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190225153610-fe579d43d832/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190225153610-fe579d43d832/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -859,8 +870,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190415214537-1da14a5a36f2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190415214537-1da14a5a36f2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -887,12 +898,18 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9 h1:0qxwC5n+ttVOINCBeRHO0nq9X7uy8SDsPoi5OaCdIEI= golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9 h1:0qxwC5n+ttVOINCBeRHO0nq9X7uy8SDsPoi5OaCdIEI=
golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -913,6 +930,8 @@ golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -931,7 +950,6 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -987,6 +1005,7 @@ golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -995,6 +1014,7 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210412220455-f1c623a9e750/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210412220455-f1c623a9e750/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210521090106-6ca3eb03dfc2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210521090106-6ca3eb03dfc2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1005,12 +1025,24 @@ golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220329152356-43be30ef3008 h1:pq9pwoi2rjLWvmiVser/lIOgiyA3fli4M+RfGVMA7nE=
golang.org/x/sys v0.0.0-20220329152356-43be30ef3008/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1025,22 +1057,18 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
@@ -1054,7 +1082,6 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -1062,7 +1089,6 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
@@ -1073,7 +1099,6 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200323144430-8dcfad9e016e/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
@@ -1082,8 +1107,8 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200815165600-90abf76919f3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200827163409-021d7c6f1ec3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
@@ -1091,13 +1116,18 @@ golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1132,7 +1162,13 @@ google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtuk
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU=
google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw=
google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo=
google.golang.org/appengine v1.0.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.0.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -1178,8 +1214,10 @@ google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
@@ -1198,9 +1236,19 @@ google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKr
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
@@ -1225,6 +1273,9 @@ google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQ
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@@ -1249,21 +1300,20 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.63.2 h1:tGK/CyBg7SMzb60vP1M03vNZ3VDu3wGQJwn7Sxi9r3c= gopkg.in/ini.v1 v1.66.3/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI= gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@@ -1309,5 +1359,3 @@ modernc.org/zappy v1.0.0/go.mod h1:hHe+oGahLVII/aTTyWK/b53VDHMAGCBYYeZ9sn83HC4=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sourcegraph.com/sourcegraph/appdash v0.0.0-20180110180208-2cc67fd64755/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67/go.mod h1:L5q+DGLGOQFpo1snNEkLOJT2d1YTW66rWNzatr3He1k=

View File

@@ -9,11 +9,24 @@ import (
"github.com/Yamashou/gqlgenc/client" "github.com/Yamashou/gqlgenc/client"
) )
type StashBoxGraphQLClient interface {
FindSceneByFingerprint(ctx context.Context, fingerprint FingerprintQueryInput, httpRequestOptions ...client.HTTPRequestOption) (*FindSceneByFingerprint, error)
FindScenesByFullFingerprints(ctx context.Context, fingerprints []*FingerprintQueryInput, httpRequestOptions ...client.HTTPRequestOption) (*FindScenesByFullFingerprints, error)
SearchScene(ctx context.Context, term string, httpRequestOptions ...client.HTTPRequestOption) (*SearchScene, error)
SearchPerformer(ctx context.Context, term string, httpRequestOptions ...client.HTTPRequestOption) (*SearchPerformer, error)
FindPerformerByID(ctx context.Context, id string, httpRequestOptions ...client.HTTPRequestOption) (*FindPerformerByID, error)
FindSceneByID(ctx context.Context, id string, httpRequestOptions ...client.HTTPRequestOption) (*FindSceneByID, error)
SubmitFingerprint(ctx context.Context, input FingerprintSubmission, httpRequestOptions ...client.HTTPRequestOption) (*SubmitFingerprint, error)
Me(ctx context.Context, httpRequestOptions ...client.HTTPRequestOption) (*Me, error)
SubmitSceneDraft(ctx context.Context, input SceneDraftInput, httpRequestOptions ...client.HTTPRequestOption) (*SubmitSceneDraft, error)
SubmitPerformerDraft(ctx context.Context, input PerformerDraftInput, httpRequestOptions ...client.HTTPRequestOption) (*SubmitPerformerDraft, error)
}
type Client struct { type Client struct {
Client *client.Client Client *client.Client
} }
func NewClient(cli *http.Client, baseURL string, options ...client.HTTPRequestOption) *Client { func NewClient(cli *http.Client, baseURL string, options ...client.HTTPRequestOption) StashBoxGraphQLClient {
return &Client{Client: client.NewClient(cli, baseURL, options...)} return &Client{Client: client.NewClient(cli, baseURL, options...)}
} }
@@ -45,7 +58,6 @@ type Query struct {
Version Version "json:\"version\" graphql:\"version\"" Version Version "json:\"version\" graphql:\"version\""
GetConfig StashBoxConfig "json:\"getConfig\" graphql:\"getConfig\"" GetConfig StashBoxConfig "json:\"getConfig\" graphql:\"getConfig\""
} }
type Mutation struct { type Mutation struct {
SceneCreate *Scene "json:\"sceneCreate\" graphql:\"sceneCreate\"" SceneCreate *Scene "json:\"sceneCreate\" graphql:\"sceneCreate\""
SceneUpdate *Scene "json:\"sceneUpdate\" graphql:\"sceneUpdate\"" SceneUpdate *Scene "json:\"sceneUpdate\" graphql:\"sceneUpdate\""
@@ -91,6 +103,8 @@ type Mutation struct {
SubmitSceneDraft DraftSubmissionStatus "json:\"submitSceneDraft\" graphql:\"submitSceneDraft\"" SubmitSceneDraft DraftSubmissionStatus "json:\"submitSceneDraft\" graphql:\"submitSceneDraft\""
SubmitPerformerDraft DraftSubmissionStatus "json:\"submitPerformerDraft\" graphql:\"submitPerformerDraft\"" SubmitPerformerDraft DraftSubmissionStatus "json:\"submitPerformerDraft\" graphql:\"submitPerformerDraft\""
DestroyDraft bool "json:\"destroyDraft\" graphql:\"destroyDraft\"" DestroyDraft bool "json:\"destroyDraft\" graphql:\"destroyDraft\""
FavoritePerformer bool "json:\"favoritePerformer\" graphql:\"favoritePerformer\""
FavoriteStudio bool "json:\"favoriteStudio\" graphql:\"favoriteStudio\""
} }
type URLFragment struct { type URLFragment struct {
URL string "json:\"url\" graphql:\"url\"" URL string "json:\"url\" graphql:\"url\""
@@ -188,7 +202,7 @@ type FindPerformerByID struct {
type FindSceneByID struct { type FindSceneByID struct {
FindScene *SceneFragment "json:\"findScene\" graphql:\"findScene\"" FindScene *SceneFragment "json:\"findScene\" graphql:\"findScene\""
} }
type SubmitFingerprintPayload struct { type SubmitFingerprint struct {
SubmitFingerprint bool "json:\"submitFingerprint\" graphql:\"submitFingerprint\"" SubmitFingerprint bool "json:\"submitFingerprint\" graphql:\"submitFingerprint\""
} }
type Me struct { type Me struct {
@@ -196,39 +210,22 @@ type Me struct {
Name string "json:\"name\" graphql:\"name\"" Name string "json:\"name\" graphql:\"name\""
} "json:\"me\" graphql:\"me\"" } "json:\"me\" graphql:\"me\""
} }
type SubmitSceneDraftPayload struct { type SubmitSceneDraft struct {
SubmitSceneDraft struct { SubmitSceneDraft struct {
ID *string "json:\"id\" graphql:\"id\"" ID *string "json:\"id\" graphql:\"id\""
} "json:\"submitSceneDraft\" graphql:\"submitSceneDraft\"" } "json:\"submitSceneDraft\" graphql:\"submitSceneDraft\""
} }
type SubmitPerformerDraftPayload struct { type SubmitPerformerDraft struct {
SubmitPerformerDraft struct { SubmitPerformerDraft struct {
ID *string "json:\"id\" graphql:\"id\"" ID *string "json:\"id\" graphql:\"id\""
} "json:\"submitPerformerDraft\" graphql:\"submitPerformerDraft\"" } "json:\"submitPerformerDraft\" graphql:\"submitPerformerDraft\""
} }
const FindSceneByFingerprintQuery = `query FindSceneByFingerprint ($fingerprint: FingerprintQueryInput!) { const FindSceneByFingerprintDocument = `query FindSceneByFingerprint ($fingerprint: FingerprintQueryInput!) {
findSceneByFingerprint(fingerprint: $fingerprint) { findSceneByFingerprint(fingerprint: $fingerprint) {
... SceneFragment ... SceneFragment
} }
} }
fragment BodyModificationFragment on BodyModification {
location
description
}
fragment FingerprintFragment on Fingerprint {
algorithm
hash
duration
}
fragment URLFragment on URL {
url
type
}
fragment TagFragment on Tag {
name
id
}
fragment PerformerFragment on Performer { fragment PerformerFragment on Performer {
id id
name name
@@ -263,16 +260,43 @@ fragment PerformerFragment on Performer {
... BodyModificationFragment ... BodyModificationFragment
} }
} }
fragment FuzzyDateFragment on FuzzyDate {
date
accuracy
}
fragment MeasurementsFragment on Measurements { fragment MeasurementsFragment on Measurements {
band_size band_size
cup_size cup_size
waist waist
hip hip
} }
fragment BodyModificationFragment on BodyModification {
location
description
}
fragment URLFragment on URL {
url
type
}
fragment StudioFragment on Studio {
name
id
urls {
... URLFragment
}
images {
... ImageFragment
}
}
fragment TagFragment on Tag {
name
id
}
fragment FuzzyDateFragment on FuzzyDate {
date
accuracy
}
fragment FingerprintFragment on Fingerprint {
algorithm
hash
duration
}
fragment SceneFragment on Scene { fragment SceneFragment on Scene {
id id
title title
@@ -304,16 +328,6 @@ fragment ImageFragment on Image {
width width
height height
} }
fragment StudioFragment on Studio {
name
id
urls {
... URLFragment
}
images {
... ImageFragment
}
}
fragment PerformerAppearanceFragment on PerformerAppearance { fragment PerformerAppearanceFragment on PerformerAppearance {
as as
performer { performer {
@@ -328,27 +342,52 @@ func (c *Client) FindSceneByFingerprint(ctx context.Context, fingerprint Fingerp
} }
var res FindSceneByFingerprint var res FindSceneByFingerprint
if err := c.Client.Post(ctx, FindSceneByFingerprintQuery, &res, vars, httpRequestOptions...); err != nil { if err := c.Client.Post(ctx, "FindSceneByFingerprint", FindSceneByFingerprintDocument, &res, vars, httpRequestOptions...); err != nil {
return nil, err return nil, err
} }
return &res, nil return &res, nil
} }
const FindScenesByFullFingerprintsQuery = `query FindScenesByFullFingerprints ($fingerprints: [FingerprintQueryInput!]!) { const FindScenesByFullFingerprintsDocument = `query FindScenesByFullFingerprints ($fingerprints: [FingerprintQueryInput!]!) {
findScenesByFullFingerprints(fingerprints: $fingerprints) { findScenesByFullFingerprints(fingerprints: $fingerprints) {
... SceneFragment ... SceneFragment
} }
} }
fragment StudioFragment on Studio { fragment SceneFragment on Scene {
name
id id
title
details
duration
date
urls { urls {
... URLFragment ... URLFragment
} }
images { images {
... ImageFragment ... ImageFragment
} }
studio {
... StudioFragment
}
tags {
... TagFragment
}
performers {
... PerformerAppearanceFragment
}
fingerprints {
... FingerprintFragment
}
}
fragment URLFragment on URL {
url
type
}
fragment PerformerAppearanceFragment on PerformerAppearance {
as
performer {
... PerformerFragment
}
} }
fragment PerformerFragment on Performer { fragment PerformerFragment on Performer {
id id
@@ -398,55 +437,30 @@ fragment BodyModificationFragment on BodyModification {
location location
description description
} }
fragment FingerprintFragment on Fingerprint {
algorithm
hash
duration
}
fragment ImageFragment on Image { fragment ImageFragment on Image {
id id
url url
width width
height height
} }
fragment URLFragment on URL { fragment StudioFragment on Studio {
url
type
}
fragment TagFragment on Tag {
name name
id id
}
fragment PerformerAppearanceFragment on PerformerAppearance {
as
performer {
... PerformerFragment
}
}
fragment FingerprintFragment on Fingerprint {
algorithm
hash
duration
}
fragment SceneFragment on Scene {
id
title
details
duration
date
urls { urls {
... URLFragment ... URLFragment
} }
images { images {
... ImageFragment ... ImageFragment
} }
studio {
... StudioFragment
}
tags {
... TagFragment
}
performers {
... PerformerAppearanceFragment
}
fingerprints {
... FingerprintFragment
} }
fragment TagFragment on Tag {
name
id
} }
` `
@@ -456,23 +470,18 @@ func (c *Client) FindScenesByFullFingerprints(ctx context.Context, fingerprints
} }
var res FindScenesByFullFingerprints var res FindScenesByFullFingerprints
if err := c.Client.Post(ctx, FindScenesByFullFingerprintsQuery, &res, vars, httpRequestOptions...); err != nil { if err := c.Client.Post(ctx, "FindScenesByFullFingerprints", FindScenesByFullFingerprintsDocument, &res, vars, httpRequestOptions...); err != nil {
return nil, err return nil, err
} }
return &res, nil return &res, nil
} }
const SearchSceneQuery = `query SearchScene ($term: String!) { const SearchSceneDocument = `query SearchScene ($term: String!) {
searchScene(term: $term) { searchScene(term: $term) {
... SceneFragment ... SceneFragment
} }
} }
fragment FingerprintFragment on Fingerprint {
algorithm
hash
duration
}
fragment URLFragment on URL { fragment URLFragment on URL {
url url
type type
@@ -493,51 +502,6 @@ fragment PerformerAppearanceFragment on PerformerAppearance {
... PerformerFragment ... PerformerFragment
} }
} }
fragment MeasurementsFragment on Measurements {
band_size
cup_size
waist
hip
}
fragment BodyModificationFragment on BodyModification {
location
description
}
fragment SceneFragment on Scene {
id
title
details
duration
date
urls {
... URLFragment
}
images {
... ImageFragment
}
studio {
... StudioFragment
}
tags {
... TagFragment
}
performers {
... PerformerAppearanceFragment
}
fingerprints {
... FingerprintFragment
}
}
fragment StudioFragment on Studio {
name
id
urls {
... URLFragment
}
images {
... ImageFragment
}
}
fragment PerformerFragment on Performer { fragment PerformerFragment on Performer {
id id
name name
@@ -576,6 +540,56 @@ fragment FuzzyDateFragment on FuzzyDate {
date date
accuracy accuracy
} }
fragment FingerprintFragment on Fingerprint {
algorithm
hash
duration
}
fragment SceneFragment on Scene {
id
title
details
duration
date
urls {
... URLFragment
}
images {
... ImageFragment
}
studio {
... StudioFragment
}
tags {
... TagFragment
}
performers {
... PerformerAppearanceFragment
}
fingerprints {
... FingerprintFragment
}
}
fragment StudioFragment on Studio {
name
id
urls {
... URLFragment
}
images {
... ImageFragment
}
}
fragment MeasurementsFragment on Measurements {
band_size
cup_size
waist
hip
}
fragment BodyModificationFragment on BodyModification {
location
description
}
` `
func (c *Client) SearchScene(ctx context.Context, term string, httpRequestOptions ...client.HTTPRequestOption) (*SearchScene, error) { func (c *Client) SearchScene(ctx context.Context, term string, httpRequestOptions ...client.HTTPRequestOption) (*SearchScene, error) {
@@ -584,18 +598,42 @@ func (c *Client) SearchScene(ctx context.Context, term string, httpRequestOption
} }
var res SearchScene var res SearchScene
if err := c.Client.Post(ctx, SearchSceneQuery, &res, vars, httpRequestOptions...); err != nil { if err := c.Client.Post(ctx, "SearchScene", SearchSceneDocument, &res, vars, httpRequestOptions...); err != nil {
return nil, err return nil, err
} }
return &res, nil return &res, nil
} }
const SearchPerformerQuery = `query SearchPerformer ($term: String!) { const SearchPerformerDocument = `query SearchPerformer ($term: String!) {
searchPerformer(term: $term) { searchPerformer(term: $term) {
... PerformerFragment ... PerformerFragment
} }
} }
fragment URLFragment on URL {
url
type
}
fragment ImageFragment on Image {
id
url
width
height
}
fragment FuzzyDateFragment on FuzzyDate {
date
accuracy
}
fragment MeasurementsFragment on Measurements {
band_size
cup_size
waist
hip
}
fragment BodyModificationFragment on BodyModification {
location
description
}
fragment PerformerFragment on Performer { fragment PerformerFragment on Performer {
id id
name name
@@ -630,30 +668,6 @@ fragment PerformerFragment on Performer {
... BodyModificationFragment ... BodyModificationFragment
} }
} }
fragment URLFragment on URL {
url
type
}
fragment ImageFragment on Image {
id
url
width
height
}
fragment FuzzyDateFragment on FuzzyDate {
date
accuracy
}
fragment MeasurementsFragment on Measurements {
band_size
cup_size
waist
hip
}
fragment BodyModificationFragment on BodyModification {
location
description
}
` `
func (c *Client) SearchPerformer(ctx context.Context, term string, httpRequestOptions ...client.HTTPRequestOption) (*SearchPerformer, error) { func (c *Client) SearchPerformer(ctx context.Context, term string, httpRequestOptions ...client.HTTPRequestOption) (*SearchPerformer, error) {
@@ -662,42 +676,18 @@ func (c *Client) SearchPerformer(ctx context.Context, term string, httpRequestOp
} }
var res SearchPerformer var res SearchPerformer
if err := c.Client.Post(ctx, SearchPerformerQuery, &res, vars, httpRequestOptions...); err != nil { if err := c.Client.Post(ctx, "SearchPerformer", SearchPerformerDocument, &res, vars, httpRequestOptions...); err != nil {
return nil, err return nil, err
} }
return &res, nil return &res, nil
} }
const FindPerformerByIDQuery = `query FindPerformerByID ($id: ID!) { const FindPerformerByIDDocument = `query FindPerformerByID ($id: ID!) {
findPerformer(id: $id) { findPerformer(id: $id) {
... PerformerFragment ... PerformerFragment
} }
} }
fragment URLFragment on URL {
url
type
}
fragment ImageFragment on Image {
id
url
width
height
}
fragment FuzzyDateFragment on FuzzyDate {
date
accuracy
}
fragment MeasurementsFragment on Measurements {
band_size
cup_size
waist
hip
}
fragment BodyModificationFragment on BodyModification {
location
description
}
fragment PerformerFragment on Performer { fragment PerformerFragment on Performer {
id id
name name
@@ -732,29 +722,15 @@ fragment PerformerFragment on Performer {
... BodyModificationFragment ... BodyModificationFragment
} }
} }
` fragment URLFragment on URL {
url
func (c *Client) FindPerformerByID(ctx context.Context, id string, httpRequestOptions ...client.HTTPRequestOption) (*FindPerformerByID, error) { type
vars := map[string]interface{}{
"id": id,
} }
fragment ImageFragment on Image {
var res FindPerformerByID
if err := c.Client.Post(ctx, FindPerformerByIDQuery, &res, vars, httpRequestOptions...); err != nil {
return nil, err
}
return &res, nil
}
const FindSceneByIDQuery = `query FindSceneByID ($id: ID!) {
findScene(id: $id) {
... SceneFragment
}
}
fragment TagFragment on Tag {
name
id id
url
width
height
} }
fragment FuzzyDateFragment on FuzzyDate { fragment FuzzyDateFragment on FuzzyDate {
date date
@@ -766,39 +742,29 @@ fragment MeasurementsFragment on Measurements {
waist waist
hip hip
} }
fragment FingerprintFragment on Fingerprint { fragment BodyModificationFragment on BodyModification {
algorithm location
hash description
duration
} }
fragment SceneFragment on Scene { `
id
title func (c *Client) FindPerformerByID(ctx context.Context, id string, httpRequestOptions ...client.HTTPRequestOption) (*FindPerformerByID, error) {
details vars := map[string]interface{}{
duration "id": id,
date
urls {
... URLFragment
} }
images {
... ImageFragment var res FindPerformerByID
if err := c.Client.Post(ctx, "FindPerformerByID", FindPerformerByIDDocument, &res, vars, httpRequestOptions...); err != nil {
return nil, err
} }
studio {
... StudioFragment return &res, nil
} }
tags {
... TagFragment const FindSceneByIDDocument = `query FindSceneByID ($id: ID!) {
findScene(id: $id) {
... SceneFragment
} }
performers {
... PerformerAppearanceFragment
}
fingerprints {
... FingerprintFragment
}
}
fragment URLFragment on URL {
url
type
} }
fragment ImageFragment on Image { fragment ImageFragment on Image {
id id
@@ -806,16 +772,6 @@ fragment ImageFragment on Image {
width width
height height
} }
fragment StudioFragment on Studio {
name
id
urls {
... URLFragment
}
images {
... ImageFragment
}
}
fragment PerformerAppearanceFragment on PerformerAppearance { fragment PerformerAppearanceFragment on PerformerAppearance {
as as
performer { performer {
@@ -856,10 +812,68 @@ fragment PerformerFragment on Performer {
... BodyModificationFragment ... BodyModificationFragment
} }
} }
fragment FuzzyDateFragment on FuzzyDate {
date
accuracy
}
fragment BodyModificationFragment on BodyModification { fragment BodyModificationFragment on BodyModification {
location location
description description
} }
fragment FingerprintFragment on Fingerprint {
algorithm
hash
duration
}
fragment SceneFragment on Scene {
id
title
details
duration
date
urls {
... URLFragment
}
images {
... ImageFragment
}
studio {
... StudioFragment
}
tags {
... TagFragment
}
performers {
... PerformerAppearanceFragment
}
fingerprints {
... FingerprintFragment
}
}
fragment URLFragment on URL {
url
type
}
fragment StudioFragment on Studio {
name
id
urls {
... URLFragment
}
images {
... ImageFragment
}
}
fragment TagFragment on Tag {
name
id
}
fragment MeasurementsFragment on Measurements {
band_size
cup_size
waist
hip
}
` `
func (c *Client) FindSceneByID(ctx context.Context, id string, httpRequestOptions ...client.HTTPRequestOption) (*FindSceneByID, error) { func (c *Client) FindSceneByID(ctx context.Context, id string, httpRequestOptions ...client.HTTPRequestOption) (*FindSceneByID, error) {
@@ -868,32 +882,32 @@ func (c *Client) FindSceneByID(ctx context.Context, id string, httpRequestOption
} }
var res FindSceneByID var res FindSceneByID
if err := c.Client.Post(ctx, FindSceneByIDQuery, &res, vars, httpRequestOptions...); err != nil { if err := c.Client.Post(ctx, "FindSceneByID", FindSceneByIDDocument, &res, vars, httpRequestOptions...); err != nil {
return nil, err return nil, err
} }
return &res, nil return &res, nil
} }
const SubmitFingerprintQuery = `mutation SubmitFingerprint ($input: FingerprintSubmission!) { const SubmitFingerprintDocument = `mutation SubmitFingerprint ($input: FingerprintSubmission!) {
submitFingerprint(input: $input) submitFingerprint(input: $input)
} }
` `
func (c *Client) SubmitFingerprint(ctx context.Context, input FingerprintSubmission, httpRequestOptions ...client.HTTPRequestOption) (*SubmitFingerprintPayload, error) { func (c *Client) SubmitFingerprint(ctx context.Context, input FingerprintSubmission, httpRequestOptions ...client.HTTPRequestOption) (*SubmitFingerprint, error) {
vars := map[string]interface{}{ vars := map[string]interface{}{
"input": input, "input": input,
} }
var res SubmitFingerprintPayload var res SubmitFingerprint
if err := c.Client.Post(ctx, SubmitFingerprintQuery, &res, vars, httpRequestOptions...); err != nil { if err := c.Client.Post(ctx, "SubmitFingerprint", SubmitFingerprintDocument, &res, vars, httpRequestOptions...); err != nil {
return nil, err return nil, err
} }
return &res, nil return &res, nil
} }
const MeQuery = `query Me { const MeDocument = `query Me {
me { me {
name name
} }
@@ -904,47 +918,47 @@ func (c *Client) Me(ctx context.Context, httpRequestOptions ...client.HTTPReques
vars := map[string]interface{}{} vars := map[string]interface{}{}
var res Me var res Me
if err := c.Client.Post(ctx, MeQuery, &res, vars, httpRequestOptions...); err != nil { if err := c.Client.Post(ctx, "Me", MeDocument, &res, vars, httpRequestOptions...); err != nil {
return nil, err return nil, err
} }
return &res, nil return &res, nil
} }
const SubmitSceneDraftQuery = `mutation SubmitSceneDraft ($input: SceneDraftInput!) { const SubmitSceneDraftDocument = `mutation SubmitSceneDraft ($input: SceneDraftInput!) {
submitSceneDraft(input: $input) { submitSceneDraft(input: $input) {
id id
} }
} }
` `
func (c *Client) SubmitSceneDraft(ctx context.Context, input SceneDraftInput, httpRequestOptions ...client.HTTPRequestOption) (*SubmitSceneDraftPayload, error) { func (c *Client) SubmitSceneDraft(ctx context.Context, input SceneDraftInput, httpRequestOptions ...client.HTTPRequestOption) (*SubmitSceneDraft, error) {
vars := map[string]interface{}{ vars := map[string]interface{}{
"input": input, "input": input,
} }
var res SubmitSceneDraftPayload var res SubmitSceneDraft
if err := c.Client.Post(ctx, SubmitSceneDraftQuery, &res, vars, httpRequestOptions...); err != nil { if err := c.Client.Post(ctx, "SubmitSceneDraft", SubmitSceneDraftDocument, &res, vars, httpRequestOptions...); err != nil {
return nil, err return nil, err
} }
return &res, nil return &res, nil
} }
const SubmitPerformerDraftQuery = `mutation SubmitPerformerDraft ($input: PerformerDraftInput!) { const SubmitPerformerDraftDocument = `mutation SubmitPerformerDraft ($input: PerformerDraftInput!) {
submitPerformerDraft(input: $input) { submitPerformerDraft(input: $input) {
id id
} }
} }
` `
func (c *Client) SubmitPerformerDraft(ctx context.Context, input PerformerDraftInput, httpRequestOptions ...client.HTTPRequestOption) (*SubmitPerformerDraftPayload, error) { func (c *Client) SubmitPerformerDraft(ctx context.Context, input PerformerDraftInput, httpRequestOptions ...client.HTTPRequestOption) (*SubmitPerformerDraft, error) {
vars := map[string]interface{}{ vars := map[string]interface{}{
"input": input, "input": input,
} }
var res SubmitPerformerDraftPayload var res SubmitPerformerDraft
if err := c.Client.Post(ctx, SubmitPerformerDraftQuery, &res, vars, httpRequestOptions...); err != nil { if err := c.Client.Post(ctx, "SubmitPerformerDraft", SubmitPerformerDraftDocument, &res, vars, httpRequestOptions...); err != nil {
return nil, err return nil, err
} }

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"mime/multipart" "mime/multipart"
"net/http" "net/http"
"os" "os"
@@ -15,6 +16,8 @@ import (
"github.com/Yamashou/gqlgenc/client" "github.com/Yamashou/gqlgenc/client"
"github.com/Yamashou/gqlgenc/graphqljson" "github.com/Yamashou/gqlgenc/graphqljson"
"github.com/corona10/goimagehash" "github.com/corona10/goimagehash"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"github.com/stashapp/stash/pkg/fsutil" "github.com/stashapp/stash/pkg/fsutil"
"github.com/stashapp/stash/pkg/logger" "github.com/stashapp/stash/pkg/logger"
@@ -511,7 +514,8 @@ func enumToStringPtr(e fmt.Stringer, titleCase bool) *string {
if e != nil { if e != nil {
ret := strings.ReplaceAll(e.String(), "_", " ") ret := strings.ReplaceAll(e.String(), "_", " ")
if titleCase { if titleCase {
ret = strings.Title(strings.ToLower(ret)) c := cases.Title(language.Und)
ret = c.String(strings.ToLower(ret))
} }
return &ret return &ret
} }
@@ -928,8 +932,8 @@ func (c Client) SubmitSceneDraft(ctx context.Context, sceneID int, endpoint stri
} }
var id *string var id *string
var ret graphql.SubmitSceneDraftPayload var ret graphql.SubmitSceneDraft
err := c.submitDraft(ctx, graphql.SubmitSceneDraftQuery, draft, image, &ret) err := c.submitDraft(ctx, graphql.SubmitSceneDraftDocument, draft, image, &ret)
id = ret.SubmitSceneDraft.ID id = ret.SubmitSceneDraft.ID
return id, err return id, err
@@ -1005,8 +1009,8 @@ func (c Client) SubmitPerformerDraft(ctx context.Context, performer *models.Perf
} }
var id *string var id *string
var ret graphql.SubmitPerformerDraftPayload var ret graphql.SubmitPerformerDraft
err := c.submitDraft(ctx, graphql.SubmitPerformerDraftQuery, draft, image, &ret) err := c.submitDraft(ctx, graphql.SubmitPerformerDraftDocument, draft, image, &ret)
id = ret.SubmitPerformerDraft.ID id = ret.SubmitPerformerDraft.ID
return id, err return id, err
@@ -1059,7 +1063,12 @@ func (c *Client) submitDraft(ctx context.Context, query string, input interface{
} }
defer resp.Body.Close() defer resp.Body.Close()
if err := graphqljson.Unmarshal(resp.Body, ret); err != nil { responseBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
if err := graphqljson.UnmarshalData(responseBytes, ret); err != nil {
return err return err
} }

View File

@@ -1,3 +1,3 @@
/codegen/templates/data.go linguist-generated /codegen/templates/data.go linguist-generated
/example/dataloader/*_gen.go linguist-generated /_examples/dataloader/*_gen.go linguist-generated
generated.go linguist-generated generated.go linguist-generated

View File

@@ -1,14 +1,16 @@
/vendor /vendor
/docs/public /docs/public
/example/chat/node_modules /docs/.hugo_build.lock
/_examples/chat/node_modules
/integration/node_modules /integration/node_modules
/integration/schema-fetched.graphql /integration/schema-fetched.graphql
/example/chat/package-lock.json /_examples/chat/package-lock.json
/example/federation/package-lock.json /_examples/federation/package-lock.json
/example/federation/node_modules /_examples/federation/node_modules
/codegen/gen /codegen/gen
/gen /gen
/.vscode
.idea/ .idea/
*.test *.test
*.out *.out

View File

@@ -21,12 +21,12 @@ linters:
- gosimple - gosimple
- govet - govet
- ineffassign - ineffassign
- interfacer
- misspell - misspell
- nakedret - nakedret
- prealloc - prealloc
- staticcheck - staticcheck
- structcheck - structcheck
- typecheck
- unconvert - unconvert
- unused - unused
- varcheck - varcheck

8634
vendor/github.com/99designs/gqlgen/CHANGELOG.md generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@ Want to contribute to gqlgen? Here are some guidelines for how we accept help.
## Getting in Touch ## Getting in Touch
Our [gitter](https://gitter.im/gqlgen/Lobby) channel is the best place to ask questions or get advice on using gqlgen. Our [discord](https://discord.gg/DYEq3EMs4U) server is the best place to ask questions or get advice on using gqlgen.
## Reporting Bugs and Issues ## Reporting Bugs and Issues

View File

@@ -1,24 +1,42 @@
# gqlgen [![Continuous Integration](https://github.com/99designs/gqlgen/workflows/Continuous%20Integration/badge.svg)](https://github.com/99designs/gqlgen/actions) [![Read the Docs](https://badgen.net/badge/docs/available/green)](http://gqlgen.com/) [![GoDoc](https://godoc.org/github.com/99designs/gqlgen?status.svg)](https://godoc.org/github.com/99designs/gqlgen) ![gqlgen](https://user-images.githubusercontent.com/980499/133180111-d064b38c-6eb9-444b-a60f-7005a6e68222.png)
![gqlgen](https://user-images.githubusercontent.com/46195831/89802919-0bb8ef00-db2a-11ea-8ba4-88e7a58b2fd2.png)
# gqlgen [![Integration](https://github.com/99designs/gqlgen/actions/workflows/integration.yml/badge.svg)](https://github.com/99designs/gqlgen/actions) [![Coverage Status](https://coveralls.io/repos/github/99designs/gqlgen/badge.svg?branch=master)](https://coveralls.io/github/99designs/gqlgen?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/99designs/gqlgen)](https://goreportcard.com/report/github.com/99designs/gqlgen) [![Go Reference](https://pkg.go.dev/badge/github.com/99designs/gqlgen.svg)](https://pkg.go.dev/github.com/99designs/gqlgen) [![Read the Docs](https://badgen.net/badge/docs/available/green)](http://gqlgen.com/)
## What is gqlgen? ## What is gqlgen?
[gqlgen](https://github.com/99designs/gqlgen) is a Go library for building GraphQL servers without any fuss.<br/> [gqlgen](https://github.com/99designs/gqlgen) is a Go library for building GraphQL servers without any fuss.<br/>
- **gqlgen is based on a Schema first approach** — You get to Define your API using the GraphQL [Schema Definition Language](http://graphql.org/learn/schema/). - **gqlgen is based on a Schema first approach** — You get to Define your API using the GraphQL [Schema Definition Language](http://graphql.org/learn/schema/).
- **gqlgen priortizes Type safety** — You should never see `map[string]interface{}` here. - **gqlgen prioritizes Type safety** — You should never see `map[string]interface{}` here.
- **gqlgen enables Codegen** — We generate the boring bits, so you can focus on building your app quickly. - **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/) Still not convinced enough to use **gqlgen**? Compare **gqlgen** with other Go graphql [implementations](https://gqlgen.com/feature-comparison/)
## Getting Started ## Quick start
- To install gqlgen run the comand `go get github.com/99designs/gqlgen` in your project directory.<br/> 1. [Initialise a new go module](https://golang.org/doc/tutorial/create-module)
- You could initialize a new project using the recommended folder structure by running this command `go run github.com/99designs/gqlgen init`.
You could find a more comprehensive guide to help you get started [here](https://gqlgen.com/getting-started/).<br/> mkdir example
We also have a couple of real-world [examples](https://github.com/99designs/gqlgen/tree/master/example) that show how to GraphQL applicatons with **gqlgen** seamlessly, cd example
You can see these [examples](https://github.com/99designs/gqlgen/tree/master/example) here or visit [godoc](https://godoc.org/github.com/99designs/gqlgen). 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 ## Reporting Issues
@@ -85,6 +103,25 @@ func (r *userResolver) Friends(ctx context.Context, obj *User) ([]*User, error)
} }
``` ```
You can also use inline config with directives to achieve the same result
```graphql
directive @goModel(model: String, models: [String!]) on OBJECT
| INPUT_OBJECT
| SCALAR
| ENUM
| INTERFACE
| UNION
directive @goField(forceResolver: Boolean, name: String) on INPUT_FIELD_DEFINITION
| FIELD_DEFINITION
type User @goModel(model: "github.com/you/pkg/model.User") {
id: ID! @goField(name: "todoId")
friends: [User!]! @goField(forceResolver: true)
}
```
### Can I change the type of the ID from type String to Type Int? ### 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: Yes! You can by remapping it in config as seen below:
@@ -93,7 +130,7 @@ Yes! You can by remapping it in config as seen below:
models: models:
ID: # The GraphQL type ID is backed by ID: # The GraphQL type ID is backed by
model: model:
- github.com/99designs/gqlgen/graphql.IntID # An go integer - github.com/99designs/gqlgen/graphql.IntID # a go integer
- github.com/99designs/gqlgen/graphql.ID # or a go string - github.com/99designs/gqlgen/graphql.ID # or a go string
``` ```
@@ -103,7 +140,7 @@ first model in this list is used as the default type and it will always be used
- Generating models based on schema - Generating models based on schema
- As arguments in resolvers - As arguments in resolvers
There isnt any way around this, gqlgen has no way to know what you want in a given context. There isn't any way around this, gqlgen has no way to know what you want in a given context.
## Other Resources ## Other Resources

View File

@@ -0,0 +1,14 @@
# When gqlgen gets released, the following things need to happen
Assuming the next version is $NEW_VERSION=v0.16.0 or something like that.
1. Run the https://github.com/99designs/gqlgen/blob/master/bin/release:
```
./bin/release $NEW_VERSION
```
2. git-chglog -o CHANGELOG.md
3. git commit and push the CHANGELOG.md
4. Go to https://github.com/99designs/gqlgen/releases and draft new release, autogenerate the release notes, and Create a discussion for this release
5. Comment on the release discussion with any really important notes (breaking changes)
I used https://github.com/git-chglog/git-chglog to automate the changelog maintenance process for now. We could just as easily use go releaser to make the whole thing automated.

View File

@@ -15,7 +15,7 @@ There are also a bunch of tests in against the examples, feel free to take examp
These tests are **really** slow, because they need to run the whole codegen step. Use them very sparingly. If you can, find a way to unit test it instead. These tests are **really** slow, because they need to run the whole codegen step. Use them very sparingly. If you can, find a way to unit test it instead.
Take a look at `codegen/input_test.go` for an example. Take a look at `codegen/testserver/input_test.go` for an example.
### Testing introspection ### Testing introspection
@@ -31,7 +31,7 @@ in another terminal
```bash ```bash
cd integration cd integration
npm install npm install
SERVER_URL=http://localhost:8080/query ./node_modules/.bin/graphql get-schema ./node_modules/.bin/graphql-codegen
``` ```
will write the schema to `integration/schema-fetched.graphql`, compare that with `schema-expected.graphql` will write the schema to `integration/schema-fetched.graphql`, compare that with `schema-expected.graphql`

View File

@@ -1,6 +1,7 @@
package api package api
import ( import (
"fmt"
"syscall" "syscall"
"github.com/99designs/gqlgen/codegen" "github.com/99designs/gqlgen/codegen"
@@ -9,7 +10,6 @@ import (
"github.com/99designs/gqlgen/plugin/federation" "github.com/99designs/gqlgen/plugin/federation"
"github.com/99designs/gqlgen/plugin/modelgen" "github.com/99designs/gqlgen/plugin/modelgen"
"github.com/99designs/gqlgen/plugin/resolvergen" "github.com/99designs/gqlgen/plugin/resolvergen"
"github.com/pkg/errors"
) )
func Generate(cfg *config.Config, option ...Option) error { func Generate(cfg *config.Config, option ...Option) error {
@@ -40,7 +40,7 @@ func Generate(cfg *config.Config, option ...Option) error {
} }
if err := cfg.LoadSchema(); err != nil { if err := cfg.LoadSchema(); err != nil {
return errors.Wrap(err, "failed to load schema") return fmt.Errorf("failed to load schema: %w", err)
} }
for _, p := range plugins { for _, p := range plugins {
@@ -53,47 +53,53 @@ func Generate(cfg *config.Config, option ...Option) error {
// LoadSchema again now we have everything // LoadSchema again now we have everything
if err := cfg.LoadSchema(); err != nil { if err := cfg.LoadSchema(); err != nil {
return errors.Wrap(err, "failed to load schema") return fmt.Errorf("failed to load schema: %w", err)
} }
if err := cfg.Init(); err != nil { if err := cfg.Init(); err != nil {
return errors.Wrap(err, "generating core failed") return fmt.Errorf("generating core failed: %w", err)
} }
for _, p := range plugins { for _, p := range plugins {
if mut, ok := p.(plugin.ConfigMutator); ok { if mut, ok := p.(plugin.ConfigMutator); ok {
err := mut.MutateConfig(cfg) err := mut.MutateConfig(cfg)
if err != nil { if err != nil {
return errors.Wrap(err, p.Name()) return fmt.Errorf("%s: %w", p.Name(), err)
} }
} }
} }
// Merge again now that the generated models have been injected into the typemap // Merge again now that the generated models have been injected into the typemap
data, err := codegen.BuildData(cfg) data, err := codegen.BuildData(cfg)
if err != nil { if err != nil {
return errors.Wrap(err, "merging type systems failed") return fmt.Errorf("merging type systems failed: %w", err)
} }
if err = codegen.GenerateCode(data); err != nil { if err = codegen.GenerateCode(data); err != nil {
return errors.Wrap(err, "generating core failed") return fmt.Errorf("generating core failed: %w", err)
}
if !cfg.SkipModTidy {
if err = cfg.Packages.ModTidy(); err != nil {
return fmt.Errorf("tidy failed: %w", err)
}
} }
for _, p := range plugins { for _, p := range plugins {
if mut, ok := p.(plugin.CodeGenerator); ok { if mut, ok := p.(plugin.CodeGenerator); ok {
err := mut.GenerateCode(data) err := mut.GenerateCode(data)
if err != nil { if err != nil {
return errors.Wrap(err, p.Name()) return fmt.Errorf("%s: %w", p.Name(), err)
} }
} }
} }
if err = codegen.GenerateCode(data); err != nil { if err = codegen.GenerateCode(data); err != nil {
return errors.Wrap(err, "generating core failed") return fmt.Errorf("generating core failed: %w", err)
} }
if !cfg.SkipValidation { if !cfg.SkipValidation {
if err := validate(cfg); err != nil { if err := validate(cfg); err != nil {
return errors.Wrap(err, "validation failed") return fmt.Errorf("validation failed: %w", err)
} }
} }

View File

@@ -18,3 +18,30 @@ func AddPlugin(p plugin.Plugin) Option {
*plugins = append(*plugins, p) *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
}
}
}

View File

@@ -1,10 +0,0 @@
package cmd
import (
// Import and ignore the ambient imports listed below so dependency managers
// don't prune unused code for us. Both lists should be kept in sync.
_ "github.com/99designs/gqlgen/graphql"
_ "github.com/99designs/gqlgen/graphql/introspection"
_ "github.com/vektah/gqlparser/v2"
_ "github.com/vektah/gqlparser/v2/ast"
)

View File

@@ -1,43 +0,0 @@
package cmd
import (
"os"
"github.com/99designs/gqlgen/api"
"github.com/99designs/gqlgen/codegen/config"
"github.com/pkg/errors"
"github.com/urfave/cli/v2"
)
var genCmd = &cli.Command{
Name: "generate",
Usage: "generate a graphql server based on schema",
Flags: []cli.Flag{
&cli.BoolFlag{Name: "verbose, v", Usage: "show logs"},
&cli.StringFlag{Name: "config, c", Usage: "the config filename"},
},
Action: func(ctx *cli.Context) error {
var cfg *config.Config
var err error
if configFilename := ctx.String("config"); configFilename != "" {
cfg, err = config.LoadConfig(configFilename)
if err != nil {
return err
}
} else {
cfg, err = config.LoadConfigFromDefaultLocations()
if os.IsNotExist(errors.Cause(err)) {
cfg, err = config.LoadDefaultConfig()
}
if err != nil {
return err
}
}
if err = api.Generate(cfg); err != nil {
return err
}
return nil
},
}

View File

@@ -1,199 +0,0 @@
package cmd
import (
"bytes"
"fmt"
"html/template"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/99designs/gqlgen/api"
"github.com/99designs/gqlgen/codegen/config"
"github.com/99designs/gqlgen/internal/code"
"github.com/99designs/gqlgen/plugin/servergen"
"github.com/urfave/cli/v2"
)
var configTemplate = template.Must(template.New("name").Parse(
`# Where are all the schema files located? globs are supported eg src/**/*.graphqls
schema:
- graph/*.graphqls
# Where should the generated server code go?
exec:
filename: graph/generated/generated.go
package: generated
# Uncomment to enable federation
# federation:
# filename: graph/generated/federation.go
# package: generated
# Where should any generated models go?
model:
filename: graph/model/models_gen.go
package: model
# Where should the resolver implementations go?
resolver:
layout: follow-schema
dir: graph
package: graph
# Optional: turn on use ` + "`" + `gqlgen:"fieldName"` + "`" + ` tags in your models
# struct_tag: json
# Optional: turn on to use []Thing instead of []*Thing
# omit_slice_element_pointers: false
# Optional: set to speed up generation time by not performing a final validation pass.
# skip_validation: true
# gqlgen will search for any type names in the schema in these go packages
# if they match it will use them, otherwise it will generate them.
autobind:
- "{{.}}/graph/model"
# This section declares type mapping between the GraphQL and go type systems
#
# The first line in each type will be used as defaults for resolver arguments and
# modelgen, the others will be allowed when binding to fields. Configure them to
# your liking
models:
ID:
model:
- github.com/99designs/gqlgen/graphql.ID
- github.com/99designs/gqlgen/graphql.Int
- github.com/99designs/gqlgen/graphql.Int64
- github.com/99designs/gqlgen/graphql.Int32
Int:
model:
- github.com/99designs/gqlgen/graphql.Int
- github.com/99designs/gqlgen/graphql.Int64
- github.com/99designs/gqlgen/graphql.Int32
`))
var schemaDefault = `# GraphQL schema example
#
# https://gqlgen.com/getting-started/
type Todo {
id: ID!
text: String!
done: Boolean!
user: User!
}
type User {
id: ID!
name: String!
}
type Query {
todos: [Todo!]!
}
input NewTodo {
text: String!
userId: String!
}
type Mutation {
createTodo(input: NewTodo!): Todo!
}
`
var initCmd = &cli.Command{
Name: "init",
Usage: "create a new gqlgen project",
Flags: []cli.Flag{
&cli.BoolFlag{Name: "verbose, v", Usage: "show logs"},
&cli.StringFlag{Name: "config, c", Usage: "the config filename"},
&cli.StringFlag{Name: "server", Usage: "where to write the server stub to", Value: "server.go"},
&cli.StringFlag{Name: "schema", Usage: "where to write the schema stub to", Value: "graph/schema.graphqls"},
},
Action: func(ctx *cli.Context) error {
configFilename := ctx.String("config")
serverFilename := ctx.String("server")
pkgName := code.ImportPathForDir(".")
if pkgName == "" {
return fmt.Errorf("unable to determine import path for current directory, you probably need to run go mod init first")
}
if err := initSchema(ctx.String("schema")); err != nil {
return err
}
if !configExists(configFilename) {
if err := initConfig(configFilename, pkgName); err != nil {
return err
}
}
GenerateGraphServer(serverFilename)
return nil
},
}
func GenerateGraphServer(serverFilename string) {
cfg, err := config.LoadConfigFromDefaultLocations()
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
}
if err := api.Generate(cfg, api.AddPlugin(servergen.New(serverFilename))); err != nil {
fmt.Fprintln(os.Stderr, err.Error())
}
fmt.Fprintf(os.Stdout, "Exec \"go run ./%s\" to start GraphQL server\n", serverFilename)
}
func configExists(configFilename string) bool {
var cfg *config.Config
if configFilename != "" {
cfg, _ = config.LoadConfig(configFilename)
} else {
cfg, _ = config.LoadConfigFromDefaultLocations()
}
return cfg != nil
}
func initConfig(configFilename string, pkgName string) error {
if configFilename == "" {
configFilename = "gqlgen.yml"
}
if err := os.MkdirAll(filepath.Dir(configFilename), 0755); err != nil {
return fmt.Errorf("unable to create config dir: " + err.Error())
}
var buf bytes.Buffer
if err := configTemplate.Execute(&buf, pkgName); err != nil {
panic(err)
}
if err := ioutil.WriteFile(configFilename, buf.Bytes(), 0644); err != nil {
return fmt.Errorf("unable to write cfg file: " + err.Error())
}
return nil
}
func initSchema(schemaFilename string) error {
_, err := os.Stat(schemaFilename)
if !os.IsNotExist(err) {
return nil
}
if err := os.MkdirAll(filepath.Dir(schemaFilename), 0755); err != nil {
return fmt.Errorf("unable to create schema dir: " + err.Error())
}
if err = ioutil.WriteFile(schemaFilename, []byte(strings.TrimSpace(schemaDefault)), 0644); err != nil {
return fmt.Errorf("unable to write schema file: " + err.Error())
}
return nil
}

View File

@@ -1,45 +0,0 @@
package cmd
import (
"fmt"
"io/ioutil"
"log"
"os"
"github.com/99designs/gqlgen/graphql"
"github.com/urfave/cli/v2"
// Required since otherwise dep will prune away these unused packages before codegen has a chance to run
_ "github.com/99designs/gqlgen/graphql/handler"
_ "github.com/99designs/gqlgen/handler"
)
func Execute() {
app := cli.NewApp()
app.Name = "gqlgen"
app.Usage = genCmd.Usage
app.Description = "This is a library for quickly creating strictly typed graphql servers in golang. See https://gqlgen.com/ for a getting started guide."
app.HideVersion = true
app.Flags = genCmd.Flags
app.Version = graphql.Version
app.Before = func(context *cli.Context) error {
if context.Bool("verbose") {
log.SetFlags(0)
} else {
log.SetOutput(ioutil.Discard)
}
return nil
}
app.Action = genCmd.Action
app.Commands = []*cli.Command{
genCmd,
initCmd,
versionCmd,
}
if err := app.Run(os.Args); err != nil {
fmt.Fprint(os.Stderr, err.Error())
os.Exit(1)
}
}

View File

@@ -1,17 +0,0 @@
package cmd
import (
"fmt"
"github.com/99designs/gqlgen/graphql"
"github.com/urfave/cli/v2"
)
var versionCmd = &cli.Command{
Name: "version",
Usage: "print the version string",
Action: func(ctx *cli.Context) error {
fmt.Println(graphql.Version)
return nil
},
}

View File

@@ -7,7 +7,6 @@ import (
"github.com/99designs/gqlgen/codegen/config" "github.com/99designs/gqlgen/codegen/config"
"github.com/99designs/gqlgen/codegen/templates" "github.com/99designs/gqlgen/codegen/templates"
"github.com/pkg/errors"
"github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/ast"
) )
@@ -67,14 +66,14 @@ func (b *builder) buildArg(obj *Object, arg *ast.ArgumentDefinition) (*FieldArgu
if arg.DefaultValue != nil { if arg.DefaultValue != nil {
newArg.Default, err = arg.DefaultValue.Value(nil) newArg.Default, err = arg.DefaultValue.Value(nil)
if err != nil { if err != nil {
return nil, errors.Errorf("default value is not valid: %s", err.Error()) return nil, fmt.Errorf("default value is not valid: %w", err)
} }
} }
return &newArg, nil return &newArg, nil
} }
func (b *builder) bindArgs(field *Field, params *types.Tuple) error { func (b *builder) bindArgs(field *Field, params *types.Tuple) ([]*FieldArgument, error) {
var newArgs []*FieldArgument var newArgs []*FieldArgument
nextArg: nextArg:
@@ -84,7 +83,7 @@ nextArg:
if strings.EqualFold(oldArg.Name, param.Name()) { if strings.EqualFold(oldArg.Name, param.Name()) {
tr, err := b.Binder.TypeReference(oldArg.Type, param.Type()) tr, err := b.Binder.TypeReference(oldArg.Type, param.Type())
if err != nil { if err != nil {
return err return nil, err
} }
oldArg.TypeReference = tr oldArg.TypeReference = tr
@@ -94,11 +93,10 @@ nextArg:
} }
// no matching arg found, abort // no matching arg found, abort
return fmt.Errorf("arg %s not in schema", param.Name()) return nil, fmt.Errorf("arg %s not in schema", param.Name())
} }
field.Args = newArgs return newArgs, nil
return nil
} }
func (a *Data) Args() map[string][]*FieldArgument { func (a *Data) Args() map[string][]*FieldArgument {
@@ -111,7 +109,7 @@ func (a *Data) Args() map[string][]*FieldArgument {
} }
} }
for _, d := range a.Directives { for _, d := range a.Directives() {
if len(d.Args) > 0 { if len(d.Args) > 0 {
ret[d.ArgsFunc()] = d.Args ret[d.ArgsFunc()] = d.Args
} }

View File

@@ -5,13 +5,13 @@ func (ec *executionContext) {{ $name }}(ctx context.Context, rawArgs map[string]
{{- range $i, $arg := . }} {{- range $i, $arg := . }}
var arg{{$i}} {{ $arg.TypeReference.GO | ref}} var arg{{$i}} {{ $arg.TypeReference.GO | ref}}
if tmp, ok := rawArgs[{{$arg.Name|quote}}]; ok { if tmp, ok := rawArgs[{{$arg.Name|quote}}]; ok {
ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField({{$arg.Name|quote}})) ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField({{$arg.Name|quote}}))
{{- if $arg.ImplDirectives }} {{- if $arg.ImplDirectives }}
directive0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, tmp) } directive0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, tmp) }
{{ template "implDirectives" $arg }} {{ template "implDirectives" $arg }}
tmp, err = directive{{$arg.ImplDirectives|len}}(ctx) tmp, err = directive{{$arg.ImplDirectives|len}}(ctx)
if err != nil { if err != nil {
return nil, err return nil, graphql.ErrorOnPath(ctx, err)
} }
if data, ok := tmp.({{ $arg.TypeReference.GO | ref }}) ; ok { if data, ok := tmp.({{ $arg.TypeReference.GO | ref }}) ; ok {
arg{{$i}} = data arg{{$i}} = data
@@ -20,7 +20,7 @@ func (ec *executionContext) {{ $name }}(ctx context.Context, rawArgs map[string]
arg{{$i}} = nil arg{{$i}} = nil
{{- end }} {{- end }}
} else { } else {
return nil, fmt.Errorf(`unexpected type %T from directive, should be {{ $arg.TypeReference.GO }}`, tmp) return nil, graphql.ErrorOnPath(ctx, fmt.Errorf(`unexpected type %T from directive, should be {{ $arg.TypeReference.GO }}`, tmp))
} }
{{- else }} {{- else }}
arg{{$i}}, err = ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, tmp) arg{{$i}}, err = ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, tmp)

View File

@@ -1,16 +1,20 @@
package config package config
import ( import (
"errors"
"fmt" "fmt"
"go/token" "go/token"
"go/types" "go/types"
"golang.org/x/tools/go/packages"
"github.com/99designs/gqlgen/codegen/templates" "github.com/99designs/gqlgen/codegen/templates"
"github.com/99designs/gqlgen/internal/code" "github.com/99designs/gqlgen/internal/code"
"github.com/pkg/errors"
"github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/ast"
) )
var ErrTypeNotFound = errors.New("unable to find type")
// Binder connects graphql types to golang types using static analysis // Binder connects graphql types to golang types using static analysis
type Binder struct { type Binder struct {
pkgs *code.Packages pkgs *code.Packages
@@ -18,6 +22,7 @@ type Binder struct {
cfg *Config cfg *Config
References []*TypeReference References []*TypeReference
SawInvalid bool SawInvalid bool
objectCache map[string]map[string]types.Object
} }
func (c *Config) NewBinder() *Binder { func (c *Config) NewBinder() *Binder {
@@ -76,8 +81,10 @@ func (b *Binder) FindType(pkgName string, typeName string) (types.Type, error) {
return obj.Type(), nil return obj.Type(), nil
} }
var MapType = types.NewMap(types.Typ[types.String], types.NewInterfaceType(nil, nil).Complete()) var (
var InterfaceType = types.NewInterfaceType(nil, nil) 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) { func (b *Binder) DefaultUserObject(name string) (types.Type, error) {
models := b.cfg.Models[name].Model models := b.cfg.Models[name].Model
@@ -110,56 +117,68 @@ func (b *Binder) FindObject(pkgName string, typeName string) (types.Object, erro
if pkgName == "" { if pkgName == "" {
return nil, fmt.Errorf("package cannot be nil") return nil, fmt.Errorf("package cannot be nil")
} }
fullName := typeName
if pkgName != "" {
fullName = pkgName + "." + typeName
}
pkg := b.pkgs.LoadWithTypes(pkgName) pkg := b.pkgs.LoadWithTypes(pkgName)
if pkg == nil { if pkg == nil {
return nil, errors.Errorf("required package was not loaded: %s", fullName) err := b.pkgs.Errors()
if err != nil {
return nil, fmt.Errorf("package could not be loaded: %s.%s: %w", pkgName, typeName, err)
}
return nil, fmt.Errorf("required package was not loaded: %s.%s", pkgName, typeName)
}
if b.objectCache == nil {
b.objectCache = make(map[string]map[string]types.Object, b.pkgs.Count())
}
defsIndex, ok := b.objectCache[pkgName]
if !ok {
defsIndex = indexDefs(pkg)
b.objectCache[pkgName] = defsIndex
} }
// function based marshalers take precedence // 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 { for astNode, def := range pkg.TypesInfo.Defs {
// only look at defs in the top scope // only look at defs in the top scope
if def == nil || def.Parent() == nil || def.Parent() != pkg.Types.Scope() { if def == nil {
continue
}
parent := def.Parent()
if parent == nil || parent != scope {
continue continue
} }
if astNode.Name == "Marshal"+typeName { if _, ok := res[astNode.Name]; !ok {
return def, nil // The above check may not be really needed, it is only here to have a consistent behavior with
// previous implementation of FindObject() function which only honored the first inclusion of a def.
// If this is still needed, we can consider something like sync.Map.LoadOrStore() to avoid two lookups.
res[astNode.Name] = def
} }
} }
// then look for types directly return res
for astNode, def := range pkg.TypesInfo.Defs {
// only look at defs in the top scope
if def == nil || def.Parent() == nil || def.Parent() != pkg.Types.Scope() {
continue
}
if astNode.Name == typeName {
return def, nil
}
}
return nil, errors.Errorf("unable to find type %s\n", fullName)
} }
func (b *Binder) PointerTo(ref *TypeReference) *TypeReference { func (b *Binder) PointerTo(ref *TypeReference) *TypeReference {
newRef := &TypeReference{ newRef := *ref
GO: types.NewPointer(ref.GO), newRef.GO = types.NewPointer(ref.GO)
GQL: ref.GQL, b.References = append(b.References, &newRef)
CastType: ref.CastType, return &newRef
Definition: ref.Definition,
Unmarshaler: ref.Unmarshaler,
Marshaler: ref.Marshaler,
IsMarshaler: ref.IsMarshaler,
}
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. // TypeReference is used by args and field types. The Definition can refer to both input and output types.
@@ -172,33 +191,21 @@ type TypeReference struct {
Marshaler *types.Func // When using external marshalling functions this will point to the Marshal function 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 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 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 { func (ref *TypeReference) Elem() *TypeReference {
if p, isPtr := ref.GO.(*types.Pointer); isPtr { if p, isPtr := ref.GO.(*types.Pointer); isPtr {
return &TypeReference{ newRef := *ref
GO: p.Elem(), newRef.GO = p.Elem()
Target: ref.Target, return &newRef
GQL: ref.GQL,
CastType: ref.CastType,
Definition: ref.Definition,
Unmarshaler: ref.Unmarshaler,
Marshaler: ref.Marshaler,
IsMarshaler: ref.IsMarshaler,
}
} }
if ref.IsSlice() { if ref.IsSlice() {
return &TypeReference{ newRef := *ref
GO: ref.GO.(*types.Slice).Elem(), newRef.GO = ref.GO.(*types.Slice).Elem()
Target: ref.Target, newRef.GQL = ref.GQL.Elem
GQL: ref.GQL.Elem, return &newRef
CastType: ref.CastType,
Definition: ref.Definition,
Unmarshaler: ref.Unmarshaler,
Marshaler: ref.Marshaler,
IsMarshaler: ref.IsMarshaler,
}
} }
return nil return nil
} }
@@ -208,6 +215,16 @@ func (t *TypeReference) IsPtr() bool {
return isPtr 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 { func (t *TypeReference) IsNilable() bool {
return IsNilable(t.GO) return IsNilable(t.GO)
} }
@@ -217,6 +234,14 @@ func (t *TypeReference) IsSlice() bool {
return t.GQL.Elem != nil && isSlice 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 { func (t *TypeReference) IsNamed() bool {
_, isSlice := t.GO.(*types.Named) _, isSlice := t.GO.(*types.Named)
return isSlice return isSlice
@@ -232,12 +257,12 @@ func (t *TypeReference) IsScalar() bool {
} }
func (t *TypeReference) UniquenessKey() string { func (t *TypeReference) UniquenessKey() string {
var nullability = "O" nullability := "O"
if t.GQL.NonNull { if t.GQL.NonNull {
nullability = "N" nullability = "N"
} }
var elemNullability = "" elemNullability := ""
if t.GQL.Elem != nil && t.GQL.Elem.NonNull { if t.GQL.Elem != nil && t.GQL.Elem.NonNull {
// Fix for #896 // Fix for #896
elemNullability = "ᚄ" elemNullability = "ᚄ"
@@ -351,8 +376,13 @@ func (b *Binder) TypeReference(schemaType *ast.Type, bindTarget types.Type) (ret
if fun, isFunc := obj.(*types.Func); isFunc { if fun, isFunc := obj.(*types.Func); isFunc {
ref.GO = fun.Type().(*types.Signature).Params().At(0).Type() 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.Marshaler = fun
ref.Unmarshaler = types.NewFunc(0, fun.Pkg(), "Unmarshal"+typeName, nil) 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") { } else if hasMethod(obj.Type(), "MarshalGQL") && hasMethod(obj.Type(), "UnmarshalGQL") {
ref.GO = obj.Type() ref.GO = obj.Type()
ref.IsMarshaler = true ref.IsMarshaler = true

View File

@@ -10,7 +10,6 @@ import (
"strings" "strings"
"github.com/99designs/gqlgen/internal/code" "github.com/99designs/gqlgen/internal/code"
"github.com/pkg/errors"
"github.com/vektah/gqlparser/v2" "github.com/vektah/gqlparser/v2"
"github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/ast"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
@@ -18,7 +17,7 @@ import (
type Config struct { type Config struct {
SchemaFilename StringList `yaml:"schema,omitempty"` SchemaFilename StringList `yaml:"schema,omitempty"`
Exec PackageConfig `yaml:"exec"` Exec ExecConfig `yaml:"exec"`
Model PackageConfig `yaml:"model,omitempty"` Model PackageConfig `yaml:"model,omitempty"`
Federation PackageConfig `yaml:"federation,omitempty"` Federation PackageConfig `yaml:"federation,omitempty"`
Resolver ResolverConfig `yaml:"resolver,omitempty"` Resolver ResolverConfig `yaml:"resolver,omitempty"`
@@ -28,11 +27,12 @@ type Config struct {
Directives map[string]DirectiveConfig `yaml:"directives,omitempty"` Directives map[string]DirectiveConfig `yaml:"directives,omitempty"`
OmitSliceElementPointers bool `yaml:"omit_slice_element_pointers,omitempty"` OmitSliceElementPointers bool `yaml:"omit_slice_element_pointers,omitempty"`
SkipValidation bool `yaml:"skip_validation,omitempty"` SkipValidation bool `yaml:"skip_validation,omitempty"`
SkipModTidy bool `yaml:"skip_mod_tidy,omitempty"`
Sources []*ast.Source `yaml:"-"` Sources []*ast.Source `yaml:"-"`
Packages *code.Packages `yaml:"-"` Packages *code.Packages `yaml:"-"`
Schema *ast.Schema `yaml:"-"` Schema *ast.Schema `yaml:"-"`
// Deprecated use Federation instead. Will be removed next release // Deprecated: use Federation instead. Will be removed next release
Federated bool `yaml:"federated,omitempty"` Federated bool `yaml:"federated,omitempty"`
} }
@@ -43,7 +43,7 @@ func DefaultConfig() *Config {
return &Config{ return &Config{
SchemaFilename: StringList{"schema.graphql"}, SchemaFilename: StringList{"schema.graphql"},
Model: PackageConfig{Filename: "models_gen.go"}, Model: PackageConfig{Filename: "models_gen.go"},
Exec: PackageConfig{Filename: "generated.go"}, Exec: ExecConfig{Filename: "generated.go"},
Directives: map[string]DirectiveConfig{}, Directives: map[string]DirectiveConfig{},
Models: TypeMap{}, Models: TypeMap{},
} }
@@ -59,7 +59,7 @@ func LoadDefaultConfig() (*Config, error) {
var schemaRaw []byte var schemaRaw []byte
schemaRaw, err = ioutil.ReadFile(filename) schemaRaw, err = ioutil.ReadFile(filename)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "unable to open schema") return nil, fmt.Errorf("unable to open schema: %w", err)
} }
config.Sources = append(config.Sources, &ast.Source{Name: filename, Input: string(schemaRaw)}) config.Sources = append(config.Sources, &ast.Source{Name: filename, Input: string(schemaRaw)})
@@ -78,7 +78,7 @@ func LoadConfigFromDefaultLocations() (*Config, error) {
err = os.Chdir(filepath.Dir(cfgFile)) err = os.Chdir(filepath.Dir(cfgFile))
if err != nil { if err != nil {
return nil, errors.Wrap(err, "unable to enter config dir") return nil, fmt.Errorf("unable to enter config dir: %w", err)
} }
return LoadConfig(cfgFile) return LoadConfig(cfgFile)
} }
@@ -96,17 +96,28 @@ func LoadConfig(filename string) (*Config, error) {
b, err := ioutil.ReadFile(filename) b, err := ioutil.ReadFile(filename)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "unable to read config") return nil, fmt.Errorf("unable to read config: %w", err)
} }
if err := yaml.UnmarshalStrict(b, config); err != nil { if err := yaml.UnmarshalStrict(b, config); err != nil {
return nil, errors.Wrap(err, "unable to parse config") return nil, fmt.Errorf("unable to parse config: %w", err)
} }
if err := CompleteConfig(config); err != nil {
return nil, err
}
return config, nil
}
// CompleteConfig fills in the schema and other values to a config loaded from
// YAML.
func CompleteConfig(config *Config) error {
defaultDirectives := map[string]DirectiveConfig{ defaultDirectives := map[string]DirectiveConfig{
"skip": {SkipRuntime: true}, "skip": {SkipRuntime: true},
"include": {SkipRuntime: true}, "include": {SkipRuntime: true},
"deprecated": {SkipRuntime: true}, "deprecated": {SkipRuntime: true},
"specifiedBy": {SkipRuntime: true},
} }
for key, value := range defaultDirectives { for key, value := range defaultDirectives {
@@ -140,12 +151,13 @@ func LoadConfig(filename string) (*Config, error) {
return nil return nil
}); err != nil { }); err != nil {
return nil, errors.Wrapf(err, "failed to walk schema at root %s", pathParts[0]) return fmt.Errorf("failed to walk schema at root %s: %w", pathParts[0], err)
} }
} else { } else {
var err error
matches, err = filepath.Glob(f) matches, err = filepath.Glob(f)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "failed to glob schema filename %s", f) return fmt.Errorf("failed to glob schema filename %s: %w", f, err)
} }
} }
@@ -163,13 +175,12 @@ func LoadConfig(filename string) (*Config, error) {
var schemaRaw []byte var schemaRaw []byte
schemaRaw, err = ioutil.ReadFile(filename) schemaRaw, err = ioutil.ReadFile(filename)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "unable to open schema") return fmt.Errorf("unable to open schema: %w", err)
} }
config.Sources = append(config.Sources, &ast.Source{Name: filename, Input: string(schemaRaw)}) config.Sources = append(config.Sources, &ast.Source{Name: filename, Input: string(schemaRaw)})
} }
return nil
return config, nil
} }
func (c *Config) Init() error { func (c *Config) Init() error {
@@ -194,15 +205,8 @@ func (c *Config) Init() error {
} }
c.injectBuiltins() c.injectBuiltins()
// prefetch all packages in one big packages.Load call // prefetch all packages in one big packages.Load call
pkgs := []string{ c.Packages.LoadAll(c.packageList()...)
"github.com/99designs/gqlgen/graphql",
"github.com/99designs/gqlgen/graphql/introspection",
}
pkgs = append(pkgs, c.Models.ReferencedPackages()...)
pkgs = append(pkgs, c.AutoBind...)
c.Packages.LoadAll(pkgs...)
// check everything is valid on the way out // check everything is valid on the way out
err = c.check() err = c.check()
@@ -213,6 +217,20 @@ func (c *Config) Init() error {
return nil 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 { func (c *Config) injectTypesFromSchema() error {
c.Directives["goModel"] = DirectiveConfig{ c.Directives["goModel"] = DirectiveConfig{
SkipRuntime: true, SkipRuntime: true,
@@ -222,6 +240,10 @@ func (c *Config) injectTypesFromSchema() error {
SkipRuntime: true, SkipRuntime: true,
} }
c.Directives["goTag"] = DirectiveConfig{
SkipRuntime: true,
}
for _, schemaType := range c.Schema.Types { for _, schemaType := range c.Schema.Types {
if schemaType == c.Schema.Query || schemaType == c.Schema.Mutation || schemaType == c.Schema.Subscription { if schemaType == c.Schema.Query || schemaType == c.Schema.Mutation || schemaType == c.Schema.Subscription {
continue continue
@@ -333,10 +355,10 @@ func (c *Config) check() error {
fileList := map[string][]FilenamePackage{} fileList := map[string][]FilenamePackage{}
if err := c.Models.Check(); err != nil { if err := c.Models.Check(); err != nil {
return errors.Wrap(err, "config.models") return fmt.Errorf("config.models: %w", err)
} }
if err := c.Exec.Check(); err != nil { if err := c.Exec.Check(); err != nil {
return errors.Wrap(err, "config.exec") return fmt.Errorf("config.exec: %w", err)
} }
fileList[c.Exec.ImportPath()] = append(fileList[c.Exec.ImportPath()], FilenamePackage{ fileList[c.Exec.ImportPath()] = append(fileList[c.Exec.ImportPath()], FilenamePackage{
Filename: c.Exec.Filename, Filename: c.Exec.Filename,
@@ -346,7 +368,7 @@ func (c *Config) check() error {
if c.Model.IsDefined() { if c.Model.IsDefined() {
if err := c.Model.Check(); err != nil { if err := c.Model.Check(); err != nil {
return errors.Wrap(err, "config.model") return fmt.Errorf("config.model: %w", err)
} }
fileList[c.Model.ImportPath()] = append(fileList[c.Model.ImportPath()], FilenamePackage{ fileList[c.Model.ImportPath()] = append(fileList[c.Model.ImportPath()], FilenamePackage{
Filename: c.Model.Filename, Filename: c.Model.Filename,
@@ -356,7 +378,7 @@ func (c *Config) check() error {
} }
if c.Resolver.IsDefined() { if c.Resolver.IsDefined() {
if err := c.Resolver.Check(); err != nil { if err := c.Resolver.Check(); err != nil {
return errors.Wrap(err, "config.resolver") return fmt.Errorf("config.resolver: %w", err)
} }
fileList[c.Resolver.ImportPath()] = append(fileList[c.Resolver.ImportPath()], FilenamePackage{ fileList[c.Resolver.ImportPath()] = append(fileList[c.Resolver.ImportPath()], FilenamePackage{
Filename: c.Resolver.Filename, Filename: c.Resolver.Filename,
@@ -366,7 +388,7 @@ func (c *Config) check() error {
} }
if c.Federation.IsDefined() { if c.Federation.IsDefined() {
if err := c.Federation.Check(); err != nil { if err := c.Federation.Check(); err != nil {
return errors.Wrap(err, "config.federation") return fmt.Errorf("config.federation: %w", err)
} }
fileList[c.Federation.ImportPath()] = append(fileList[c.Federation.ImportPath()], FilenamePackage{ fileList[c.Federation.ImportPath()] = append(fileList[c.Federation.ImportPath()], FilenamePackage{
Filename: c.Federation.Filename, Filename: c.Federation.Filename,
@@ -470,7 +492,7 @@ func inStrSlice(haystack []string, needle string) bool {
func findCfg() (string, error) { func findCfg() (string, error) {
dir, err := os.Getwd() dir, err := os.Getwd()
if err != nil { if err != nil {
return "", errors.Wrap(err, "unable to get working dir to findCfg") return "", fmt.Errorf("unable to get working dir to findCfg: %w", err)
} }
cfg := findCfgInDir(dir) cfg := findCfgInDir(dir)
@@ -510,7 +532,7 @@ func (c *Config) autobind() error {
} }
for i, p := range ps { for i, p := range ps {
if p == nil { if p == nil || p.Module == nil {
return fmt.Errorf("unable to load %s - make sure you're using an import path to a package that exists", c.AutoBind[i]) 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 { if t := p.Types.Scope().Lookup(t.Name); t != nil {
@@ -554,7 +576,7 @@ func (c *Config) injectBuiltins() {
"__EnumValue": {Model: StringList{"github.com/99designs/gqlgen/graphql/introspection.EnumValue"}}, "__EnumValue": {Model: StringList{"github.com/99designs/gqlgen/graphql/introspection.EnumValue"}},
"__InputValue": {Model: StringList{"github.com/99designs/gqlgen/graphql/introspection.InputValue"}}, "__InputValue": {Model: StringList{"github.com/99designs/gqlgen/graphql/introspection.InputValue"}},
"__Schema": {Model: StringList{"github.com/99designs/gqlgen/graphql/introspection.Schema"}}, "__Schema": {Model: StringList{"github.com/99designs/gqlgen/graphql/introspection.Schema"}},
"Float": {Model: StringList{"github.com/99designs/gqlgen/graphql.Float"}}, "Float": {Model: StringList{"github.com/99designs/gqlgen/graphql.FloatContext"}},
"String": {Model: StringList{"github.com/99designs/gqlgen/graphql.String"}}, "String": {Model: StringList{"github.com/99designs/gqlgen/graphql.String"}},
"Boolean": {Model: StringList{"github.com/99designs/gqlgen/graphql.Boolean"}}, "Boolean": {Model: StringList{"github.com/99designs/gqlgen/graphql.Boolean"}},
"Int": {Model: StringList{ "Int": {Model: StringList{

View File

@@ -0,0 +1,97 @@
package config
import (
"fmt"
"go/types"
"path/filepath"
"strings"
"github.com/99designs/gqlgen/internal/code"
)
type ExecConfig struct {
Package string `yaml:"package,omitempty"`
Layout ExecLayout `yaml:"layout,omitempty"` // Default: single-file
// Only for single-file layout:
Filename string `yaml:"filename,omitempty"`
// Only for follow-schema layout:
FilenameTemplate string `yaml:"filename_template,omitempty"` // String template with {name} as placeholder for base name.
DirName string `yaml:"dir"`
}
type ExecLayout string
var (
// Write all generated code to a single file.
ExecLayoutSingleFile ExecLayout = "single-file"
// Write generated code to a directory, generating one Go source file for each GraphQL schema file.
ExecLayoutFollowSchema ExecLayout = "follow-schema"
)
func (r *ExecConfig) Check() error {
if r.Layout == "" {
r.Layout = ExecLayoutSingleFile
}
switch r.Layout {
case ExecLayoutSingleFile:
if r.Filename == "" {
return fmt.Errorf("filename must be specified when using single-file layout")
}
if !strings.HasSuffix(r.Filename, ".go") {
return fmt.Errorf("filename should be path to a go source file when using single-file layout")
}
r.Filename = abs(r.Filename)
case ExecLayoutFollowSchema:
if r.DirName == "" {
return fmt.Errorf("dir must be specified when using follow-schema layout")
}
r.DirName = abs(r.DirName)
default:
return fmt.Errorf("invalid layout %s", r.Layout)
}
if strings.ContainsAny(r.Package, "./\\") {
return fmt.Errorf("package should be the output package name only, do not include the output filename")
}
if r.Package == "" && r.Dir() != "" {
r.Package = code.NameForDir(r.Dir())
}
return nil
}
func (r *ExecConfig) ImportPath() string {
if r.Dir() == "" {
return ""
}
return code.ImportPathForDir(r.Dir())
}
func (r *ExecConfig) Dir() string {
switch r.Layout {
case ExecLayoutSingleFile:
if r.Filename == "" {
return ""
}
return filepath.Dir(r.Filename)
case ExecLayoutFollowSchema:
return abs(r.DirName)
default:
panic("invalid layout " + r.Layout)
}
}
func (r *ExecConfig) Pkg() *types.Package {
if r.Dir() == "" {
return nil
}
return types.NewPackage(r.ImportPath(), r.Package)
}
func (r *ExecConfig) IsDefined() bool {
return r.Filename != "" || r.DirName != ""
}

View File

@@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"sort" "sort"
"github.com/pkg/errors"
"github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/ast"
"github.com/99designs/gqlgen/codegen/config" "github.com/99designs/gqlgen/codegen/config"
@@ -15,7 +14,13 @@ import (
type Data struct { type Data struct {
Config *config.Config Config *config.Config
Schema *ast.Schema Schema *ast.Schema
Directives DirectiveList // 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 Objects Objects
Inputs Objects Inputs Objects
Interfaces map[string]*Interface Interfaces map[string]*Interface
@@ -34,7 +39,24 @@ type builder struct {
Directives map[string]*Directive 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) { func BuildData(cfg *config.Config) (*Data, error) {
// We reload all packages to allow packages to be compared correctly.
cfg.ReloadAllPackages()
b := builder{ b := builder{
Config: cfg, Config: cfg,
Schema: cfg.Schema, Schema: cfg.Schema,
@@ -57,7 +79,7 @@ func BuildData(cfg *config.Config) (*Data, error) {
s := Data{ s := Data{
Config: cfg, Config: cfg,
Directives: dataDirectives, AllDirectives: dataDirectives,
Schema: b.Schema, Schema: b.Schema,
Interfaces: map[string]*Interface{}, Interfaces: map[string]*Interface{},
} }
@@ -67,14 +89,14 @@ func BuildData(cfg *config.Config) (*Data, error) {
case ast.Object: case ast.Object:
obj, err := b.buildObject(schemaType) obj, err := b.buildObject(schemaType)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "unable to build object definition") return nil, fmt.Errorf("unable to build object definition: %w", err)
} }
s.Objects = append(s.Objects, obj) s.Objects = append(s.Objects, obj)
case ast.InputObject: case ast.InputObject:
input, err := b.buildObject(schemaType) input, err := b.buildObject(schemaType)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "unable to build input definition") return nil, fmt.Errorf("unable to build input definition: %w", err)
} }
s.Inputs = append(s.Inputs, input) s.Inputs = append(s.Inputs, input)
@@ -82,7 +104,7 @@ func BuildData(cfg *config.Config) (*Data, error) {
case ast.Union, ast.Interface: case ast.Union, ast.Interface:
s.Interfaces[schemaType.Name], err = b.buildInterface(schemaType) s.Interfaces[schemaType.Name], err = b.buildInterface(schemaType)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "unable to bind to interface") return nil, fmt.Errorf("unable to bind to interface: %w", err)
} }
} }
} }

View File

@@ -6,7 +6,6 @@ import (
"strings" "strings"
"github.com/99designs/gqlgen/codegen/templates" "github.com/99designs/gqlgen/codegen/templates"
"github.com/pkg/errors"
"github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/ast"
) )
@@ -52,7 +51,7 @@ func (b *builder) buildDirectives() (map[string]*Directive, error) {
for name, dir := range b.Schema.Directives { for name, dir := range b.Schema.Directives {
if _, ok := directives[name]; ok { if _, ok := directives[name]; ok {
return nil, errors.Errorf("directive with name %s already exists", name) return nil, fmt.Errorf("directive with name %s already exists", name)
} }
var args []*FieldArgument var args []*FieldArgument
@@ -72,7 +71,7 @@ func (b *builder) buildDirectives() (map[string]*Directive, error) {
var err error var err error
newArg.Default, err = arg.DefaultValue.Value(nil) newArg.Default, err = arg.DefaultValue.Value(nil)
if err != nil { if err != nil {
return nil, errors.Errorf("default value for directive argument %s(%s) is not valid: %s", dir.Name, arg.Name, err.Error()) return nil, fmt.Errorf("default value for directive argument %s(%s) is not valid: %w", dir.Name, arg.Name, err)
} }
} }
args = append(args, newArg) args = append(args, newArg)

View File

@@ -1,6 +1,7 @@
package codegen package codegen
import ( import (
"errors"
"fmt" "fmt"
"go/types" "go/types"
"log" "log"
@@ -10,7 +11,6 @@ import (
"github.com/99designs/gqlgen/codegen/config" "github.com/99designs/gqlgen/codegen/config"
"github.com/99designs/gqlgen/codegen/templates" "github.com/99designs/gqlgen/codegen/templates"
"github.com/pkg/errors"
"github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/ast"
) )
@@ -25,6 +25,7 @@ type Field struct {
Args []*FieldArgument // A list of arguments to be passed to this field 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 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 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 Object *Object // A link back to the parent object
Default interface{} // The default value Default interface{} // The default value
Stream bool // does this field return a channel? Stream bool // does this field return a channel?
@@ -50,7 +51,7 @@ func (b *builder) buildField(obj *Object, field *ast.FieldDefinition) (*Field, e
var err error var err error
f.Default, err = field.DefaultValue.Value(nil) f.Default, err = field.DefaultValue.Value(nil)
if err != nil { if err != nil {
return nil, errors.Errorf("default value %s is not valid: %s", field.Name, err.Error()) return nil, fmt.Errorf("default value %s is not valid: %w", field.Name, err)
} }
} }
@@ -64,6 +65,9 @@ func (b *builder) buildField(obj *Object, field *ast.FieldDefinition) (*Field, e
if err = b.bindField(obj, &f); err != nil { if err = b.bindField(obj, &f); err != nil {
f.IsResolver = true f.IsResolver = true
if errors.Is(err, config.ErrTypeNotFound) {
return nil, err
}
log.Println(err.Error()) log.Println(err.Error())
} }
@@ -88,6 +92,11 @@ func (b *builder) bindField(obj *Object, f *Field) (errret error) {
if err != nil { if err != nil {
errret = err errret = err
} }
for _, dir := range obj.Directives {
if dir.IsLocation(ast.LocationInputObject) {
dirs = append(dirs, dir)
}
}
f.Directives = append(dirs, f.Directives...) f.Directives = append(dirs, f.Directives...)
} }
}() }()
@@ -110,6 +119,7 @@ func (b *builder) bindField(obj *Object, f *Field) (errret error) {
f.GoReceiverName = "ec" f.GoReceiverName = "ec"
f.GoFieldName = "__resolve_entities" f.GoFieldName = "__resolve_entities"
f.MethodHasContext = true f.MethodHasContext = true
f.NoErr = true
return nil return nil
case f.Name == "_service": case f.Name == "_service":
f.GoFieldType = GoFieldMethod f.GoFieldType = GoFieldMethod
@@ -152,6 +162,8 @@ func (b *builder) bindField(obj *Object, f *Field) (errret error) {
sig := target.Type().(*types.Signature) sig := target.Type().(*types.Signature)
if sig.Results().Len() == 1 { if sig.Results().Len() == 1 {
f.NoErr = true 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 { } else if sig.Results().Len() != 2 {
return fmt.Errorf("method has wrong number of args") return fmt.Errorf("method has wrong number of args")
} }
@@ -167,10 +179,13 @@ func (b *builder) bindField(obj *Object, f *Field) (errret error) {
params = types.NewTuple(vars...) params = types.NewTuple(vars...)
} }
if err = b.bindArgs(f, params); err != nil { // Try to match target function's arguments with GraphQL field arguments
return errors.Wrapf(err, "%s:%d", pos.Filename, pos.Line) 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) result := sig.Results().At(0)
tr, err := b.Binder.TypeReference(f.Type, result.Type()) tr, err := b.Binder.TypeReference(f.Type, result.Type())
if err != nil { if err != nil {
@@ -181,6 +196,7 @@ func (b *builder) bindField(obj *Object, f *Field) (errret error) {
f.GoFieldType = GoFieldMethod f.GoFieldType = GoFieldMethod
f.GoReceiverName = "obj" f.GoReceiverName = "obj"
f.GoFieldName = target.Name() f.GoFieldName = target.Name()
f.Args = newArgs
f.TypeReference = tr f.TypeReference = tr
return nil return nil
@@ -237,7 +253,7 @@ func (b *builder) findBindTarget(t types.Type, name string) (types.Object, error
return foundField, nil return foundField, nil
case foundField != nil && foundMethod != nil: case foundField != nil && foundMethod != nil:
// Error // Error
return nil, errors.Errorf("found more than one way to bind for %s", name) return nil, fmt.Errorf("found more than one way to bind for %s", name)
} }
// Search embeds // Search embeds
@@ -262,7 +278,7 @@ func (b *builder) findBindStructTagTarget(in types.Type, name string) (types.Obj
tags := reflect.StructTag(t.Tag(i)) tags := reflect.StructTag(t.Tag(i))
if val, ok := tags.Lookup(b.Config.StructTag); ok && equalFieldName(val, name) { if val, ok := tags.Lookup(b.Config.StructTag); ok && equalFieldName(val, name) {
if found != nil { if found != nil {
return nil, errors.Errorf("tag %s is ambigious; multiple fields have the same tag value of %s", b.Config.StructTag, val) return nil, fmt.Errorf("tag %s is ambigious; multiple fields have the same tag value of %s", b.Config.StructTag, val)
} }
found = field found = field
@@ -300,7 +316,7 @@ func (b *builder) findBindMethoderTarget(methodFunc func(i int) *types.Func, met
} }
if found != nil { if found != nil {
return nil, errors.Errorf("found more than one matching method to bind for %s", name) return nil, fmt.Errorf("found more than one matching method to bind for %s", name)
} }
found = method found = method
@@ -322,7 +338,7 @@ func (b *builder) findBindFieldTarget(in types.Type, name string) (types.Object,
} }
if found != nil { if found != nil {
return nil, errors.Errorf("found more than one matching field to bind for %s", name) return nil, fmt.Errorf("found more than one matching field to bind for %s", name)
} }
found = field found = field
@@ -366,7 +382,7 @@ func (b *builder) findBindStructEmbedsTarget(strukt *types.Struct, name string)
} }
if f != nil && found != nil { if f != nil && found != nil {
return nil, errors.Errorf("found more than one way to bind for %s", name) return nil, fmt.Errorf("found more than one way to bind for %s", name)
} }
if f != nil { if f != nil {
@@ -388,7 +404,7 @@ func (b *builder) findBindInterfaceEmbedsTarget(iface *types.Interface, name str
} }
if f != nil && found != nil { if f != nil && found != nil {
return nil, errors.Errorf("found more than one way to bind for %s", name) return nil, fmt.Errorf("found more than one way to bind for %s", name)
} }
if f != nil { if f != nil {
@@ -417,7 +433,8 @@ func (f *Field) ImplDirectives() []*Directive {
loc = ast.LocationInputFieldDefinition loc = ast.LocationInputFieldDefinition
} }
for i := range f.Directives { for i := range f.Directives {
if !f.Directives[i].Builtin && f.Directives[i].IsLocation(loc, ast.LocationObject) { if !f.Directives[i].Builtin &&
(f.Directives[i].IsLocation(loc, ast.LocationObject) || f.Directives[i].IsLocation(loc, ast.LocationInputObject)) {
d = append(d, f.Directives[i]) d = append(d, f.Directives[i])
} }
} }
@@ -452,7 +469,10 @@ func (f *Field) GoNameUnexported() string {
} }
func (f *Field) ShortInvocation() string { func (f *Field) ShortInvocation() string {
return fmt.Sprintf("%s().%s(%s)", f.Object.Definition.Name, f.GoFieldName, f.CallArgs()) if f.Object.Kind == ast.InputObject {
return fmt.Sprintf("%s().%s(ctx, &it, data)", strings.Title(f.Object.Definition.Name), f.GoFieldName)
}
return fmt.Sprintf("%s().%s(%s)", strings.Title(f.Object.Definition.Name), f.GoFieldName, f.CallArgs())
} }
func (f *Field) ArgsFunc() string { func (f *Field) ArgsFunc() string {
@@ -472,6 +492,13 @@ func (f *Field) ResolverType() string {
} }
func (f *Field) ShortResolverDeclaration() string { func (f *Field) ShortResolverDeclaration() string {
if f.Object.Kind == ast.InputObject {
return fmt.Sprintf("(ctx context.Context, obj %s, data %s) error",
templates.CurrentImports.LookupType(f.Object.Reference()),
templates.CurrentImports.LookupType(f.TypeReference.GO),
)
}
res := "(ctx context.Context" res := "(ctx context.Context"
if !f.Object.Root { if !f.Object.Root {

View File

@@ -16,6 +16,7 @@ func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Contex
Field: field, Field: field,
Args: nil, Args: nil,
IsMethod: {{or $field.IsMethod $field.IsResolver}}, IsMethod: {{or $field.IsMethod $field.IsResolver}},
IsResolver: {{ $field.IsResolver }},
} }
ctx = graphql.WithFieldContext(ctx, fc) ctx = graphql.WithFieldContext(ctx, fc)
@@ -28,7 +29,7 @@ func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Contex
} }
fc.Args = args fc.Args = args
{{- end }} {{- end }}
{{- if $.Directives.LocationDirectives "FIELD" }} {{- if $.AllDirectives.LocationDirectives "FIELD" }}
resTmp := ec._fieldMiddleware(ctx, {{if $object.Root}}nil{{else}}obj{{end}}, func(rctx context.Context) (interface{}, error) { resTmp := ec._fieldMiddleware(ctx, {{if $object.Root}}nil{{else}}obj{{end}}, func(rctx context.Context) (interface{}, error) {
{{ template "field" $field }} {{ template "field" $field }}
}) })
@@ -81,7 +82,7 @@ func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Contex
{{ template "implDirectives" . }} {{ template "implDirectives" . }}
tmp, err := directive{{.ImplDirectives|len}}(rctx) tmp, err := directive{{.ImplDirectives|len}}(rctx)
if err != nil { if err != nil {
return nil, err return nil, graphql.ErrorOnPath(ctx, err)
} }
if tmp == nil { if tmp == nil {
return nil, nil return nil, nil
@@ -111,7 +112,13 @@ func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Contex
return nil, fmt.Errorf("unexpected type %T for field %s", v, {{ .Name | quote}}) return nil, fmt.Errorf("unexpected type %T for field %s", v, {{ .Name | quote}})
} }
{{- else if .IsMethod -}} {{- else if .IsMethod -}}
{{- if .NoErr -}} {{- if .VOkFunc -}}
v, ok := {{.GoReceiverName}}.{{.GoFieldName}}({{ .CallArgs }})
if !ok {
return nil, nil
}
return v, nil
{{- else if .NoErr -}}
return {{.GoReceiverName}}.{{.GoFieldName}}({{ .CallArgs }}), nil return {{.GoReceiverName}}.{{.GoFieldName}}({{ .CallArgs }}), nil
{{- else -}} {{- else -}}
return {{.GoReceiverName}}.{{.GoFieldName}}({{ .CallArgs }}) return {{.GoReceiverName}}.{{.GoFieldName}}({{ .CallArgs }})

View File

@@ -1,10 +1,34 @@
package codegen package codegen
import ( import (
"errors"
"fmt"
"io/ioutil"
"path/filepath"
"runtime"
"strings"
"github.com/99designs/gqlgen/codegen/config"
"github.com/99designs/gqlgen/codegen/templates" "github.com/99designs/gqlgen/codegen/templates"
"github.com/vektah/gqlparser/v2/ast"
) )
func GenerateCode(data *Data) error { 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{ return templates.Render(templates.Options{
PackageName: data.Config.Exec.Package, PackageName: data.Config.Exec.Package,
Filename: data.Config.Exec.Filename, Filename: data.Config.Exec.Filename,
@@ -14,3 +38,176 @@ func GenerateCode(data *Data) error {
Packages: data.Config.Packages, 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
}

View File

@@ -14,6 +14,7 @@
{{ reserveImport "github.com/99designs/gqlgen/graphql/introspection" }} {{ reserveImport "github.com/99designs/gqlgen/graphql/introspection" }}
{{ if eq .Config.Exec.Layout "single-file" }}
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface. // NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema { func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{ return &executableSchema{
@@ -32,7 +33,12 @@ type Config struct {
type ResolverRoot interface { type ResolverRoot interface {
{{- range $object := .Objects -}} {{- range $object := .Objects -}}
{{ if $object.HasResolvers -}} {{ if $object.HasResolvers -}}
{{$object.Name}}() {{$object.Name}}Resolver {{ucFirst $object.Name}}() {{ucFirst $object.Name}}Resolver
{{ end }}
{{- end }}
{{- range $object := .Inputs -}}
{{ if $object.HasResolvers -}}
{{ucFirst $object.Name}}() {{ucFirst $object.Name}}Resolver
{{ end }} {{ end }}
{{- end }} {{- end }}
} }
@@ -46,7 +52,7 @@ type DirectiveRoot struct {
type ComplexityRoot struct { type ComplexityRoot struct {
{{ range $object := .Objects }} {{ range $object := .Objects }}
{{ if not $object.IsReserved -}} {{ if not $object.IsReserved -}}
{{ $object.Name|go }} struct { {{ ucFirst $object.Name }} struct {
{{ range $_, $fields := $object.UniqueFields }} {{ range $_, $fields := $object.UniqueFields }}
{{- $field := index $fields 0 -}} {{- $field := index $fields 0 -}}
{{ if not $field.IsReserved -}} {{ if not $field.IsReserved -}}
@@ -57,8 +63,21 @@ type ComplexityRoot struct {
{{- end }} {{- end }}
{{ end }} {{ end }}
} }
{{ end }}
{{ range $object := .Objects -}} {{ 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 }} {{ if $object.HasResolvers }}
type {{$object.Name}}Resolver interface { type {{$object.Name}}Resolver interface {
{{ range $field := $object.Fields -}} {{ range $field := $object.Fields -}}
@@ -70,6 +89,7 @@ type ComplexityRoot struct {
{{- end }} {{- end }}
{{- end }} {{- end }}
{{ if eq .Config.Exec.Layout "single-file" }}
type executableSchema struct { type executableSchema struct {
resolvers ResolverRoot resolvers ResolverRoot
directives DirectiveRoot directives DirectiveRoot
@@ -92,7 +112,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
{{- $last := eq (add $i 1) $len }} {{- $last := eq (add $i 1) $len }}
{{- if not $field.IsReserved }} {{- if not $field.IsReserved }}
{{- if eq $i 0 }}case {{ end }}"{{$object.Name}}.{{$field.Name}}"{{ if not $last }},{{ else }}: {{- if eq $i 0 }}case {{ end }}"{{$object.Name}}.{{$field.Name}}"{{ if not $last }},{{ else }}:
if e.complexity.{{$object.Name|go}}.{{$field.GoFieldName}} == nil { if e.complexity.{{ucFirst $object.Name}}.{{$field.GoFieldName}} == nil {
break break
} }
{{ if $field.Args }} {{ if $field.Args }}
@@ -101,7 +121,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return 0, false return 0, false
} }
{{ end }} {{ end }}
return e.complexity.{{$object.Name|go}}.{{$field.GoFieldName}}(childComplexity{{if $field.Args}}, {{$field.ComplexityArgs}} {{ end }}), true return e.complexity.{{ucFirst $object.Name}}.{{$field.GoFieldName}}(childComplexity{{if $field.Args}}, {{$field.ComplexityArgs}} {{ end }}), true
{{ end }} {{ end }}
{{- end }} {{- end }}
{{- end }} {{- end }}
@@ -212,3 +232,4 @@ var sources = []*ast.Source{
{{- end }} {{- end }}
} }
var parsedSchema = gqlparser.MustLoadSchema(sources...) var parsedSchema = gqlparser.MustLoadSchema(sources...)
{{ end }}

View File

@@ -2,9 +2,12 @@
{{- if not .HasUnmarshal }} {{- if not .HasUnmarshal }}
func (ec *executionContext) unmarshalInput{{ .Name }}(ctx context.Context, obj interface{}) ({{.Type | ref}}, error) { func (ec *executionContext) unmarshalInput{{ .Name }}(ctx context.Context, obj interface{}) ({{.Type | ref}}, error) {
var it {{.Type | ref}} var it {{.Type | ref}}
var asMap = obj.(map[string]interface{}) asMap := map[string]interface{}{}
for k, v := range obj.(map[string]interface{}) {
asMap[k] = v
}
{{ range $field := .Fields}} {{ range $field := .Fields}}
{{- if $field.Default}} {{- if notNil "Default" $field }}
if _, present := asMap[{{$field.Name|quote}}] ; !present { if _, present := asMap[{{$field.Name|quote}}] ; !present {
asMap[{{$field.Name|quote}}] = {{ $field.Default | dump }} asMap[{{$field.Name|quote}}] = {{ $field.Default | dump }}
} }
@@ -17,22 +20,40 @@
case {{$field.Name|quote}}: case {{$field.Name|quote}}:
var err error var err error
ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField({{$field.Name|quote}})) ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField({{$field.Name|quote}}))
{{- if $field.ImplDirectives }} {{- if $field.ImplDirectives }}
directive0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $field.TypeReference.UnmarshalFunc }}(ctx, v) } directive0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $field.TypeReference.UnmarshalFunc }}(ctx, v) }
{{ template "implDirectives" $field }} {{ template "implDirectives" $field }}
tmp, err := directive{{$field.ImplDirectives|len}}(ctx) tmp, err := directive{{$field.ImplDirectives|len}}(ctx)
if err != nil { if err != nil {
return it, err return it, graphql.ErrorOnPath(ctx, err)
} }
if data, ok := tmp.({{ $field.TypeReference.GO | ref }}) ; ok { 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 it.{{$field.GoFieldName}} = data
{{- end }}
{{- if $field.TypeReference.IsNilable }} {{- if $field.TypeReference.IsNilable }}
{{- if not $field.IsResolver }}
} else if tmp == nil { } else if tmp == nil {
it.{{$field.GoFieldName}} = nil it.{{$field.GoFieldName}} = nil
{{- end }} {{- end }}
{{- end }}
} else { } else {
return it, fmt.Errorf(`unexpected type %T from directive, should be {{ $field.TypeReference.GO }}`, tmp) err := fmt.Errorf(`unexpected type %T from directive, should be {{ $field.TypeReference.GO }}`, tmp)
return it, graphql.ErrorOnPath(ctx, err)
}
{{- else }}
{{- 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 }} {{- else }}
it.{{$field.GoFieldName}}, err = ec.{{ $field.TypeReference.UnmarshalFunc }}(ctx, v) it.{{$field.GoFieldName}}, err = ec.{{ $field.TypeReference.UnmarshalFunc }}(ctx, v)
@@ -41,6 +62,7 @@
} }
{{- end }} {{- end }}
{{- end }} {{- end }}
{{- end }}
} }
} }

View File

@@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"go/types" "go/types"
"github.com/pkg/errors"
"github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/ast"
"github.com/99designs/gqlgen/codegen/config" "github.com/99designs/gqlgen/codegen/config"
@@ -49,7 +48,7 @@ func (b *builder) buildInterface(typ *ast.Definition) (*Interface, error) {
implementorType, err := findGoNamedType(obj) implementorType, err := findGoNamedType(obj)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "can not find backing go type %s", obj.String()) return nil, fmt.Errorf("can not find backing go type %s: %w", obj.String(), err)
} else if implementorType == nil { } else if implementorType == nil {
return nil, fmt.Errorf("can not find backing go type %s", obj.String()) return nil, fmt.Errorf("can not find backing go type %s", obj.String())
} }

View File

@@ -1,13 +1,13 @@
package codegen package codegen
import ( import (
"fmt"
"go/types" "go/types"
"strconv" "strconv"
"strings" "strings"
"unicode" "unicode"
"github.com/99designs/gqlgen/codegen/config" "github.com/99designs/gqlgen/codegen/config"
"github.com/pkg/errors"
"github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/ast"
) )
@@ -36,7 +36,7 @@ type Object struct {
func (b *builder) buildObject(typ *ast.Definition) (*Object, error) { func (b *builder) buildObject(typ *ast.Definition) (*Object, error) {
dirs, err := b.getDirectives(typ.Directives) dirs, err := b.getDirectives(typ.Directives)
if err != nil { if err != nil {
return nil, errors.Wrap(err, typ.Name) return nil, fmt.Errorf("%s: %w", typ.Name, err)
} }
obj := &Object{ obj := &Object{
@@ -46,7 +46,7 @@ func (b *builder) buildObject(typ *ast.Definition) (*Object, error) {
Stream: typ == b.Schema.Subscription, Stream: typ == b.Schema.Subscription,
Directives: dirs, Directives: dirs,
ResolverInterface: types.NewNamed( ResolverInterface: types.NewNamed(
types.NewTypeName(0, b.Config.Exec.Pkg(), typ.Name+"Resolver", nil), types.NewTypeName(0, b.Config.Exec.Pkg(), strings.Title(typ.Name)+"Resolver", nil),
nil, nil,
nil, nil,
), ),

View File

@@ -25,15 +25,20 @@ func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.Selec
{{- else }} {{- else }}
func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.SelectionSet{{ if not $object.Root }},obj {{$object.Reference | ref }}{{ end }}) graphql.Marshaler { 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) fields := graphql.CollectFields(ec.OperationContext, sel, {{$object.Name|lcFirst}}Implementors)
{{if $object.Root}} {{- if $object.Root }}
ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{
Object: {{$object.Name|quote}}, Object: {{$object.Name|quote}},
}) })
{{end}} {{end}}
out := graphql.NewFieldSet(fields) out := graphql.NewFieldSet(fields)
var invalids uint32 var invalids uint32
for i, field := range fields { for i, field := range fields {
{{- if $object.Root }}
innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{
Object: field.Name,
Field: field,
})
{{end}}
switch field.Name { switch field.Name {
case "__typename": case "__typename":
out.Values[i] = graphql.MarshalString({{$object.Name|quote}}) out.Values[i] = graphql.MarshalString({{$object.Name|quote}})
@@ -41,7 +46,8 @@ func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.Selec
case "{{$field.Name}}": case "{{$field.Name}}":
{{- if $field.IsConcurrent }} {{- if $field.IsConcurrent }}
field := field field := field
out.Concurrently(i, func() (res graphql.Marshaler) {
innerFunc := func(ctx context.Context) (res graphql.Marshaler) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r)) ec.Error(ctx, ec.Recover(ctx, r))
@@ -58,9 +64,31 @@ func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.Selec
} }
{{- end }} {{- end }}
return res 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 }} {{- else }}
out.Values[i] = ec._{{$object.Name}}_{{$field.Name}}(ctx, field{{if not $object.Root}}, obj{{end}}) 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 $field.TypeReference.GQL.NonNull }}
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
{{- if $object.IsConcurrent }} {{- if $object.IsConcurrent }}

201
vendor/github.com/99designs/gqlgen/codegen/root_.gotpl generated vendored Normal file
View File

@@ -0,0 +1,201 @@
{{ reserveImport "context" }}
{{ reserveImport "fmt" }}
{{ reserveImport "io" }}
{{ reserveImport "strconv" }}
{{ reserveImport "time" }}
{{ reserveImport "sync" }}
{{ reserveImport "sync/atomic" }}
{{ reserveImport "errors" }}
{{ reserveImport "bytes" }}
{{ reserveImport "github.com/vektah/gqlparser/v2" "gqlparser" }}
{{ reserveImport "github.com/vektah/gqlparser/v2/ast" }}
{{ reserveImport "github.com/99designs/gqlgen/graphql" }}
{{ reserveImport "github.com/99designs/gqlgen/graphql/introspection" }}
// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface.
func NewExecutableSchema(cfg Config) graphql.ExecutableSchema {
return &executableSchema{
resolvers: cfg.Resolvers,
directives: cfg.Directives,
complexity: cfg.Complexity,
}
}
type Config struct {
Resolvers ResolverRoot
Directives DirectiveRoot
Complexity ComplexityRoot
}
type ResolverRoot interface {
{{- range $object := .Objects -}}
{{ if $object.HasResolvers -}}
{{ucFirst $object.Name}}() {{ucFirst $object.Name}}Resolver
{{ end }}
{{- end }}
}
type DirectiveRoot struct {
{{ range $directive := .Directives }}
{{- $directive.Declaration }}
{{ end }}
}
type ComplexityRoot struct {
{{ range $object := .Objects }}
{{ if not $object.IsReserved -}}
{{ ucFirst $object.Name }} struct {
{{ range $_, $fields := $object.UniqueFields }}
{{- $field := index $fields 0 -}}
{{ if not $field.IsReserved -}}
{{ $field.GoFieldName }} {{ $field.ComplexitySignature }}
{{ end }}
{{- end }}
}
{{- end }}
{{ end }}
}
type executableSchema struct {
resolvers ResolverRoot
directives DirectiveRoot
complexity ComplexityRoot
}
func (e *executableSchema) Schema() *ast.Schema {
return parsedSchema
}
func (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) {
ec := executionContext{nil, e}
_ = ec
switch typeName + "." + field {
{{ range $object := .Objects }}
{{ if not $object.IsReserved }}
{{ range $_, $fields := $object.UniqueFields }}
{{- $len := len $fields }}
{{- range $i, $field := $fields }}
{{- $last := eq (add $i 1) $len }}
{{- if not $field.IsReserved }}
{{- if eq $i 0 }}case {{ end }}"{{$object.Name}}.{{$field.Name}}"{{ if not $last }},{{ else }}:
if e.complexity.{{ucFirst $object.Name }}.{{$field.GoFieldName}} == nil {
break
}
{{ if $field.Args }}
args, err := ec.{{ $field.ArgsFunc }}(context.TODO(),rawArgs)
if err != nil {
return 0, false
}
{{ end }}
return e.complexity.{{ucFirst $object.Name}}.{{$field.GoFieldName}}(childComplexity{{if $field.Args}}, {{$field.ComplexityArgs}} {{ end }}), true
{{ end }}
{{- end }}
{{- end }}
{{ end }}
{{ end }}
{{ end }}
}
return 0, false
}
func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
rc := graphql.GetOperationContext(ctx)
ec := executionContext{rc, e}
first := true
switch rc.Operation.Operation {
{{- if .QueryRoot }} case ast.Query:
return func(ctx context.Context) *graphql.Response {
if !first { return nil }
first = false
{{ if .Directives.LocationDirectives "QUERY" -}}
data := ec._queryMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error){
return ec._{{.QueryRoot.Name}}(ctx, rc.Operation.SelectionSet), nil
})
{{- else -}}
data := ec._{{.QueryRoot.Name}}(ctx, rc.Operation.SelectionSet)
{{- end }}
var buf bytes.Buffer
data.MarshalGQL(&buf)
return &graphql.Response{
Data: buf.Bytes(),
}
}
{{ end }}
{{- if .MutationRoot }} case ast.Mutation:
return func(ctx context.Context) *graphql.Response {
if !first { return nil }
first = false
{{ if .Directives.LocationDirectives "MUTATION" -}}
data := ec._mutationMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error){
return ec._{{.MutationRoot.Name}}(ctx, rc.Operation.SelectionSet), nil
})
{{- else -}}
data := ec._{{.MutationRoot.Name}}(ctx, rc.Operation.SelectionSet)
{{- end }}
var buf bytes.Buffer
data.MarshalGQL(&buf)
return &graphql.Response{
Data: buf.Bytes(),
}
}
{{ end }}
{{- if .SubscriptionRoot }} case ast.Subscription:
{{ if .Directives.LocationDirectives "SUBSCRIPTION" -}}
next := ec._subscriptionMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error){
return ec._{{.SubscriptionRoot.Name}}(ctx, rc.Operation.SelectionSet),nil
})
{{- else -}}
next := ec._{{.SubscriptionRoot.Name}}(ctx, rc.Operation.SelectionSet)
{{- end }}
var buf bytes.Buffer
return func(ctx context.Context) *graphql.Response {
buf.Reset()
data := next()
if data == nil {
return nil
}
data.MarshalGQL(&buf)
return &graphql.Response{
Data: buf.Bytes(),
}
}
{{ end }}
default:
return graphql.OneShot(graphql.ErrorResponse(ctx, "unsupported GraphQL operation"))
}
}
type executionContext struct {
*graphql.OperationContext
*executableSchema
}
func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
return introspection.WrapSchema(parsedSchema), nil
}
func (ec *executionContext) introspectType(name string) (*introspection.Type, error) {
if ec.DisableIntrospection {
return nil, errors.New("introspection disabled")
}
return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
}
var sources = []*ast.Source{
{{- range $source := .Config.Sources }}
{Name: {{$source.Name|quote}}, Input: {{$source.Input|rawQuote}}, BuiltIn: {{$source.BuiltIn}}},
{{- end }}
}
var parsedSchema = gqlparser.MustLoadSchema(sources...)

View File

@@ -105,7 +105,7 @@ func (s *Imports) Lookup(path string) string {
for s.findByAlias(alias) != nil { for s.findByAlias(alias) != nil {
alias = imp.Name + strconv.Itoa(i) alias = imp.Name + strconv.Itoa(i)
i++ i++
if i > 10 { if i > 1000 {
panic(fmt.Errorf("too many collisions, last attempt was %s", alias)) panic(fmt.Errorf("too many collisions, last attempt was %s", alias))
} }
} }

View File

@@ -18,7 +18,6 @@ import (
"github.com/99designs/gqlgen/internal/code" "github.com/99designs/gqlgen/internal/code"
"github.com/99designs/gqlgen/internal/imports" "github.com/99designs/gqlgen/internal/imports"
"github.com/pkg/errors"
) )
// CurrentImports keeps track of all the import declarations that are needed during the execution of a plugin. // CurrentImports keeps track of all the import declarations that are needed during the execution of a plugin.
@@ -79,7 +78,7 @@ func Render(cfg Options) error {
var err error var err error
t, err = t.New("template.gotpl").Parse(cfg.Template) t, err = t.New("template.gotpl").Parse(cfg.Template)
if err != nil { if err != nil {
return errors.Wrap(err, "error with provided template") return fmt.Errorf("error with provided template: %w", err)
} }
roots = append(roots, "template.gotpl") roots = append(roots, "template.gotpl")
} else { } else {
@@ -92,6 +91,10 @@ func Render(cfg Options) error {
if !strings.HasSuffix(info.Name(), ".gotpl") { if !strings.HasSuffix(info.Name(), ".gotpl") {
return nil 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) b, err := ioutil.ReadFile(path)
if err != nil { if err != nil {
return err return err
@@ -99,7 +102,7 @@ func Render(cfg Options) error {
t, err = t.New(name).Parse(string(b)) t, err = t.New(name).Parse(string(b))
if err != nil { if err != nil {
return errors.Wrap(err, cfg.Filename) return fmt.Errorf("%s: %w", cfg.Filename, err)
} }
roots = append(roots, name) roots = append(roots, name)
@@ -107,7 +110,7 @@ func Render(cfg Options) error {
return nil return nil
}) })
if err != nil { if err != nil {
return errors.Wrap(err, "locating templates") return fmt.Errorf("locating templates: %w", err)
} }
} }
@@ -129,7 +132,7 @@ func Render(cfg Options) error {
} }
err := t.Lookup(root).Execute(&buf, cfg.Data) err := t.Lookup(root).Execute(&buf, cfg.Data)
if err != nil { if err != nil {
return errors.Wrap(err, root) return fmt.Errorf("%s: %w", root, err)
} }
if cfg.RegionTags { if cfg.RegionTags {
buf.WriteString("\n// endregion " + center(70, "*", " "+root+" ") + "\n") buf.WriteString("\n// endregion " + center(70, "*", " "+root+" ") + "\n")
@@ -450,18 +453,23 @@ var commonInitialisms = map[string]bool{
"ASCII": true, "ASCII": true,
"CPU": true, "CPU": true,
"CSS": true, "CSS": true,
"CSV": true,
"DNS": true, "DNS": true,
"EOF": true, "EOF": true,
"GUID": true, "GUID": true,
"HTML": true, "HTML": true,
"HTTP": true, "HTTP": true,
"HTTPS": true, "HTTPS": true,
"ICMP": true,
"ID": true, "ID": true,
"IP": true, "IP": true,
"JSON": true, "JSON": true,
"KVK": true,
"LHS": true, "LHS": true,
"PDF": true,
"PGP": true, "PGP": true,
"QPS": true, "QPS": true,
"QR": true,
"RAM": true, "RAM": true,
"RHS": true, "RHS": true,
"RPC": true, "RPC": true,
@@ -469,16 +477,17 @@ var commonInitialisms = map[string]bool{
"SMTP": true, "SMTP": true,
"SQL": true, "SQL": true,
"SSH": true, "SSH": true,
"SVG": true,
"TCP": true, "TCP": true,
"TLS": true, "TLS": true,
"TTL": true, "TTL": true,
"UDP": true, "UDP": true,
"UI": true, "UI": true,
"UID": true, "UID": true,
"UUID": true,
"URI": true, "URI": true,
"URL": true, "URL": true,
"UTF8": true, "UTF8": true,
"UUID": true,
"VM": true, "VM": true,
"XML": true, "XML": true,
"XMPP": true, "XMPP": true,
@@ -487,7 +496,7 @@ var commonInitialisms = map[string]bool{
} }
func rawQuote(s string) string { func rawQuote(s string) string {
return "`" + strings.Replace(s, "`", "`+\"`\"+`", -1) + "`" return "`" + strings.ReplaceAll(s, "`", "`+\"`\"+`") + "`"
} }
func notNil(field string, data interface{}) bool { func notNil(field string, data interface{}) bool {
@@ -549,7 +558,7 @@ func Dump(val interface{}) string {
} }
func prefixLines(prefix, s string) string { func prefixLines(prefix, s string) string {
return prefix + strings.Replace(s, "\n", "\n"+prefix, -1) return prefix + strings.ReplaceAll(s, "\n", "\n"+prefix)
} }
func resolveName(name string, skip int) string { func resolveName(name string, skip int) string {
@@ -582,9 +591,9 @@ func render(filename string, tpldata interface{}) (*bytes.Buffer, error) {
} }
func write(filename string, b []byte, packages *code.Packages) error { func write(filename string, b []byte, packages *code.Packages) error {
err := os.MkdirAll(filepath.Dir(filename), 0755) err := os.MkdirAll(filepath.Dir(filename), 0o755)
if err != nil { if err != nil {
return errors.Wrap(err, "failed to create directory") return fmt.Errorf("failed to create directory: %w", err)
} }
formatted, err := imports.Prune(filename, b, packages) formatted, err := imports.Prune(filename, b, packages)
@@ -593,9 +602,9 @@ func write(filename string, b []byte, packages *code.Packages) error {
formatted = b formatted = b
} }
err = ioutil.WriteFile(filename, formatted, 0644) err = ioutil.WriteFile(filename, formatted, 0o644)
if err != nil { if err != nil {
return errors.Wrapf(err, "failed to write %s", filename) return fmt.Errorf("failed to write %s: %w", filename, err)
} }
return nil return nil

View File

@@ -26,7 +26,7 @@ func processType(ret map[string]*config.TypeReference, ref *config.TypeReference
} }
ret[key] = ref ret[key] = ref
if ref.IsSlice() { if ref.IsSlice() || ref.IsPtrToSlice() || ref.IsPtrToPtr() {
processType(ret, ref.Elem()) processType(ret, ref.Elem())
} }
} }

View File

@@ -1,63 +1,84 @@
{{- range $type := .ReferencedTypes }} {{- range $type := .ReferencedTypes }}
{{ with $type.UnmarshalFunc }} {{ with $type.UnmarshalFunc }}
func (ec *executionContext) {{ . }}(ctx context.Context, v interface{}) ({{ $type.GO | ref }}, error) { func (ec *executionContext) {{ . }}(ctx context.Context, v interface{}) ({{ $type.GO | ref }}, error) {
{{- if and $type.IsNilable (not $type.GQL.NonNull) }} {{- if and $type.IsNilable (not $type.GQL.NonNull) (not $type.IsPtrToPtr) }}
if v == nil { return nil, nil } if v == nil { return nil, nil }
{{- end }} {{- end }}
{{- if $type.IsSlice }} {{- if $type.IsPtrToSlice }}
res, err := ec.{{ $type.Elem.UnmarshalFunc }}(ctx, v)
return &res, graphql.ErrorOnPath(ctx, err)
{{- else if $type.IsSlice }}
var vSlice []interface{} var vSlice []interface{}
if v != nil { if v != nil {
if tmp1, ok := v.([]interface{}); ok { vSlice = graphql.CoerceList(v)
vSlice = tmp1
} else {
vSlice = []interface{}{ v }
}
} }
var err error var err error
res := make([]{{$type.GO.Elem | ref}}, len(vSlice)) res := make([]{{$type.GO.Elem | ref}}, len(vSlice))
for i := range vSlice { for i := range vSlice {
ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithIndex(i)) ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i))
res[i], err = ec.{{ $type.Elem.UnmarshalFunc }}(ctx, vSlice[i]) res[i], err = ec.{{ $type.Elem.UnmarshalFunc }}(ctx, vSlice[i])
if err != nil { if err != nil {
return nil, graphql.WrapErrorWithInputPath(ctx, err) return nil, err
} }
} }
return res, nil 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 }} {{- else }}
{{- if $type.Unmarshaler }} {{- if $type.Unmarshaler }}
{{- if $type.CastType }} {{- if $type.CastType }}
{{- if $type.IsContext }}
tmp, err := {{ $type.Unmarshaler | call }}(ctx, v)
{{- else }}
tmp, err := {{ $type.Unmarshaler | call }}(v) tmp, err := {{ $type.Unmarshaler | call }}(v)
{{- if $type.IsNilable }} {{- end }}
{{- if and $type.IsNilable $type.Elem }}
res := {{ $type.Elem.GO | ref }}(tmp) res := {{ $type.Elem.GO | ref }}(tmp)
{{- else}} {{- else}}
res := {{ $type.GO | ref }}(tmp) res := {{ $type.GO | ref }}(tmp)
{{- end }} {{- end }}
{{- else}}
{{- if $type.IsContext }}
res, err := {{ $type.Unmarshaler | call }}(ctx, v)
{{- else }} {{- else }}
res, err := {{ $type.Unmarshaler | call }}(v) res, err := {{ $type.Unmarshaler | call }}(v)
{{- end }} {{- end }}
{{- end }}
{{- if and $type.IsTargetNilable (not $type.IsNilable) }} {{- if and $type.IsTargetNilable (not $type.IsNilable) }}
return *res, graphql.WrapErrorWithInputPath(ctx, err) return *res, graphql.ErrorOnPath(ctx, err)
{{- else if and (not $type.IsTargetNilable) $type.IsNilable }} {{- else if and (not $type.IsTargetNilable) $type.IsNilable }}
return &res, graphql.WrapErrorWithInputPath(ctx, err) return &res, graphql.ErrorOnPath(ctx, err)
{{- else}} {{- else}}
return res, graphql.WrapErrorWithInputPath(ctx, err) return res, graphql.ErrorOnPath(ctx, err)
{{- end }} {{- end }}
{{- else if eq ($type.GO | ref) "map[string]interface{}" }} {{- else if eq ($type.GO | ref) "map[string]interface{}" }}
return v.(map[string]interface{}), nil return v.(map[string]interface{}), nil
{{- else if $type.IsMarshaler }} {{- else if $type.IsMarshaler }}
{{- if $type.IsNilable }} {{- if and $type.IsNilable $type.Elem }}
var res = new({{ $type.Elem.GO | ref }}) var res = new({{ $type.Elem.GO | ref }})
{{- else}} {{- else}}
var res {{ $type.GO | ref }} var res {{ $type.GO | ref }}
{{- end }} {{- end }}
{{- if $type.IsContext }}
err := res.UnmarshalGQLContext(ctx, v)
{{- else }}
err := res.UnmarshalGQL(v) err := res.UnmarshalGQL(v)
return res, graphql.WrapErrorWithInputPath(ctx, err) {{- end }}
return res, graphql.ErrorOnPath(ctx, err)
{{- else }} {{- else }}
res, err := ec.unmarshalInput{{ $type.GQL.Name }}(ctx, v) res, err := ec.unmarshalInput{{ $type.GQL.Name }}(ctx, v)
{{- if $type.IsNilable }} {{- if $type.IsNilable }}
return &res, graphql.WrapErrorWithInputPath(ctx, err) return &res, graphql.ErrorOnPath(ctx, err)
{{- else}} {{- else}}
return res, graphql.WrapErrorWithInputPath(ctx, err) return res, graphql.ErrorOnPath(ctx, err)
{{- end }} {{- end }}
{{- end }} {{- end }}
{{- end }} {{- end }}
@@ -66,7 +87,9 @@
{{ with $type.MarshalFunc }} {{ with $type.MarshalFunc }}
func (ec *executionContext) {{ . }}(ctx context.Context, sel ast.SelectionSet, v {{ $type.GO | ref }}) graphql.Marshaler { func (ec *executionContext) {{ . }}(ctx context.Context, sel ast.SelectionSet, v {{ $type.GO | ref }}) graphql.Marshaler {
{{- if $type.IsSlice }} {{- if $type.IsPtrToSlice }}
return ec.{{ $type.Elem.MarshalFunc }}(ctx, sel, *v)
{{- else if $type.IsSlice }}
{{- if not $type.GQL.NonNull }} {{- if not $type.GQL.NonNull }}
if v == nil { if v == nil {
return graphql.Null return graphql.Null
@@ -110,7 +133,19 @@
{{- end }} {{- end }}
} }
{{ if not $type.IsScalar }} wg.Wait() {{ 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 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 }} {{- else }}
{{- if $type.IsNilable }} {{- if $type.IsNilable }}
if v == nil { if v == nil {
@@ -123,7 +158,11 @@
} }
{{- end }} {{- end }}
{{- if $type.IsMarshaler }} {{- if $type.IsMarshaler }}
{{- if $type.IsContext }}
return graphql.WrapContextMarshaler(ctx, v)
{{- else }}
return v return v
{{- end }}
{{- else if $type.Marshaler }} {{- else if $type.Marshaler }}
{{- $v := "v" }} {{- $v := "v" }}
{{- if and $type.IsTargetNilable (not $type.IsNilable) }} {{- if and $type.IsTargetNilable (not $type.IsNilable) }}
@@ -131,16 +170,18 @@
{{- else if and (not $type.IsTargetNilable) $type.IsNilable }} {{- else if and (not $type.IsTargetNilable) $type.IsNilable }}
{{- $v = "*v" }} {{- $v = "*v" }}
{{- end }} {{- end }}
{{- if $type.GQL.NonNull }}
res := {{ $type.Marshaler | call }}({{- if $type.CastType }}{{ $type.CastType | ref }}({{ $v }}){{else}}{{ $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 res == graphql.Null {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "must not be null") ec.Errorf(ctx, "must not be null")
} }
} }
return res {{- end }}
{{- if $type.IsContext }}
return graphql.WrapContextMarshaler(ctx, res)
{{- else }} {{- else }}
return {{ $type.Marshaler | call }}({{- if $type.CastType }}{{ $type.CastType | ref }}({{ $v }}){{else}}{{ $v }}{{- end }}) return res
{{- end }} {{- end }}
{{- else }} {{- else }}
return ec._{{$type.Definition.Name}}(ctx, sel, {{ if not $type.IsNilable}}&{{end}} v) return ec._{{$type.Definition.Name}}(ctx, sel, {{ if not $type.IsNilable}}&{{end}} v)

View File

@@ -1,10 +1,9 @@
package codegen package codegen
import ( import (
"fmt"
"go/types" "go/types"
"strings" "strings"
"github.com/pkg/errors"
) )
func findGoNamedType(def types.Type) (*types.Named, error) { func findGoNamedType(def types.Type) (*types.Named, error) {
@@ -14,7 +13,7 @@ func findGoNamedType(def types.Type) (*types.Named, error) {
namedType, ok := def.(*types.Named) namedType, ok := def.(*types.Named)
if !ok { if !ok {
return nil, errors.Errorf("expected %s to be a named type, instead found %T\n", def.String(), def) return nil, fmt.Errorf("expected %s to be a named type, instead found %T\n", def.String(), def)
} }
return namedType, nil return namedType, nil
@@ -34,14 +33,14 @@ func findGoInterface(def types.Type) (*types.Interface, error) {
underlying, ok := namedType.Underlying().(*types.Interface) underlying, ok := namedType.Underlying().(*types.Interface)
if !ok { if !ok {
return nil, errors.Errorf("expected %s to be a named interface, instead found %s", def.String(), namedType.String()) return nil, fmt.Errorf("expected %s to be a named interface, instead found %s", def.String(), namedType.String())
} }
return underlying, nil return underlying, nil
} }
func equalFieldName(source, target string) bool { func equalFieldName(source, target string) bool {
source = strings.Replace(source, "_", "", -1) source = strings.ReplaceAll(source, "_", "")
target = strings.Replace(target, "_", "", -1) target = strings.ReplaceAll(target, "_", "")
return strings.EqualFold(source, target) return strings.EqualFold(source, target)
} }

View File

@@ -26,6 +26,11 @@ func (cw complexityWalker) selectionSetComplexity(selectionSet ast.SelectionSet)
switch s := selection.(type) { switch s := selection.(type) {
case *ast.Field: case *ast.Field:
fieldDefinition := cw.schema.Types[s.Definition.Type.Name()] fieldDefinition := cw.schema.Types[s.Definition.Type.Name()]
if fieldDefinition.Name == "__Schema" {
continue
}
var childComplexity int var childComplexity int
switch fieldDefinition.Kind { switch fieldDefinition.Kind {
case ast.Object, ast.Interface, ast.Union: case ast.Object, ast.Interface, ast.Union:

View File

@@ -7,13 +7,10 @@ import (
) )
func MarshalBoolean(b bool) Marshaler { func MarshalBoolean(b bool) Marshaler {
return WriterFunc(func(w io.Writer) {
if b { if b {
w.Write(trueLit) return WriterFunc(func(w io.Writer) { w.Write(trueLit) })
} else {
w.Write(falseLit)
} }
}) return WriterFunc(func(w io.Writer) { w.Write(falseLit) })
} }
func UnmarshalBoolean(v interface{}) (bool, error) { func UnmarshalBoolean(v interface{}) (bool, error) {

56
vendor/github.com/99designs/gqlgen/graphql/coercion.go generated vendored Normal file
View File

@@ -0,0 +1,56 @@
package graphql
import (
"encoding/json"
)
// CoerceList applies coercion from a single value to a list.
func CoerceList(v interface{}) []interface{} {
var vSlice []interface{}
if v != nil {
switch v := v.(type) {
case []interface{}:
// already a slice no coercion required
vSlice = v
case []string:
if len(v) > 0 {
vSlice = []interface{}{v[0]}
}
case []json.Number:
if len(v) > 0 {
vSlice = []interface{}{v[0]}
}
case []bool:
if len(v) > 0 {
vSlice = []interface{}{v[0]}
}
case []map[string]interface{}:
if len(v) > 0 {
vSlice = []interface{}{v[0]}
}
case []float64:
if len(v) > 0 {
vSlice = []interface{}{v[0]}
}
case []float32:
if len(v) > 0 {
vSlice = []interface{}{v[0]}
}
case []int:
if len(v) > 0 {
vSlice = []interface{}{v[0]}
}
case []int32:
if len(v) > 0 {
vSlice = []interface{}{v[0]}
}
case []int64:
if len(v) > 0 {
vSlice = []interface{}{v[0]}
}
default:
vSlice = []interface{}{v}
}
}
return vSlice
}

View File

@@ -28,6 +28,8 @@ type FieldContext struct {
Result interface{} Result interface{}
// IsMethod indicates if the resolver is a method // IsMethod indicates if the resolver is a method
IsMethod bool IsMethod bool
// IsResolver indicates if the field has a user-specified resolver
IsResolver bool
} }
type FieldStats struct { type FieldStats struct {

View File

@@ -1,85 +0,0 @@
package graphql
import (
"context"
"github.com/vektah/gqlparser/v2/ast"
"github.com/vektah/gqlparser/v2/gqlerror"
)
const fieldInputCtx key = "field_input_context"
type FieldInputContext struct {
ParentField *FieldContext
ParentInput *FieldInputContext
Field *string
Index *int
}
func (fic *FieldInputContext) Path() ast.Path {
var inputPath ast.Path
for it := fic; it != nil; it = it.ParentInput {
if it.Index != nil {
inputPath = append(inputPath, ast.PathIndex(*it.Index))
} else if it.Field != nil {
inputPath = append(inputPath, ast.PathName(*it.Field))
}
}
// because we are walking up the chain, all the elements are backwards, do an inplace flip.
for i := len(inputPath)/2 - 1; i >= 0; i-- {
opp := len(inputPath) - 1 - i
inputPath[i], inputPath[opp] = inputPath[opp], inputPath[i]
}
if fic.ParentField != nil {
fieldPath := fic.ParentField.Path()
return append(fieldPath, inputPath...)
}
return inputPath
}
func NewFieldInputWithField(field string) *FieldInputContext {
return &FieldInputContext{Field: &field}
}
func NewFieldInputWithIndex(index int) *FieldInputContext {
return &FieldInputContext{Index: &index}
}
func WithFieldInputContext(ctx context.Context, fic *FieldInputContext) context.Context {
if fieldContext := GetFieldContext(ctx); fieldContext != nil {
fic.ParentField = fieldContext
}
if fieldInputContext := GetFieldInputContext(ctx); fieldInputContext != nil {
fic.ParentInput = fieldInputContext
}
return context.WithValue(ctx, fieldInputCtx, fic)
}
func GetFieldInputContext(ctx context.Context) *FieldInputContext {
if val, ok := ctx.Value(fieldInputCtx).(*FieldInputContext); ok {
return val
}
return nil
}
func WrapErrorWithInputPath(ctx context.Context, err error) error {
if err == nil {
return nil
}
inputContext := GetFieldInputContext(ctx)
path := inputContext.Path()
if gerr, ok := err.(*gqlerror.Error); ok {
if gerr.Path == nil {
gerr.Path = path
}
return gerr
} else {
return gqlerror.WrapPath(path, err)
}
}

View File

@@ -18,8 +18,9 @@ type OperationContext struct {
Operation *ast.OperationDefinition Operation *ast.OperationDefinition
DisableIntrospection bool DisableIntrospection bool
Recover RecoverFunc RecoverFunc RecoverFunc
ResolverMiddleware FieldMiddleware ResolverMiddleware FieldMiddleware
RootResolverMiddleware RootFieldMiddleware
Stats Stats Stats Stats
} }
@@ -37,8 +38,11 @@ func (c *OperationContext) Validate(ctx context.Context) error {
if c.ResolverMiddleware == nil { if c.ResolverMiddleware == nil {
return errors.New("field 'ResolverMiddleware' is required") return errors.New("field 'ResolverMiddleware' is required")
} }
if c.Recover == nil { if c.RootResolverMiddleware == nil {
c.Recover = DefaultRecover return errors.New("field 'RootResolverMiddleware' is required")
}
if c.RecoverFunc == nil {
c.RecoverFunc = DefaultRecover
} }
return nil return nil
@@ -105,3 +109,7 @@ func (c *OperationContext) Errorf(ctx context.Context, format string, args ...in
func (c *OperationContext) Error(ctx context.Context, err error) { func (c *OperationContext) Error(ctx context.Context, err error) {
AddError(ctx, err) AddError(ctx, err)
} }
func (c *OperationContext) Recover(ctx context.Context, err interface{}) error {
return ErrorOnPath(ctx, c.RecoverFunc(ctx, err))
}

View File

@@ -0,0 +1,77 @@
package graphql
import (
"context"
"github.com/vektah/gqlparser/v2/ast"
)
const fieldInputCtx key = "path_context"
type PathContext struct {
ParentField *FieldContext
Parent *PathContext
Field *string
Index *int
}
func (fic *PathContext) Path() ast.Path {
var path ast.Path
for it := fic; it != nil; it = it.Parent {
if it.Index != nil {
path = append(path, ast.PathIndex(*it.Index))
} else if it.Field != nil {
path = append(path, ast.PathName(*it.Field))
}
}
// because we are walking up the chain, all the elements are backwards, do an inplace flip.
for i := len(path)/2 - 1; i >= 0; i-- {
opp := len(path) - 1 - i
path[i], path[opp] = path[opp], path[i]
}
if fic.ParentField != nil {
fieldPath := fic.ParentField.Path()
return append(fieldPath, path...)
}
return path
}
func NewPathWithField(field string) *PathContext {
return &PathContext{Field: &field}
}
func NewPathWithIndex(index int) *PathContext {
return &PathContext{Index: &index}
}
func WithPathContext(ctx context.Context, fic *PathContext) context.Context {
if fieldContext := GetFieldContext(ctx); fieldContext != nil {
fic.ParentField = fieldContext
}
if fieldInputContext := GetPathContext(ctx); fieldInputContext != nil {
fic.Parent = fieldInputContext
}
return context.WithValue(ctx, fieldInputCtx, fic)
}
func GetPathContext(ctx context.Context) *PathContext {
if val, ok := ctx.Value(fieldInputCtx).(*PathContext); ok {
return val
}
return nil
}
func GetPath(ctx context.Context) ast.Path {
if pc := GetPathContext(ctx); pc != nil {
return pc.Path()
}
if fc := GetFieldContext(ctx); fc != nil {
return fc.Path()
}
return nil
}

View File

@@ -38,27 +38,23 @@ func WithResponseContext(ctx context.Context, presenterFunc ErrorPresenterFunc,
// AddErrorf writes a formatted error to the client, first passing it through the error presenter. // AddErrorf writes a formatted error to the client, first passing it through the error presenter.
func AddErrorf(ctx context.Context, format string, args ...interface{}) { func AddErrorf(ctx context.Context, format string, args ...interface{}) {
c := getResponseContext(ctx) AddError(ctx, fmt.Errorf(format, args...))
c.errorsMu.Lock()
defer c.errorsMu.Unlock()
c.errors = append(c.errors, c.errorPresenter(ctx, fmt.Errorf(format, args...)))
} }
// AddError sends an error to the client, first passing it through the error presenter. // AddError sends an error to the client, first passing it through the error presenter.
func AddError(ctx context.Context, err error) { func AddError(ctx context.Context, err error) {
c := getResponseContext(ctx) c := getResponseContext(ctx)
presentedError := c.errorPresenter(ctx, ErrorOnPath(ctx, err))
c.errorsMu.Lock() c.errorsMu.Lock()
defer c.errorsMu.Unlock() defer c.errorsMu.Unlock()
c.errors = append(c.errors, presentedError)
c.errors = append(c.errors, c.errorPresenter(ctx, err))
} }
func Recover(ctx context.Context, err interface{}) (userMessage error) { func Recover(ctx context.Context, err interface{}) (userMessage error) {
c := getResponseContext(ctx) c := getResponseContext(ctx)
return c.recover(ctx, err) return ErrorOnPath(ctx, c.recover(ctx, err))
} }
// HasFieldError returns true if the given field has already errored // HasFieldError returns true if the given field has already errored

View File

@@ -0,0 +1,25 @@
package graphql
import (
"context"
)
const rootResolverCtx key = "root_resolver_context"
type RootFieldContext struct {
// The name of the type this field belongs to
Object string
// The raw field
Field CollectedField
}
func GetRootFieldContext(ctx context.Context) *RootFieldContext {
if val, ok := ctx.Value(rootResolverCtx).(*RootFieldContext); ok {
return val
}
return nil
}
func WithRootFieldContext(ctx context.Context, rc *RootFieldContext) context.Context {
return context.WithValue(ctx, rootResolverCtx, rc)
}

View File

@@ -4,8 +4,10 @@ import (
"github.com/vektah/gqlparser/v2/gqlerror" "github.com/vektah/gqlparser/v2/gqlerror"
) )
const ValidationFailed = "GRAPHQL_VALIDATION_FAILED" const (
const ParseFailed = "GRAPHQL_PARSE_FAILED" ValidationFailed = "GRAPHQL_VALIDATION_FAILED"
ParseFailed = "GRAPHQL_PARSE_FAILED"
)
type ErrorKind int type ErrorKind int

View File

@@ -2,32 +2,31 @@ package graphql
import ( import (
"context" "context"
"errors"
"github.com/vektah/gqlparser/v2/gqlerror" "github.com/vektah/gqlparser/v2/gqlerror"
) )
type ErrorPresenterFunc func(ctx context.Context, err error) *gqlerror.Error type ErrorPresenterFunc func(ctx context.Context, err error) *gqlerror.Error
type ExtendedError interface {
Extensions() map[string]interface{}
}
func DefaultErrorPresenter(ctx context.Context, err error) *gqlerror.Error { func DefaultErrorPresenter(ctx context.Context, err error) *gqlerror.Error {
if gqlerr, ok := err.(*gqlerror.Error); ok { var gqlErr *gqlerror.Error
if gqlerr.Path == nil { if errors.As(err, &gqlErr) {
gqlerr.Path = GetFieldContext(ctx).Path() return gqlErr
} }
return gqlerr return gqlerror.WrapPath(GetPath(ctx), err)
} }
var extensions map[string]interface{} func ErrorOnPath(ctx context.Context, err error) error {
if ee, ok := err.(ExtendedError); ok { if err == nil {
extensions = ee.Extensions() return nil
} }
var gqlErr *gqlerror.Error
return &gqlerror.Error{ if errors.As(err, &gqlErr) {
Message: err.Error(), if gqlErr.Path == nil {
Path: GetFieldContext(ctx).Path(), gqlErr.Path = GetPath(ctx)
Extensions: extensions,
} }
return gqlErr
}
return gqlerror.WrapPath(GetPath(ctx), err)
} }

View File

@@ -32,11 +32,12 @@ func collectFields(reqCtx *OperationContext, selSet ast.SelectionSet, satisfies
if !shouldIncludeNode(sel.Directives, reqCtx.Variables) { if !shouldIncludeNode(sel.Directives, reqCtx.Variables) {
continue continue
} }
f := getOrCreateAndAppendField(&groupedFields, sel.Alias, sel.ObjectDefinition, func() CollectedField { f := getOrCreateAndAppendField(&groupedFields, sel.Name, sel.Alias, sel.ObjectDefinition, func() CollectedField {
return CollectedField{Field: sel} return CollectedField{Field: sel}
}) })
f.Selections = append(f.Selections, sel.SelectionSet...) f.Selections = append(f.Selections, sel.SelectionSet...)
case *ast.InlineFragment: case *ast.InlineFragment:
if !shouldIncludeNode(sel.Directives, reqCtx.Variables) { if !shouldIncludeNode(sel.Directives, reqCtx.Variables) {
continue continue
@@ -45,7 +46,7 @@ func collectFields(reqCtx *OperationContext, selSet ast.SelectionSet, satisfies
continue continue
} }
for _, childField := range collectFields(reqCtx, sel.SelectionSet, satisfies, visited) { for _, childField := range collectFields(reqCtx, sel.SelectionSet, satisfies, visited) {
f := getOrCreateAndAppendField(&groupedFields, childField.Name, childField.ObjectDefinition, func() CollectedField { return childField }) f := getOrCreateAndAppendField(&groupedFields, childField.Name, childField.Alias, childField.ObjectDefinition, func() CollectedField { return childField })
f.Selections = append(f.Selections, childField.Selections...) f.Selections = append(f.Selections, childField.Selections...)
} }
@@ -70,9 +71,10 @@ func collectFields(reqCtx *OperationContext, selSet ast.SelectionSet, satisfies
} }
for _, childField := range collectFields(reqCtx, fragment.SelectionSet, satisfies, visited) { for _, childField := range collectFields(reqCtx, fragment.SelectionSet, satisfies, visited) {
f := getOrCreateAndAppendField(&groupedFields, childField.Name, childField.ObjectDefinition, func() CollectedField { return childField }) f := getOrCreateAndAppendField(&groupedFields, childField.Name, childField.Alias, childField.ObjectDefinition, func() CollectedField { return childField })
f.Selections = append(f.Selections, childField.Selections...) f.Selections = append(f.Selections, childField.Selections...)
} }
default: default:
panic(fmt.Errorf("unsupported %T", sel)) panic(fmt.Errorf("unsupported %T", sel))
} }
@@ -96,11 +98,27 @@ func instanceOf(val string, satisfies []string) bool {
return false return false
} }
func getOrCreateAndAppendField(c *[]CollectedField, name string, objectDefinition *ast.Definition, creator func() CollectedField) *CollectedField { func getOrCreateAndAppendField(c *[]CollectedField, name string, alias string, objectDefinition *ast.Definition, creator func() CollectedField) *CollectedField {
for i, cf := range *c { for i, cf := range *c {
if cf.Alias == name && (cf.ObjectDefinition == objectDefinition || (cf.ObjectDefinition != nil && objectDefinition != nil && cf.ObjectDefinition.Name == objectDefinition.Name)) { if cf.Name == name && cf.Alias == alias {
if cf.ObjectDefinition == objectDefinition {
return &(*c)[i] 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() f := creator()

View File

@@ -9,12 +9,6 @@ import (
"sync" "sync"
) )
var (
lockExecutableSchemaMockComplexity sync.RWMutex
lockExecutableSchemaMockExec sync.RWMutex
lockExecutableSchemaMockSchema sync.RWMutex
)
// Ensure, that ExecutableSchemaMock does implement ExecutableSchema. // Ensure, that ExecutableSchemaMock does implement ExecutableSchema.
// If this is not the case, regenerate this file with moq. // If this is not the case, regenerate this file with moq.
var _ ExecutableSchema = &ExecutableSchemaMock{} var _ ExecutableSchema = &ExecutableSchemaMock{}
@@ -72,6 +66,9 @@ type ExecutableSchemaMock struct {
Schema []struct { Schema []struct {
} }
} }
lockComplexity sync.RWMutex
lockExec sync.RWMutex
lockSchema sync.RWMutex
} }
// Complexity calls ComplexityFunc. // Complexity calls ComplexityFunc.
@@ -90,9 +87,9 @@ func (mock *ExecutableSchemaMock) Complexity(typeName string, fieldName string,
ChildComplexity: childComplexity, ChildComplexity: childComplexity,
Args: args, Args: args,
} }
lockExecutableSchemaMockComplexity.Lock() mock.lockComplexity.Lock()
mock.calls.Complexity = append(mock.calls.Complexity, callInfo) mock.calls.Complexity = append(mock.calls.Complexity, callInfo)
lockExecutableSchemaMockComplexity.Unlock() mock.lockComplexity.Unlock()
return mock.ComplexityFunc(typeName, fieldName, childComplexity, args) return mock.ComplexityFunc(typeName, fieldName, childComplexity, args)
} }
@@ -111,9 +108,9 @@ func (mock *ExecutableSchemaMock) ComplexityCalls() []struct {
ChildComplexity int ChildComplexity int
Args map[string]interface{} Args map[string]interface{}
} }
lockExecutableSchemaMockComplexity.RLock() mock.lockComplexity.RLock()
calls = mock.calls.Complexity calls = mock.calls.Complexity
lockExecutableSchemaMockComplexity.RUnlock() mock.lockComplexity.RUnlock()
return calls return calls
} }
@@ -127,9 +124,9 @@ func (mock *ExecutableSchemaMock) Exec(ctx context.Context) ResponseHandler {
}{ }{
Ctx: ctx, Ctx: ctx,
} }
lockExecutableSchemaMockExec.Lock() mock.lockExec.Lock()
mock.calls.Exec = append(mock.calls.Exec, callInfo) mock.calls.Exec = append(mock.calls.Exec, callInfo)
lockExecutableSchemaMockExec.Unlock() mock.lockExec.Unlock()
return mock.ExecFunc(ctx) return mock.ExecFunc(ctx)
} }
@@ -142,9 +139,9 @@ func (mock *ExecutableSchemaMock) ExecCalls() []struct {
var calls []struct { var calls []struct {
Ctx context.Context Ctx context.Context
} }
lockExecutableSchemaMockExec.RLock() mock.lockExec.RLock()
calls = mock.calls.Exec calls = mock.calls.Exec
lockExecutableSchemaMockExec.RUnlock() mock.lockExec.RUnlock()
return calls return calls
} }
@@ -155,9 +152,9 @@ func (mock *ExecutableSchemaMock) Schema() *ast.Schema {
} }
callInfo := struct { callInfo := struct {
}{} }{}
lockExecutableSchemaMockSchema.Lock() mock.lockSchema.Lock()
mock.calls.Schema = append(mock.calls.Schema, callInfo) mock.calls.Schema = append(mock.calls.Schema, callInfo)
lockExecutableSchemaMockSchema.Unlock() mock.lockSchema.Unlock()
return mock.SchemaFunc() return mock.SchemaFunc()
} }
@@ -168,8 +165,8 @@ func (mock *ExecutableSchemaMock) SchemaCalls() []struct {
} { } {
var calls []struct { var calls []struct {
} }
lockExecutableSchemaMockSchema.RLock() mock.lockSchema.RLock()
calls = mock.calls.Schema calls = mock.calls.Schema
lockExecutableSchemaMockSchema.RUnlock() mock.lockSchema.RUnlock()
return calls return calls
} }

View File

@@ -40,8 +40,9 @@ func New(es graphql.ExecutableSchema) *Executor {
func (e *Executor) CreateOperationContext(ctx context.Context, params *graphql.RawParams) (*graphql.OperationContext, gqlerror.List) { func (e *Executor) CreateOperationContext(ctx context.Context, params *graphql.RawParams) (*graphql.OperationContext, gqlerror.List) {
rc := &graphql.OperationContext{ rc := &graphql.OperationContext{
DisableIntrospection: true, DisableIntrospection: true,
Recover: e.recoverFunc, RecoverFunc: e.recoverFunc,
ResolverMiddleware: e.ext.fieldMiddleware, ResolverMiddleware: e.ext.fieldMiddleware,
RootResolverMiddleware: e.ext.rootFieldMiddleware,
Stats: graphql.Stats{ Stats: graphql.Stats{
Read: params.ReadTime, Read: params.ReadTime,
OperationStart: graphql.GetStartTime(ctx), OperationStart: graphql.GetStartTime(ctx),

View File

@@ -17,6 +17,7 @@ func (e *Executor) Use(extension graphql.HandlerExtension) {
case graphql.OperationParameterMutator, case graphql.OperationParameterMutator,
graphql.OperationContextMutator, graphql.OperationContextMutator,
graphql.OperationInterceptor, graphql.OperationInterceptor,
graphql.RootFieldInterceptor,
graphql.FieldInterceptor, graphql.FieldInterceptor,
graphql.ResponseInterceptor: graphql.ResponseInterceptor:
e.extensions = append(e.extensions, extension) e.extensions = append(e.extensions, extension)
@@ -32,6 +33,11 @@ func (e *Executor) AroundFields(f graphql.FieldMiddleware) {
e.Use(aroundFieldFunc(f)) 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 // AroundOperations is a convenience method for creating an extension that only implements operation middleware
func (e *Executor) AroundOperations(f graphql.OperationMiddleware) { func (e *Executor) AroundOperations(f graphql.OperationMiddleware) {
e.Use(aroundOpFunc(f)) e.Use(aroundOpFunc(f))
@@ -45,6 +51,7 @@ func (e *Executor) AroundResponses(f graphql.ResponseMiddleware) {
type extensions struct { type extensions struct {
operationMiddleware graphql.OperationMiddleware operationMiddleware graphql.OperationMiddleware
responseMiddleware graphql.ResponseMiddleware responseMiddleware graphql.ResponseMiddleware
rootFieldMiddleware graphql.RootFieldMiddleware
fieldMiddleware graphql.FieldMiddleware fieldMiddleware graphql.FieldMiddleware
operationParameterMutators []graphql.OperationParameterMutator operationParameterMutators []graphql.OperationParameterMutator
operationContextMutators []graphql.OperationContextMutator operationContextMutators []graphql.OperationContextMutator
@@ -58,6 +65,9 @@ func processExtensions(exts []graphql.HandlerExtension) extensions {
responseMiddleware: func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response { responseMiddleware: func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
return next(ctx) 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) { fieldMiddleware: func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
return next(ctx) return next(ctx)
}, },
@@ -84,6 +94,15 @@ func processExtensions(exts []graphql.HandlerExtension) extensions {
} }
} }
if p, ok := p.(graphql.RootFieldInterceptor); ok {
previous := e.rootFieldMiddleware
e.rootFieldMiddleware = func(ctx context.Context, next graphql.RootResolver) graphql.Marshaler {
return p.InterceptRootField(ctx, func(ctx context.Context) graphql.Marshaler {
return previous(ctx, next)
})
}
}
if p, ok := p.(graphql.FieldInterceptor); ok { if p, ok := p.(graphql.FieldInterceptor); ok {
previous := e.fieldMiddleware previous := e.fieldMiddleware
e.fieldMiddleware = func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) { e.fieldMiddleware = func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
@@ -157,3 +176,20 @@ func (f aroundFieldFunc) Validate(schema graphql.ExecutableSchema) error {
func (f aroundFieldFunc) InterceptField(ctx context.Context, next graphql.Resolver) (res interface{}, err error) { func (f aroundFieldFunc) InterceptField(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
return f(ctx, next) 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)
}

View File

@@ -1,9 +1,11 @@
package graphql package graphql
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"math"
"strconv" "strconv"
) )
@@ -29,3 +31,17 @@ func UnmarshalFloat(v interface{}) (float64, error) {
return 0, fmt.Errorf("%T is not an float", v) 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)
}

View File

@@ -19,6 +19,9 @@ type (
Resolver func(ctx context.Context) (res interface{}, err error) Resolver func(ctx context.Context) (res interface{}, err error)
FieldMiddleware func(ctx context.Context, next Resolver) (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 { RawParams struct {
Query string `json:"query"` Query string `json:"query"`
OperationName string `json:"operationName"` OperationName string `json:"operationName"`
@@ -76,6 +79,10 @@ type (
InterceptResponse(ctx context.Context, next ResponseHandler) *Response InterceptResponse(ctx context.Context, next ResponseHandler) *Response
} }
RootFieldInterceptor interface {
InterceptRootField(ctx context.Context, next RootResolver) Marshaler
}
// FieldInterceptor called around each field // FieldInterceptor called around each field
FieldInterceptor interface { FieldInterceptor interface {
InterceptField(ctx context.Context, next Resolver) (res interface{}, err error) InterceptField(ctx context.Context, next Resolver) (res interface{}, err error)

View File

@@ -14,8 +14,10 @@ import (
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
) )
const errPersistedQueryNotFound = "PersistedQueryNotFound" const (
const errPersistedQueryNotFoundCode = "PERSISTED_QUERY_NOT_FOUND" errPersistedQueryNotFound = "PersistedQueryNotFound"
errPersistedQueryNotFoundCode = "PERSISTED_QUERY_NOT_FOUND"
)
// AutomaticPersistedQuery saves client upload by optimistically sending only the hashes of queries, if the server // 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 // does not yet know what the query is for the hash it will respond telling the client to send the query along with the

View File

@@ -74,6 +74,11 @@ func (s *Server) AroundFields(f graphql.FieldMiddleware) {
s.exec.AroundFields(f) 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 // AroundOperations is a convenience method for creating an extension that only implements operation middleware
func (s *Server) AroundOperations(f graphql.OperationMiddleware) { func (s *Server) AroundOperations(f graphql.OperationMiddleware) {
s.exec.AroundOperations(f) s.exec.AroundOperations(f)

View File

@@ -83,7 +83,7 @@ func (f MultipartForm) Do(w http.ResponseWriter, r *http.Request, exec graphql.G
return return
} }
var uploadsMap = map[string][]string{} uploadsMap := map[string][]string{}
if err = json.Unmarshal([]byte(r.Form.Get("map")), &uploadsMap); err != nil { if err = json.Unmarshal([]byte(r.Form.Get("map")), &uploadsMap); err != nil {
w.WriteHeader(http.StatusUnprocessableEntity) w.WriteHeader(http.StatusUnprocessableEntity)
writeJsonError(w, "map form field could not be decoded") writeJsonError(w, "map form field could not be decoded")

View File

@@ -48,7 +48,6 @@ func (h POST) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecu
writeJson(w, resp) writeJson(w, resp)
return return
} }
ctx := graphql.WithOperationContext(r.Context(), rc) responses, ctx := exec.DispatchOperation(r.Context(), rc)
responses, ctx := exec.DispatchOperation(ctx, rc)
writeJson(w, responses(ctx)) writeJson(w, responses(ctx))
} }

View File

@@ -18,8 +18,8 @@ func (o Options) Supports(r *http.Request) bool {
func (o Options) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) { func (o Options) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) {
switch r.Method { switch r.Method {
case http.MethodOptions: case http.MethodOptions:
w.WriteHeader(http.StatusOK)
w.Header().Set("Allow", "OPTIONS, GET, POST") w.Header().Set("Allow", "OPTIONS, GET, POST")
w.WriteHeader(http.StatusOK)
case http.MethodHead: case http.MethodHead:
w.WriteHeader(http.StatusMethodNotAllowed) w.WriteHeader(http.StatusMethodNotAllowed)
} }

View File

@@ -4,8 +4,10 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"log" "log"
"net"
"net/http" "net/http"
"sync" "sync"
"time" "time"
@@ -16,44 +18,37 @@ import (
"github.com/vektah/gqlparser/v2/gqlerror" "github.com/vektah/gqlparser/v2/gqlerror"
) )
const (
connectionInitMsg = "connection_init" // Client -> Server
connectionTerminateMsg = "connection_terminate" // Client -> Server
startMsg = "start" // Client -> Server
stopMsg = "stop" // Client -> Server
connectionAckMsg = "connection_ack" // Server -> Client
connectionErrorMsg = "connection_error" // Server -> Client
dataMsg = "data" // Server -> Client
errorMsg = "error" // Server -> Client
completeMsg = "complete" // Server -> Client
connectionKeepAliveMsg = "ka" // Server -> Client
)
type ( type (
Websocket struct { Websocket struct {
Upgrader websocket.Upgrader Upgrader websocket.Upgrader
InitFunc WebsocketInitFunc InitFunc WebsocketInitFunc
InitTimeout time.Duration
ErrorFunc WebsocketErrorFunc
KeepAlivePingInterval time.Duration KeepAlivePingInterval time.Duration
PingPongInterval time.Duration
didInjectSubprotocols bool
} }
wsConnection struct { wsConnection struct {
Websocket Websocket
ctx context.Context ctx context.Context
conn *websocket.Conn conn *websocket.Conn
me messageExchanger
active map[string]context.CancelFunc active map[string]context.CancelFunc
mu sync.Mutex mu sync.Mutex
keepAliveTicker *time.Ticker keepAliveTicker *time.Ticker
pingPongTicker *time.Ticker
exec graphql.GraphExecutor exec graphql.GraphExecutor
initPayload InitPayload initPayload InitPayload
} }
operationMessage struct {
Payload json.RawMessage `json:"payload,omitempty"`
ID string `json:"id,omitempty"`
Type string `json:"type"`
}
WebsocketInitFunc func(ctx context.Context, initPayload InitPayload) (context.Context, error) WebsocketInitFunc func(ctx context.Context, initPayload InitPayload) (context.Context, error)
WebsocketErrorFunc func(ctx context.Context, err error)
) )
var errReadTimeout = errors.New("read timeout")
var _ graphql.Transport = Websocket{} var _ graphql.Transport = Websocket{}
func (t Websocket) Supports(r *http.Request) bool { func (t Websocket) Supports(r *http.Request) bool {
@@ -61,20 +56,34 @@ func (t Websocket) Supports(r *http.Request) bool {
} }
func (t Websocket) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) { func (t Websocket) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) {
ws, err := t.Upgrader.Upgrade(w, r, http.Header{ t.injectGraphQLWSSubprotocols()
"Sec-Websocket-Protocol": []string{"graphql-ws"}, ws, err := t.Upgrader.Upgrade(w, r, http.Header{})
})
if err != nil { if err != nil {
log.Printf("unable to upgrade %T to websocket %s: ", w, err.Error()) log.Printf("unable to upgrade %T to websocket %s: ", w, err.Error())
SendErrorf(w, http.StatusBadRequest, "unable to upgrade") SendErrorf(w, http.StatusBadRequest, "unable to upgrade")
return 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{ conn := wsConnection{
active: map[string]context.CancelFunc{}, active: map[string]context.CancelFunc{},
conn: ws, conn: ws,
ctx: r.Context(), ctx: r.Context(),
exec: exec, exec: exec,
me: me,
Websocket: t, Websocket: t,
} }
@@ -85,18 +94,62 @@ func (t Websocket) Do(w http.ResponseWriter, r *http.Request, exec graphql.Graph
conn.run() 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 { func (c *wsConnection) init() bool {
message := c.readOp() var m message
if message == nil { 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") c.close(websocket.CloseProtocolError, "decoding error")
return false return false
} }
switch message.Type { switch m.t {
case connectionInitMsg: case initMessageType:
if len(message.Payload) > 0 { if len(m.payload) > 0 {
c.initPayload = make(InitPayload) c.initPayload = make(InitPayload)
err := json.Unmarshal(message.Payload, &c.initPayload) err := json.Unmarshal(m.payload, &c.initPayload)
if err != nil { if err != nil {
return false return false
} }
@@ -112,13 +165,13 @@ func (c *wsConnection) init() bool {
c.ctx = ctx c.ctx = ctx
} }
c.write(&operationMessage{Type: connectionAckMsg}) c.write(&message{t: connectionAckMessageType})
c.write(&operationMessage{Type: connectionKeepAliveMsg}) c.write(&message{t: keepAliveMessageType})
case connectionTerminateMsg: case connectionCloseMessageType:
c.close(websocket.CloseNormalClosure, "terminated") c.close(websocket.CloseNormalClosure, "terminated")
return false return false
default: default:
c.sendConnectionError("unexpected message %s", message.Type) c.sendConnectionError("unexpected message %s", m.t)
c.close(websocket.CloseProtocolError, "unexpected message") c.close(websocket.CloseProtocolError, "unexpected message")
return false return false
} }
@@ -126,9 +179,9 @@ func (c *wsConnection) init() bool {
return true return true
} }
func (c *wsConnection) write(msg *operationMessage) { func (c *wsConnection) write(msg *message) {
c.mu.Lock() c.mu.Lock()
c.conn.WriteJSON(msg) c.handlePossibleError(c.me.Send(msg))
c.mu.Unlock() c.mu.Unlock()
} }
@@ -141,8 +194,9 @@ func (c *wsConnection) run() {
c.close(websocket.CloseAbnormalClosure, "unexpected closure") c.close(websocket.CloseAbnormalClosure, "unexpected closure")
}() }()
// Create a timer that will fire every interval to keep the connection alive. // If we're running in graphql-ws mode, create a timer that will trigger a
if c.KeepAlivePingInterval != 0 { // keep alive message every interval
if (c.conn.Subprotocol() == "" || c.conn.Subprotocol() == graphqlwsSubprotocol) && c.KeepAlivePingInterval != 0 {
c.mu.Lock() c.mu.Lock()
c.keepAliveTicker = time.NewTicker(c.KeepAlivePingInterval) c.keepAliveTicker = time.NewTicker(c.KeepAlivePingInterval)
c.mu.Unlock() c.mu.Unlock()
@@ -150,28 +204,53 @@ func (c *wsConnection) run() {
go c.keepAlive(ctx) 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 { for {
start := graphql.Now() start := graphql.Now()
message := c.readOp() m, err := c.me.NextMessage()
if message == nil { 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 return
} }
switch message.Type { switch m.t {
case startMsg: case startMessageType:
c.subscribe(start, message) c.subscribe(start, &m)
case stopMsg: case stopMessageType:
c.mu.Lock() c.mu.Lock()
closer := c.active[message.ID] closer := c.active[m.id]
c.mu.Unlock() c.mu.Unlock()
if closer != nil { if closer != nil {
closer() closer()
} }
case connectionTerminateMsg: case connectionCloseMessageType:
c.close(websocket.CloseNormalClosure, "terminated") c.close(websocket.CloseNormalClosure, "terminated")
return return
case pingMessageType:
c.write(&message{t: pongMessageType, payload: m.payload})
case pongMessageType:
c.conn.SetReadDeadline(time.Now().UTC().Add(2 * c.PingPongInterval))
default: default:
c.sendConnectionError("unexpected message %s", message.Type) c.sendConnectionError("unexpected message %s", m.t)
c.close(websocket.CloseProtocolError, "unexpected message") c.close(websocket.CloseProtocolError, "unexpected message")
return return
} }
@@ -185,17 +264,38 @@ func (c *wsConnection) keepAlive(ctx context.Context) {
c.keepAliveTicker.Stop() c.keepAliveTicker.Stop()
return return
case <-c.keepAliveTicker.C: case <-c.keepAliveTicker.C:
c.write(&operationMessage{Type: connectionKeepAliveMsg}) c.write(&message{t: keepAliveMessageType})
} }
} }
} }
func (c *wsConnection) subscribe(start time.Time, message *operationMessage) { func (c *wsConnection) ping(ctx context.Context) {
for {
select {
case <-ctx.Done():
c.pingPongTicker.Stop()
return
case <-c.pingPongTicker.C:
c.write(&message{t: pingMessageType, payload: json.RawMessage{}})
}
}
}
func (c *wsConnection) closeOnCancel(ctx context.Context) {
<-ctx.Done()
if r := closeReasonForContext(ctx); r != "" {
c.sendConnectionError(r)
}
c.close(websocket.CloseNormalClosure, "terminated")
}
func (c *wsConnection) subscribe(start time.Time, msg *message) {
ctx := graphql.StartOperationTrace(c.ctx) ctx := graphql.StartOperationTrace(c.ctx)
var params *graphql.RawParams var params *graphql.RawParams
if err := jsonDecode(bytes.NewReader(message.Payload), &params); err != nil { if err := jsonDecode(bytes.NewReader(msg.payload), &params); err != nil {
c.sendError(message.ID, &gqlerror.Error{Message: "invalid json"}) c.sendError(msg.id, &gqlerror.Error{Message: "invalid json"})
c.complete(message.ID) c.complete(msg.id)
return return
} }
@@ -209,12 +309,12 @@ func (c *wsConnection) subscribe(start time.Time, message *operationMessage) {
resp := c.exec.DispatchError(graphql.WithOperationContext(ctx, rc), err) resp := c.exec.DispatchError(graphql.WithOperationContext(ctx, rc), err)
switch errcode.GetErrorKind(err) { switch errcode.GetErrorKind(err) {
case errcode.KindProtocol: case errcode.KindProtocol:
c.sendError(message.ID, resp.Errors...) c.sendError(msg.id, resp.Errors...)
default: default:
c.sendResponse(message.ID, &graphql.Response{Errors: err}) c.sendResponse(msg.id, &graphql.Response{Errors: err})
} }
c.complete(message.ID) c.complete(msg.id)
return return
} }
@@ -226,16 +326,29 @@ func (c *wsConnection) subscribe(start time.Time, message *operationMessage) {
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
c.mu.Lock() c.mu.Lock()
c.active[message.ID] = cancel c.active[msg.id] = cancel
c.mu.Unlock() c.mu.Unlock()
go func() { go func() {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
userErr := rc.Recover(ctx, r) err := rc.Recover(ctx, r)
c.sendError(message.ID, &gqlerror.Error{Message: userErr.Error()}) 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) responses, ctx := c.exec.DispatchOperation(ctx, rc)
for { for {
response := responses(ctx) response := responses(ctx)
@@ -243,12 +356,12 @@ func (c *wsConnection) subscribe(start time.Time, message *operationMessage) {
break break
} }
c.sendResponse(message.ID, response) c.sendResponse(msg.id, response)
} }
c.complete(message.ID) c.complete(msg.id)
c.mu.Lock() c.mu.Lock()
delete(c.active, message.ID) delete(c.active, msg.id)
c.mu.Unlock() c.mu.Unlock()
cancel() cancel()
}() }()
@@ -259,15 +372,15 @@ func (c *wsConnection) sendResponse(id string, response *graphql.Response) {
if err != nil { if err != nil {
panic(err) panic(err)
} }
c.write(&operationMessage{ c.write(&message{
Payload: b, payload: b,
ID: id, id: id,
Type: dataMsg, t: dataMessageType,
}) })
} }
func (c *wsConnection) complete(id string) { func (c *wsConnection) complete(id string) {
c.write(&operationMessage{ID: id, Type: completeMsg}) c.write(&message{id: id, t: completeMessageType})
} }
func (c *wsConnection) sendError(id string, errors ...*gqlerror.Error) { func (c *wsConnection) sendError(id string, errors ...*gqlerror.Error) {
@@ -279,7 +392,7 @@ func (c *wsConnection) sendError(id string, errors ...*gqlerror.Error) {
if err != nil { if err != nil {
panic(err) panic(err)
} }
c.write(&operationMessage{Type: errorMsg, ID: id, Payload: b}) c.write(&message{t: errorMessageType, id: id, payload: b})
} }
func (c *wsConnection) sendConnectionError(format string, args ...interface{}) { func (c *wsConnection) sendConnectionError(format string, args ...interface{}) {
@@ -288,29 +401,15 @@ func (c *wsConnection) sendConnectionError(format string, args ...interface{}) {
panic(err) panic(err)
} }
c.write(&operationMessage{Type: connectionErrorMsg, Payload: b}) c.write(&message{t: connectionErrorMessageType, payload: b})
}
func (c *wsConnection) readOp() *operationMessage {
_, r, err := c.conn.NextReader()
if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) {
return nil
} else if err != nil {
c.sendConnectionError("invalid json: %T %s", err, err.Error())
return nil
}
message := operationMessage{}
if err := jsonDecode(r, &message); err != nil {
c.sendConnectionError("invalid json")
return nil
}
return &message
} }
func (c *wsConnection) close(closeCode int, message string) { func (c *wsConnection) close(closeCode int, message string) {
c.mu.Lock() c.mu.Lock()
_ = c.conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(closeCode, message)) _ = c.conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(closeCode, message))
for _, closer := range c.active {
closer()
}
c.mu.Unlock() c.mu.Unlock()
_ = c.conn.Close() _ = c.conn.Close()
} }

View File

@@ -0,0 +1,22 @@
package transport
import (
"context"
)
// A private key for context that only this package can access. This is important
// to prevent collisions between different context uses
var closeReasonCtxKey = &wsCloseReasonContextKey{"close-reason"}
type wsCloseReasonContextKey struct {
name string
}
func AppendCloseReason(ctx context.Context, reason string) context.Context {
return context.WithValue(ctx, closeReasonCtxKey, reason)
}
func closeReasonForContext(ctx context.Context) string {
reason, _ := ctx.Value(closeReasonCtxKey).(string)
return reason
}

View File

@@ -0,0 +1,149 @@
package transport
import (
"encoding/json"
"fmt"
"github.com/gorilla/websocket"
)
// https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md
const (
graphqltransportwsSubprotocol = "graphql-transport-ws"
graphqltransportwsConnectionInitMsg = graphqltransportwsMessageType("connection_init")
graphqltransportwsConnectionAckMsg = graphqltransportwsMessageType("connection_ack")
graphqltransportwsSubscribeMsg = graphqltransportwsMessageType("subscribe")
graphqltransportwsNextMsg = graphqltransportwsMessageType("next")
graphqltransportwsErrorMsg = graphqltransportwsMessageType("error")
graphqltransportwsCompleteMsg = graphqltransportwsMessageType("complete")
graphqltransportwsPingMsg = graphqltransportwsMessageType("ping")
graphqltransportwsPongMsg = graphqltransportwsMessageType("pong")
)
var allGraphqltransportwsMessageTypes = []graphqltransportwsMessageType{
graphqltransportwsConnectionInitMsg,
graphqltransportwsConnectionAckMsg,
graphqltransportwsSubscribeMsg,
graphqltransportwsNextMsg,
graphqltransportwsErrorMsg,
graphqltransportwsCompleteMsg,
graphqltransportwsPingMsg,
graphqltransportwsPongMsg,
}
type (
graphqltransportwsMessageExchanger struct {
c *websocket.Conn
}
graphqltransportwsMessage struct {
Payload json.RawMessage `json:"payload,omitempty"`
ID string `json:"id,omitempty"`
Type graphqltransportwsMessageType `json:"type"`
noOp bool
}
graphqltransportwsMessageType string
)
func (me graphqltransportwsMessageExchanger) NextMessage() (message, error) {
_, r, err := me.c.NextReader()
if err != nil {
return message{}, handleNextReaderError(err)
}
var graphqltransportwsMessage graphqltransportwsMessage
if err := jsonDecode(r, &graphqltransportwsMessage); err != nil {
return message{}, errInvalidMsg
}
return graphqltransportwsMessage.toMessage()
}
func (me graphqltransportwsMessageExchanger) Send(m *message) error {
msg := &graphqltransportwsMessage{}
if err := msg.fromMessage(m); err != nil {
return err
}
if msg.noOp {
return nil
}
return me.c.WriteJSON(msg)
}
func (t *graphqltransportwsMessageType) UnmarshalText(text []byte) (err error) {
var found bool
for _, candidate := range allGraphqltransportwsMessageTypes {
if string(candidate) == string(text) {
*t = candidate
found = true
break
}
}
if !found {
err = fmt.Errorf("invalid message type %s", string(text))
}
return err
}
func (t graphqltransportwsMessageType) MarshalText() ([]byte, error) {
return []byte(string(t)), nil
}
func (m graphqltransportwsMessage) toMessage() (message, error) {
var t messageType
var err error
switch m.Type {
default:
err = fmt.Errorf("invalid client->server message type %s", m.Type)
case graphqltransportwsConnectionInitMsg:
t = initMessageType
case graphqltransportwsSubscribeMsg:
t = startMessageType
case graphqltransportwsCompleteMsg:
t = stopMessageType
case graphqltransportwsPingMsg:
t = pingMessageType
case graphqltransportwsPongMsg:
t = pongMessageType
}
return message{
payload: m.Payload,
id: m.ID,
t: t,
}, err
}
func (m *graphqltransportwsMessage) fromMessage(msg *message) (err error) {
m.ID = msg.id
m.Payload = msg.payload
switch msg.t {
default:
err = fmt.Errorf("invalid server->client message type %s", msg.t)
case connectionAckMessageType:
m.Type = graphqltransportwsConnectionAckMsg
case keepAliveMessageType:
m.noOp = true
case connectionErrorMessageType:
m.noOp = true
case dataMessageType:
m.Type = graphqltransportwsNextMsg
case completeMessageType:
m.Type = graphqltransportwsCompleteMsg
case errorMessageType:
m.Type = graphqltransportwsErrorMsg
case pingMessageType:
m.Type = graphqltransportwsPingMsg
case pongMessageType:
m.Type = graphqltransportwsPongMsg
}
return err
}

View File

@@ -0,0 +1,171 @@
package transport
import (
"encoding/json"
"fmt"
"github.com/gorilla/websocket"
)
// https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md
const (
graphqlwsSubprotocol = "graphql-ws"
graphqlwsConnectionInitMsg = graphqlwsMessageType("connection_init")
graphqlwsConnectionTerminateMsg = graphqlwsMessageType("connection_terminate")
graphqlwsStartMsg = graphqlwsMessageType("start")
graphqlwsStopMsg = graphqlwsMessageType("stop")
graphqlwsConnectionAckMsg = graphqlwsMessageType("connection_ack")
graphqlwsConnectionErrorMsg = graphqlwsMessageType("connection_error")
graphqlwsDataMsg = graphqlwsMessageType("data")
graphqlwsErrorMsg = graphqlwsMessageType("error")
graphqlwsCompleteMsg = graphqlwsMessageType("complete")
graphqlwsConnectionKeepAliveMsg = graphqlwsMessageType("ka")
)
var allGraphqlwsMessageTypes = []graphqlwsMessageType{
graphqlwsConnectionInitMsg,
graphqlwsConnectionTerminateMsg,
graphqlwsStartMsg,
graphqlwsStopMsg,
graphqlwsConnectionAckMsg,
graphqlwsConnectionErrorMsg,
graphqlwsDataMsg,
graphqlwsErrorMsg,
graphqlwsCompleteMsg,
graphqlwsConnectionKeepAliveMsg,
}
type (
graphqlwsMessageExchanger struct {
c *websocket.Conn
}
graphqlwsMessage struct {
Payload json.RawMessage `json:"payload,omitempty"`
ID string `json:"id,omitempty"`
Type graphqlwsMessageType `json:"type"`
noOp bool
}
graphqlwsMessageType string
)
func (me graphqlwsMessageExchanger) NextMessage() (message, error) {
_, r, err := me.c.NextReader()
if err != nil {
return message{}, handleNextReaderError(err)
}
var graphqlwsMessage graphqlwsMessage
if err := jsonDecode(r, &graphqlwsMessage); err != nil {
return message{}, errInvalidMsg
}
return graphqlwsMessage.toMessage()
}
func (me graphqlwsMessageExchanger) Send(m *message) error {
msg := &graphqlwsMessage{}
if err := msg.fromMessage(m); err != nil {
return err
}
if msg.noOp {
return nil
}
return me.c.WriteJSON(msg)
}
func (t *graphqlwsMessageType) UnmarshalText(text []byte) (err error) {
var found bool
for _, candidate := range allGraphqlwsMessageTypes {
if string(candidate) == string(text) {
*t = candidate
found = true
break
}
}
if !found {
err = fmt.Errorf("invalid message type %s", string(text))
}
return err
}
func (t graphqlwsMessageType) MarshalText() ([]byte, error) {
return []byte(string(t)), nil
}
func (m graphqlwsMessage) toMessage() (message, error) {
var t messageType
var err error
switch m.Type {
default:
err = fmt.Errorf("invalid client->server message type %s", m.Type)
case graphqlwsConnectionInitMsg:
t = initMessageType
case graphqlwsConnectionTerminateMsg:
t = connectionCloseMessageType
case graphqlwsStartMsg:
t = startMessageType
case graphqlwsStopMsg:
t = stopMessageType
case graphqlwsConnectionAckMsg:
t = connectionAckMessageType
case graphqlwsConnectionErrorMsg:
t = connectionErrorMessageType
case graphqlwsDataMsg:
t = dataMessageType
case graphqlwsErrorMsg:
t = errorMessageType
case graphqlwsCompleteMsg:
t = completeMessageType
case graphqlwsConnectionKeepAliveMsg:
t = keepAliveMessageType
}
return message{
payload: m.Payload,
id: m.ID,
t: t,
}, err
}
func (m *graphqlwsMessage) fromMessage(msg *message) (err error) {
m.ID = msg.id
m.Payload = msg.payload
switch msg.t {
default:
err = fmt.Errorf("invalid server->client message type %s", msg.t)
case initMessageType:
m.Type = graphqlwsConnectionInitMsg
case connectionAckMessageType:
m.Type = graphqlwsConnectionAckMsg
case keepAliveMessageType:
m.Type = graphqlwsConnectionKeepAliveMsg
case connectionErrorMessageType:
m.Type = graphqlwsConnectionErrorMsg
case connectionCloseMessageType:
m.Type = graphqlwsConnectionTerminateMsg
case startMessageType:
m.Type = graphqlwsStartMsg
case stopMessageType:
m.Type = graphqlwsStopMsg
case dataMessageType:
m.Type = graphqlwsDataMsg
case completeMessageType:
m.Type = graphqlwsCompleteMsg
case errorMessageType:
m.Type = graphqlwsErrorMsg
case pingMessageType:
m.noOp = true
case pongMessageType:
m.noOp = true
}
return err
}

View File

@@ -0,0 +1,116 @@
package transport
import (
"encoding/json"
"errors"
"github.com/gorilla/websocket"
)
const (
initMessageType messageType = iota
connectionAckMessageType
keepAliveMessageType
connectionErrorMessageType
connectionCloseMessageType
startMessageType
stopMessageType
dataMessageType
completeMessageType
errorMessageType
pingMessageType
pongMessageType
)
var (
supportedSubprotocols = []string{
graphqlwsSubprotocol,
graphqltransportwsSubprotocol,
}
errWsConnClosed = errors.New("websocket connection closed")
errInvalidMsg = errors.New("invalid message received")
)
type (
messageType int
message struct {
payload json.RawMessage
id string
t messageType
}
messageExchanger interface {
NextMessage() (message, error)
Send(m *message) error
}
)
func (t messageType) String() string {
var text string
switch t {
default:
text = "unknown"
case initMessageType:
text = "init"
case connectionAckMessageType:
text = "connection ack"
case keepAliveMessageType:
text = "keep alive"
case connectionErrorMessageType:
text = "connection error"
case connectionCloseMessageType:
text = "connection close"
case startMessageType:
text = "start"
case stopMessageType:
text = "stop subscription"
case dataMessageType:
text = "data"
case completeMessageType:
text = "complete"
case errorMessageType:
text = "error"
case pingMessageType:
text = "ping"
case pongMessageType:
text = "pong"
}
return text
}
func contains(list []string, elem string) bool {
for _, e := range list {
if e == elem {
return true
}
}
return false
}
func (t *Websocket) injectGraphQLWSSubprotocols() {
// the list of subprotocols is specified by the consumer of the Websocket struct,
// in order to preserve backward compatibility, we inject the graphql specific subprotocols
// at runtime
if !t.didInjectSubprotocols {
defer func() {
t.didInjectSubprotocols = true
}()
for _, subprotocol := range supportedSubprotocols {
if !contains(t.Upgrader.Subprotocols, subprotocol) {
t.Upgrader.Subprotocols = append(t.Upgrader.Subprotocols, subprotocol)
}
}
}
}
func handleNextReaderError(err error) error {
// TODO: should we consider all closure scenarios here for the ws connection?
// for now we only list the error codes from the previous implementation
if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) {
return errWsConnClosed
}
return err
}

View File

@@ -8,10 +8,9 @@ import (
) )
func MarshalID(s string) Marshaler { func MarshalID(s string) Marshaler {
return WriterFunc(func(w io.Writer) { return MarshalString(s)
io.WriteString(w, strconv.Quote(s))
})
} }
func UnmarshalID(v interface{}) (string, error) { func UnmarshalID(v interface{}) (string, error) {
switch v := v.(type) { switch v := v.(type) {
case string: case string:

View File

@@ -6,20 +6,21 @@ import "github.com/vektah/gqlparser/v2/ast"
type ( type (
Directive struct { Directive struct {
Name string Name string
Description string description string
Locations []string Locations []string
Args []InputValue Args []InputValue
IsRepeatable bool
} }
EnumValue struct { EnumValue struct {
Name string Name string
Description string description string
deprecation *ast.Directive deprecation *ast.Directive
} }
Field struct { Field struct {
Name string Name string
Description string description string
Type *Type Type *Type
Args []InputValue Args []InputValue
deprecation *ast.Directive deprecation *ast.Directive
@@ -27,7 +28,7 @@ type (
InputValue struct { InputValue struct {
Name string Name string
Description string description string
DefaultValue *string DefaultValue *string
Type *Type Type *Type
} }
@@ -37,6 +38,13 @@ func WrapSchema(schema *ast.Schema) *Schema {
return &Schema{schema: schema} return &Schema{schema: schema}
} }
func (f *EnumValue) Description() *string {
if f.description == "" {
return nil
}
return &f.description
}
func (f *EnumValue) IsDeprecated() bool { func (f *EnumValue) IsDeprecated() bool {
return f.deprecation != nil return f.deprecation != nil
} }
@@ -54,6 +62,13 @@ func (f *EnumValue) DeprecationReason() *string {
return &reason.Value.Raw return &reason.Value.Raw
} }
func (f *Field) Description() *string {
if f.description == "" {
return nil
}
return &f.description
}
func (f *Field) IsDeprecated() bool { func (f *Field) IsDeprecated() bool {
return f.deprecation != nil return f.deprecation != nil
} }
@@ -70,3 +85,17 @@ func (f *Field) DeprecationReason() *string {
return &reason.Value.Raw 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
}

View File

@@ -4,6 +4,7 @@ package introspection
const Query = ` const Query = `
query IntrospectionQuery { query IntrospectionQuery {
__schema { __schema {
description
queryType { queryType {
name name
} }
@@ -31,6 +32,7 @@ fragment FullType on __Type {
kind kind
name name
description description
specifiedByURL
fields(includeDeprecated: true) { fields(includeDeprecated: true) {
name name
description description

View File

@@ -1,6 +1,7 @@
package introspection package introspection
import ( import (
"sort"
"strings" "strings"
"github.com/vektah/gqlparser/v2/ast" "github.com/vektah/gqlparser/v2/ast"
@@ -10,13 +11,28 @@ type Schema struct {
schema *ast.Schema schema *ast.Schema
} }
func (s *Schema) Description() *string {
if s.schema.Description == "" {
return nil
}
return &s.schema.Description
}
func (s *Schema) Types() []Type { func (s *Schema) Types() []Type {
types := make([]Type, 0, len(s.schema.Types)) typeIndex := map[string]Type{}
typeNames := make([]string, 0, len(s.schema.Types))
for _, typ := range s.schema.Types { for _, typ := range s.schema.Types {
if strings.HasPrefix(typ.Name, "__") { if strings.HasPrefix(typ.Name, "__") {
continue continue
} }
types = append(types, *WrapTypeFromDef(s.schema, typ)) typeNames = append(typeNames, typ.Name)
typeIndex[typ.Name] = *WrapTypeFromDef(s.schema, typ)
}
sort.Strings(typeNames)
types := make([]Type, len(typeNames))
for i, t := range typeNames {
types[i] = typeIndex[t]
} }
return types return types
} }
@@ -34,10 +50,18 @@ func (s *Schema) SubscriptionType() *Type {
} }
func (s *Schema) Directives() []Directive { func (s *Schema) Directives() []Directive {
res := make([]Directive, 0, len(s.schema.Directives)) dIndex := map[string]Directive{}
dNames := make([]string, 0, len(s.schema.Directives))
for _, d := range s.schema.Directives { for _, d := range s.schema.Directives {
res = append(res, s.directiveFromDef(d)) dNames = append(dNames, d.Name)
dIndex[d.Name] = s.directiveFromDef(d)
}
sort.Strings(dNames)
res := make([]Directive, len(dNames))
for i, d := range dNames {
res[i] = dIndex[d]
} }
return res return res
@@ -53,7 +77,7 @@ func (s *Schema) directiveFromDef(d *ast.DirectiveDefinition) Directive {
for i, arg := range d.Arguments { for i, arg := range d.Arguments {
args[i] = InputValue{ args[i] = InputValue{
Name: arg.Name, Name: arg.Name,
Description: arg.Description, description: arg.Description,
DefaultValue: defaultValue(arg.DefaultValue), DefaultValue: defaultValue(arg.DefaultValue),
Type: WrapTypeFromType(s.schema, arg.Type), Type: WrapTypeFromType(s.schema, arg.Type),
} }
@@ -61,8 +85,9 @@ func (s *Schema) directiveFromDef(d *ast.DirectiveDefinition) Directive {
return Directive{ return Directive{
Name: d.Name, Name: d.Name,
Description: d.Description, description: d.Description,
Locations: locs, Locations: locs,
Args: args, Args: args,
IsRepeatable: d.IsRepeatable,
} }
} }

View File

@@ -53,11 +53,11 @@ func (t *Type) Name() *string {
return &t.def.Name return &t.def.Name
} }
func (t *Type) Description() string { func (t *Type) Description() *string {
if t.def == nil { if t.def == nil || t.def.Description == "" {
return "" return nil
} }
return t.def.Description return &t.def.Description
} }
func (t *Type) Fields(includeDeprecated bool) []Field { func (t *Type) Fields(includeDeprecated bool) []Field {
@@ -79,14 +79,14 @@ func (t *Type) Fields(includeDeprecated bool) []Field {
args = append(args, InputValue{ args = append(args, InputValue{
Type: WrapTypeFromType(t.schema, arg.Type), Type: WrapTypeFromType(t.schema, arg.Type),
Name: arg.Name, Name: arg.Name,
Description: arg.Description, description: arg.Description,
DefaultValue: defaultValue(arg.DefaultValue), DefaultValue: defaultValue(arg.DefaultValue),
}) })
} }
fields = append(fields, Field{ fields = append(fields, Field{
Name: f.Name, Name: f.Name,
Description: f.Description, description: f.Description,
Args: args, Args: args,
Type: WrapTypeFromType(t.schema, f.Type), Type: WrapTypeFromType(t.schema, f.Type),
deprecation: f.Directives.ForName("deprecated"), deprecation: f.Directives.ForName("deprecated"),
@@ -104,7 +104,7 @@ func (t *Type) InputFields() []InputValue {
for _, f := range t.def.Fields { for _, f := range t.def.Fields {
res = append(res, InputValue{ res = append(res, InputValue{
Name: f.Name, Name: f.Name,
Description: f.Description, description: f.Description,
Type: WrapTypeFromType(t.schema, f.Type), Type: WrapTypeFromType(t.schema, f.Type),
DefaultValue: defaultValue(f.DefaultValue), DefaultValue: defaultValue(f.DefaultValue),
}) })
@@ -158,7 +158,7 @@ func (t *Type) EnumValues(includeDeprecated bool) []EnumValue {
res = append(res, EnumValue{ res = append(res, EnumValue{
Name: val.Name, Name: val.Name,
Description: val.Description, description: val.Description,
deprecation: val.Directives.ForName("deprecated"), deprecation: val.Directives.ForName("deprecated"),
}) })
} }
@@ -178,3 +178,14 @@ func (t *Type) OfType() *Type {
} }
return WrapTypeFromType(t.schema, t.typ.Elem) 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
}

View File

@@ -1,22 +1,27 @@
package graphql package graphql
import ( import (
"context"
"io" "io"
) )
var nullLit = []byte(`null`) var (
var trueLit = []byte(`true`) nullLit = []byte(`null`)
var falseLit = []byte(`false`) trueLit = []byte(`true`)
var openBrace = []byte(`{`) falseLit = []byte(`false`)
var closeBrace = []byte(`}`) openBrace = []byte(`{`)
var openBracket = []byte(`[`) closeBrace = []byte(`}`)
var closeBracket = []byte(`]`) openBracket = []byte(`[`)
var colon = []byte(`:`) closeBracket = []byte(`]`)
var comma = []byte(`,`) colon = []byte(`:`)
comma = []byte(`,`)
)
var Null = &lit{nullLit} var (
var True = &lit{trueLit} Null = &lit{nullLit}
var False = &lit{falseLit} True = &lit{trueLit}
False = &lit{falseLit}
)
type Marshaler interface { type Marshaler interface {
MarshalGQL(w io.Writer) MarshalGQL(w io.Writer)
@@ -26,12 +31,43 @@ type Unmarshaler interface {
UnmarshalGQL(v interface{}) error 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) type WriterFunc func(writer io.Writer)
func (f WriterFunc) MarshalGQL(w io.Writer) { func (f WriterFunc) MarshalGQL(w io.Writer) {
f(w) 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 type Array []Marshaler
func (a Array) MarshalGQL(writer io.Writer) { func (a Array) MarshalGQL(writer io.Writer) {
@@ -50,3 +86,8 @@ type lit struct{ b []byte }
func (l lit) MarshalGQL(w io.Writer) { func (l lit) MarshalGQL(w io.Writer) {
w.Write(l.b) w.Write(l.b)
} }
func (l lit) MarshalGQLContext(ctx context.Context, w io.Writer) error {
w.Write(l.b)
return nil
}

View File

@@ -8,37 +8,47 @@ import (
var page = template.Must(template.New("graphiql").Parse(`<!DOCTYPE html> var page = template.Must(template.New("graphiql").Parse(`<!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset=utf-8/>
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
<link rel="shortcut icon" href="https://graphcool-playground.netlify.com/favicon.png">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/static/css/index.css"
integrity="{{ .cssSRI }}" crossorigin="anonymous"/>
<link rel="shortcut icon" href="https://cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/favicon.png"
integrity="{{ .faviconSRI }}" crossorigin="anonymous"/>
<script src="https://cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/static/js/middleware.js"
integrity="{{ .jsSRI }}" crossorigin="anonymous"></script>
<title>{{.title}}</title> <title>{{.title}}</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/graphiql@{{.version}}/graphiql.min.css"
integrity="{{.cssSRI}}"
crossorigin="anonymous"
/>
</head> </head>
<body> <body style="margin: 0;">
<style type="text/css"> <div id="graphiql" style="height: 100vh;"></div>
html { font-family: "Open Sans", sans-serif; overflow: hidden; }
body { margin: 0; background: #172a3a; } <script
</style> src="https://cdn.jsdelivr.net/npm/react@17.0.2/umd/react.production.min.js"
<div id="root"/> integrity="{{.reactSRI}}"
<script type="text/javascript"> crossorigin="anonymous"
window.addEventListener('load', function (event) { ></script>
const root = document.getElementById('root'); <script
root.classList.add('playgroundIn'); src="https://cdn.jsdelivr.net/npm/react-dom@17.0.2/umd/react-dom.production.min.js"
const wsProto = location.protocol == 'https:' ? 'wss:' : 'ws:' integrity="{{.reactDOMSRI}}"
GraphQLPlayground.init(root, { crossorigin="anonymous"
endpoint: location.protocol + '//' + location.host + '{{.endpoint}}', ></script>
subscriptionsEndpoint: wsProto + '//' + location.host + '{{.endpoint }}', <script
shareEnabled: true, src="https://cdn.jsdelivr.net/npm/graphiql@{{.version}}/graphiql.min.js"
settings: { integrity="{{.jsSRI}}"
'request.credentials': 'same-origin' 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> </script>
</body> </body>
</html> </html>
@@ -50,10 +60,11 @@ func Handler(title string, endpoint string) http.HandlerFunc {
err := page.Execute(w, map[string]string{ err := page.Execute(w, map[string]string{
"title": title, "title": title,
"endpoint": endpoint, "endpoint": endpoint,
"version": "1.7.20", "version": "1.5.16",
"cssSRI": "sha256-cS9Vc2OBt9eUf4sykRWukeFYaInL29+myBmFDSa7F/U=", "cssSRI": "sha256-HADQowUuFum02+Ckkv5Yu5ygRoLllHZqg0TFZXY7NHI=",
"faviconSRI": "sha256-GhTyE+McTU79R4+pRO6ih+4TfsTOrpPwD8ReKFzb3PM=", "jsSRI": "sha256-uHp12yvpXC4PC9+6JmITxKuLYwjlW9crq9ywPE5Rxco=",
"jsSRI": "sha256-4QG1Uza2GgGdlBL3RCBCGtGeZB6bDbsw8OltCMGeJsA=", "reactSRI": "sha256-Ipu/TQ50iCCVZBUsZyNJfxrDk0E2yhaEIz0vqI+kFG8=",
"reactDOMSRI": "sha256-nbMykgB6tsOFJ7OdVmPpdqMFVk4ZsqWocT6issAPUF0=",
}) })
if err != nil { if err != nil {
panic(err) panic(err)

View File

@@ -2,10 +2,11 @@ package graphql
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"os" "os"
"runtime/debug" "runtime/debug"
"github.com/vektah/gqlparser/v2/gqlerror"
) )
type RecoverFunc func(ctx context.Context, err interface{}) (userMessage error) type RecoverFunc func(ctx context.Context, err interface{}) (userMessage error)
@@ -15,5 +16,5 @@ func DefaultRecover(ctx context.Context, err interface{}) error {
fmt.Fprintln(os.Stderr) fmt.Fprintln(os.Stderr)
debug.PrintStack() debug.PrintStack()
return errors.New("internal system error") return gqlerror.Errorf("internal system error")
} }

View File

@@ -52,6 +52,8 @@ func UnmarshalString(v interface{}) (string, error) {
return v, nil return v, nil
case int: case int:
return strconv.Itoa(v), nil return strconv.Itoa(v), nil
case int64:
return strconv.FormatInt(v, 10), nil
case float64: case float64:
return fmt.Sprintf("%f", v), nil return fmt.Sprintf("%f", v), nil
case bool: case bool:

View File

@@ -13,13 +13,13 @@ func MarshalTime(t time.Time) Marshaler {
} }
return WriterFunc(func(w io.Writer) { return WriterFunc(func(w io.Writer) {
io.WriteString(w, strconv.Quote(t.Format(time.RFC3339))) io.WriteString(w, strconv.Quote(t.Format(time.RFC3339Nano)))
}) })
} }
func UnmarshalTime(v interface{}) (time.Time, error) { func UnmarshalTime(v interface{}) (time.Time, error) {
if tmpStr, ok := v.(string); ok { if tmpStr, ok := v.(string); ok {
return time.Parse(time.RFC3339, tmpStr) return time.Parse(time.RFC3339Nano, tmpStr)
} }
return time.Time{}, errors.New("time should be RFC3339 formatted string") return time.Time{}, errors.New("time should be RFC3339Nano formatted string")
} }

81
vendor/github.com/99designs/gqlgen/graphql/uint.go generated vendored Normal file
View File

@@ -0,0 +1,81 @@
package graphql
import (
"encoding/json"
"fmt"
"io"
"strconv"
)
func MarshalUint(i uint) Marshaler {
return WriterFunc(func(w io.Writer) {
_, _ = io.WriteString(w, strconv.FormatUint(uint64(i), 10))
})
}
func UnmarshalUint(v interface{}) (uint, error) {
switch v := v.(type) {
case string:
u64, err := strconv.ParseUint(v, 10, 64)
return uint(u64), err
case int:
return uint(v), nil
case int64:
return uint(v), nil
case json.Number:
u64, err := strconv.ParseUint(string(v), 10, 64)
return uint(u64), err
default:
return 0, fmt.Errorf("%T is not an uint", v)
}
}
func MarshalUint64(i uint64) Marshaler {
return WriterFunc(func(w io.Writer) {
_, _ = io.WriteString(w, strconv.FormatUint(i, 10))
})
}
func UnmarshalUint64(v interface{}) (uint64, error) {
switch v := v.(type) {
case string:
return strconv.ParseUint(v, 10, 64)
case int:
return uint64(v), nil
case int64:
return uint64(v), nil
case json.Number:
return strconv.ParseUint(string(v), 10, 64)
default:
return 0, fmt.Errorf("%T is not an uint", v)
}
}
func MarshalUint32(i uint32) Marshaler {
return WriterFunc(func(w io.Writer) {
_, _ = io.WriteString(w, strconv.FormatUint(uint64(i), 10))
})
}
func UnmarshalUint32(v interface{}) (uint32, error) {
switch v := v.(type) {
case string:
iv, err := strconv.ParseInt(v, 10, 32)
if err != nil {
return 0, err
}
return uint32(iv), nil
case int:
return uint32(v), nil
case int64:
return uint32(v), nil
case json.Number:
iv, err := strconv.ParseUint(string(v), 10, 32)
if err != nil {
return 0, err
}
return uint32(iv), nil
default:
return 0, fmt.Errorf("%T is not an uint", v)
}
}

View File

@@ -1,3 +1,3 @@
package graphql package graphql
const Version = "v0.12.2" const Version = "v0.17.2"

View File

@@ -1,247 +0,0 @@
package handler
import (
"context"
"net/http"
"time"
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/handler/extension"
"github.com/99designs/gqlgen/graphql/handler/lru"
"github.com/99designs/gqlgen/graphql/handler/transport"
"github.com/99designs/gqlgen/graphql/playground"
"github.com/gorilla/websocket"
)
// Deprecated: switch to graphql/handler.New
func GraphQL(exec graphql.ExecutableSchema, options ...Option) http.HandlerFunc {
var cfg Config
cfg.cacheSize = 1000
for _, option := range options {
option(&cfg)
}
srv := handler.New(exec)
srv.AddTransport(transport.Websocket{
Upgrader: cfg.upgrader,
InitFunc: cfg.websocketInitFunc,
KeepAlivePingInterval: cfg.connectionKeepAlivePingInterval,
})
srv.AddTransport(transport.Options{})
srv.AddTransport(transport.GET{})
srv.AddTransport(transport.POST{})
srv.AddTransport(transport.MultipartForm{
MaxUploadSize: cfg.uploadMaxSize,
MaxMemory: cfg.uploadMaxMemory,
})
if cfg.cacheSize != 0 {
srv.SetQueryCache(lru.New(cfg.cacheSize))
}
if cfg.recover != nil {
srv.SetRecoverFunc(cfg.recover)
}
if cfg.errorPresenter != nil {
srv.SetErrorPresenter(cfg.errorPresenter)
}
for _, hook := range cfg.fieldHooks {
srv.AroundFields(hook)
}
for _, hook := range cfg.requestHooks {
srv.AroundResponses(hook)
}
if cfg.complexityLimit != 0 {
srv.Use(extension.FixedComplexityLimit(cfg.complexityLimit))
} else if cfg.complexityLimitFunc != nil {
srv.Use(&extension.ComplexityLimit{
Func: func(ctx context.Context, rc *graphql.OperationContext) int {
return cfg.complexityLimitFunc(graphql.WithOperationContext(ctx, rc))
},
})
}
if !cfg.disableIntrospection {
srv.Use(extension.Introspection{})
}
if cfg.apqCache != nil {
srv.Use(extension.AutomaticPersistedQuery{Cache: apqAdapter{cfg.apqCache}})
}
return srv.ServeHTTP
}
// Deprecated: switch to graphql/handler.New
type Config struct {
cacheSize int
upgrader websocket.Upgrader
websocketInitFunc transport.WebsocketInitFunc
connectionKeepAlivePingInterval time.Duration
recover graphql.RecoverFunc
errorPresenter graphql.ErrorPresenterFunc
fieldHooks []graphql.FieldMiddleware
requestHooks []graphql.ResponseMiddleware
complexityLimit int
complexityLimitFunc func(ctx context.Context) int
disableIntrospection bool
uploadMaxMemory int64
uploadMaxSize int64
apqCache PersistedQueryCache
}
// Deprecated: switch to graphql/handler.New
type Option func(cfg *Config)
// Deprecated: switch to graphql/handler.New
func WebsocketUpgrader(upgrader websocket.Upgrader) Option {
return func(cfg *Config) {
cfg.upgrader = upgrader
}
}
// Deprecated: switch to graphql/handler.New
func RecoverFunc(recover graphql.RecoverFunc) Option {
return func(cfg *Config) {
cfg.recover = recover
}
}
// ErrorPresenter transforms errors found while resolving into errors that will be returned to the user. It provides
// a good place to add any extra fields, like error.type, that might be desired by your frontend. Check the default
// implementation in graphql.DefaultErrorPresenter for an example.
// Deprecated: switch to graphql/handler.New
func ErrorPresenter(f graphql.ErrorPresenterFunc) Option {
return func(cfg *Config) {
cfg.errorPresenter = f
}
}
// IntrospectionEnabled = false will forbid clients from calling introspection endpoints. Can be useful in prod when you dont
// want clients introspecting the full schema.
// Deprecated: switch to graphql/handler.New
func IntrospectionEnabled(enabled bool) Option {
return func(cfg *Config) {
cfg.disableIntrospection = !enabled
}
}
// ComplexityLimit sets a maximum query complexity that is allowed to be executed.
// If a query is submitted that exceeds the limit, a 422 status code will be returned.
// Deprecated: switch to graphql/handler.New
func ComplexityLimit(limit int) Option {
return func(cfg *Config) {
cfg.complexityLimit = limit
}
}
// ComplexityLimitFunc allows you to define a function to dynamically set the maximum query complexity that is allowed
// to be executed.
// If a query is submitted that exceeds the limit, a 422 status code will be returned.
// Deprecated: switch to graphql/handler.New
func ComplexityLimitFunc(complexityLimitFunc func(ctx context.Context) int) Option {
return func(cfg *Config) {
cfg.complexityLimitFunc = complexityLimitFunc
}
}
// ResolverMiddleware allows you to define a function that will be called around every resolver,
// useful for logging.
// Deprecated: switch to graphql/handler.New
func ResolverMiddleware(middleware graphql.FieldMiddleware) Option {
return func(cfg *Config) {
cfg.fieldHooks = append(cfg.fieldHooks, middleware)
}
}
// RequestMiddleware allows you to define a function that will be called around the root request,
// after the query has been parsed. This is useful for logging
// Deprecated: switch to graphql/handler.New
func RequestMiddleware(middleware graphql.ResponseMiddleware) Option {
return func(cfg *Config) {
cfg.requestHooks = append(cfg.requestHooks, middleware)
}
}
// WebsocketInitFunc is called when the server receives connection init message from the client.
// This can be used to check initial payload to see whether to accept the websocket connection.
// Deprecated: switch to graphql/handler.New
func WebsocketInitFunc(websocketInitFunc transport.WebsocketInitFunc) Option {
return func(cfg *Config) {
cfg.websocketInitFunc = websocketInitFunc
}
}
// CacheSize sets the maximum size of the query cache.
// If size is less than or equal to 0, the cache is disabled.
// Deprecated: switch to graphql/handler.New
func CacheSize(size int) Option {
return func(cfg *Config) {
cfg.cacheSize = size
}
}
// UploadMaxSize sets the maximum number of bytes used to parse a request body
// as multipart/form-data.
// Deprecated: switch to graphql/handler.New
func UploadMaxSize(size int64) Option {
return func(cfg *Config) {
cfg.uploadMaxSize = size
}
}
// UploadMaxMemory sets the maximum number of bytes used to parse a request body
// as multipart/form-data in memory, with the remainder stored on disk in
// temporary files.
// Deprecated: switch to graphql/handler.New
func UploadMaxMemory(size int64) Option {
return func(cfg *Config) {
cfg.uploadMaxMemory = size
}
}
// WebsocketKeepAliveDuration allows you to reconfigure the keepalive behavior.
// By default, keepalive is enabled with a DefaultConnectionKeepAlivePingInterval
// duration. Set handler.connectionKeepAlivePingInterval = 0 to disable keepalive
// altogether.
// Deprecated: switch to graphql/handler.New
func WebsocketKeepAliveDuration(duration time.Duration) Option {
return func(cfg *Config) {
cfg.connectionKeepAlivePingInterval = duration
}
}
// Add cache that will hold queries for automatic persisted queries (APQ)
// Deprecated: switch to graphql/handler.New
func EnablePersistedQueryCache(cache PersistedQueryCache) Option {
return func(cfg *Config) {
cfg.apqCache = cache
}
}
func GetInitPayload(ctx context.Context) transport.InitPayload {
return transport.GetInitPayload(ctx)
}
type apqAdapter struct {
PersistedQueryCache
}
func (a apqAdapter) Get(ctx context.Context, key string) (value interface{}, ok bool) {
return a.PersistedQueryCache.Get(ctx, key)
}
func (a apqAdapter) Add(ctx context.Context, key string, value interface{}) {
a.PersistedQueryCache.Add(ctx, key, value.(string))
}
type PersistedQueryCache interface {
Add(ctx context.Context, hash string, query string)
Get(ctx context.Context, hash string) (string, bool)
}
// Deprecated: use playground.Handler instead
func Playground(title string, endpoint string) http.HandlerFunc {
return playground.Handler(title, endpoint)
}
// Deprecated: use transport.InitPayload instead
type InitPayload = transport.InitPayload

View File

@@ -0,0 +1,56 @@
# Where are all the schema files located? globs are supported eg src/**/*.graphqls
schema:
- graph/*.graphqls
# Where should the generated server code go?
exec:
filename: graph/generated/generated.go
package: generated
# Uncomment to enable federation
# federation:
# filename: graph/generated/federation.go
# package: generated
# Where should any generated models go?
model:
filename: graph/model/models_gen.go
package: model
# Where should the resolver implementations go?
resolver:
layout: follow-schema
dir: graph
package: graph
# Optional: turn on use ` + "`" + `gqlgen:"fieldName"` + "`" + ` tags in your models
# struct_tag: json
# Optional: turn on to use []Thing instead of []*Thing
# omit_slice_element_pointers: false
# Optional: set to speed up generation time by not performing a final validation pass.
# skip_validation: true
# gqlgen will search for any type names in the schema in these go packages
# if they match it will use them, otherwise it will generate them.
autobind:
# - "{{.}}/graph/model"
# This section declares type mapping between the GraphQL and go type systems
#
# The first line in each type will be used as defaults for resolver arguments and
# modelgen, the others will be allowed when binding to fields. Configure them to
# your liking
models:
ID:
model:
- github.com/99designs/gqlgen/graphql.ID
- github.com/99designs/gqlgen/graphql.Int
- github.com/99designs/gqlgen/graphql.Int64
- github.com/99designs/gqlgen/graphql.Int32
Int:
model:
- github.com/99designs/gqlgen/graphql.Int
- github.com/99designs/gqlgen/graphql.Int64
- github.com/99designs/gqlgen/graphql.Int32

View File

@@ -0,0 +1,28 @@
# GraphQL schema example
#
# https://gqlgen.com/getting-started/
type Todo {
id: ID!
text: String!
done: Boolean!
user: User!
}
type User {
id: ID!
name: String!
}
type Query {
todos: [Todo!]!
}
input NewTodo {
text: String!
userId: String!
}
type Mutation {
createTodo(input: NewTodo!): Todo!
}

View File

@@ -7,8 +7,6 @@ import (
// CompatibleTypes isnt a strict comparison, it allows for pointer differences // CompatibleTypes isnt a strict comparison, it allows for pointer differences
func CompatibleTypes(expected types.Type, actual types.Type) error { func CompatibleTypes(expected types.Type, actual types.Type) error {
//fmt.Println("Comparing ", expected.String(), actual.String())
// Special case to deal with pointer mismatches // Special case to deal with pointer mismatches
{ {
expectedPtr, expectedIsPtr := expected.(*types.Pointer) expectedPtr, expectedIsPtr := expected.(*types.Pointer)

View File

@@ -45,6 +45,14 @@ func NameForDir(dir string) string {
return SanitizePackageName(filepath.Base(dir)) return SanitizePackageName(filepath.Base(dir))
} }
type goModuleSearchResult struct {
path string
goModPath string
moduleName string
}
var goModuleRootCache = map[string]goModuleSearchResult{}
// goModuleRoot returns the root of the current go module if there is a go.mod file in the directory tree // goModuleRoot returns the root of the current go module if there is a go.mod file in the directory tree
// If not, it returns false // If not, it returns false
func goModuleRoot(dir string) (string, bool) { func goModuleRoot(dir string) (string, bool) {
@@ -53,34 +61,74 @@ func goModuleRoot(dir string) (string, bool) {
panic(err) panic(err)
} }
dir = filepath.ToSlash(dir) dir = filepath.ToSlash(dir)
modDir := dir
assumedPart := "" dirs := []string{dir}
result := goModuleSearchResult{}
for { for {
f, err := ioutil.ReadFile(filepath.Join(modDir, "go.mod")) modDir := dirs[len(dirs)-1]
if err == nil {
// found it, stop searching
return string(modregex.FindSubmatch(f)[1]) + assumedPart, true
}
assumedPart = "/" + filepath.Base(modDir) + assumedPart if val, ok := goModuleRootCache[dir]; ok {
parentDir, err := filepath.Abs(filepath.Join(modDir, "..")) result = val
if err != nil {
panic(err)
}
if parentDir == modDir {
// Walked all the way to the root and didnt find anything :'(
break break
} }
modDir = parentDir
if content, err := ioutil.ReadFile(filepath.Join(modDir, "go.mod")); err == nil {
moduleName := string(modregex.FindSubmatch(content)[1])
result = goModuleSearchResult{
path: moduleName,
goModPath: modDir,
moduleName: moduleName,
} }
goModuleRootCache[modDir] = result
break
}
if modDir == "" || modDir == "." || modDir == "/" || strings.HasSuffix(modDir, "\\") {
// Reached the top of the file tree which means go.mod file is not found
// Set root folder with a sentinel cache value
goModuleRootCache[modDir] = result
break
}
dirs = append(dirs, filepath.Dir(modDir))
}
// create a cache for each path in a tree traversed, except the top one as it is already cached
for _, d := range dirs[:len(dirs)-1] {
if result.moduleName == "" {
// go.mod is not found in the tree, so the same sentinel value fits all the directories in a tree
goModuleRootCache[d] = result
} else {
if relPath, err := filepath.Rel(result.goModPath, d); err != nil {
panic(err)
} else {
path := result.moduleName
relPath := filepath.ToSlash(relPath)
if !strings.HasSuffix(relPath, "/") {
path += "/"
}
path += relPath
goModuleRootCache[d] = goModuleSearchResult{
path: path,
goModPath: result.goModPath,
moduleName: result.moduleName,
}
}
}
}
res := goModuleRootCache[dir]
if res.moduleName == "" {
return "", false return "", false
} }
return res.path, true
}
// ImportPathForDir takes a path and returns a golang import path for the package // ImportPathForDir takes a path and returns a golang import path for the package
func ImportPathForDir(dir string) (res string) { func ImportPathForDir(dir string) (res string) {
dir, err := filepath.Abs(dir) dir, err := filepath.Abs(dir)
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@@ -2,9 +2,12 @@ package code
import ( import (
"bytes" "bytes"
"errors"
"fmt"
"os"
"os/exec"
"path/filepath" "path/filepath"
"github.com/pkg/errors"
"golang.org/x/tools/go/packages" "golang.org/x/tools/go/packages"
) )
@@ -13,7 +16,9 @@ var mode = packages.NeedName |
packages.NeedImports | packages.NeedImports |
packages.NeedTypes | packages.NeedTypes |
packages.NeedSyntax | packages.NeedSyntax |
packages.NeedTypesInfo packages.NeedTypesInfo |
packages.NeedModule |
packages.NeedDeps
// Packages is a wrapper around x/tools/go/packages that maintains a (hopefully prewarmed) cache of packages // Packages is a wrapper around x/tools/go/packages that maintains a (hopefully prewarmed) cache of packages
// that can be invalidated as writes are made and packages are known to change. // that can be invalidated as writes are made and packages are known to change.
@@ -26,6 +31,22 @@ type Packages struct {
numNameCalls int // stupid test steam. ignore. numNameCalls int // stupid test steam. ignore.
} }
// ReloadAll will call LoadAll after clearing the package cache, so we can reload
// packages in the case that the packages have changed
func (p *Packages) ReloadAll(importPaths ...string) []*packages.Package {
p.packages = nil
return p.LoadAll(importPaths...)
}
func (p *Packages) checkModuleLoaded(pkgs []*packages.Package) bool {
for i := range pkgs {
if pkgs[i] == nil || pkgs[i].Module == nil {
return false
}
}
return true
}
// LoadAll will call packages.Load and return the package data for the given packages, // LoadAll will call packages.Load and return the package data for the given packages,
// but if the package already have been loaded it will return cached values instead. // but if the package already have been loaded it will return cached values instead.
func (p *Packages) LoadAll(importPaths ...string) []*packages.Package { func (p *Packages) LoadAll(importPaths ...string) []*packages.Package {
@@ -44,6 +65,13 @@ func (p *Packages) LoadAll(importPaths ...string) []*packages.Package {
if len(missing) > 0 { if len(missing) > 0 {
p.numLoadCalls++ p.numLoadCalls++
pkgs, err := packages.Load(&packages.Config{Mode: mode}, missing...) pkgs, err := packages.Load(&packages.Config{Mode: mode}, missing...)
// Sometimes packages.Load not loaded the module info. Call it again to reload it.
if !p.checkModuleLoaded(pkgs) {
fmt.Println("reloading module info")
pkgs, err = packages.Load(&packages.Config{Mode: mode}, missing...)
}
if err != nil { if err != nil {
p.loadErrors = append(p.loadErrors, err) p.loadErrors = append(p.loadErrors, err)
} }
@@ -72,6 +100,13 @@ func (p *Packages) addToCache(pkg *packages.Package) {
// Load works the same as LoadAll, except a single package at a time. // Load works the same as LoadAll, except a single package at a time.
func (p *Packages) Load(importPath string) *packages.Package { func (p *Packages) Load(importPath string) *packages.Package {
// Quick cache check first to avoid expensive allocations of LoadAll()
if p.packages != nil {
if pkg, ok := p.packages[importPath]; ok {
return pkg
}
}
pkgs := p.LoadAll(importPath) pkgs := p.LoadAll(importPath)
if len(pkgs) == 0 { if len(pkgs) == 0 {
return nil return nil
@@ -149,6 +184,17 @@ func (p *Packages) Evict(importPath string) {
} }
} }
func (p *Packages) ModTidy() error {
p.packages = nil
tidyCmd := exec.Command("go", "mod", "tidy")
tidyCmd.Stdout = os.Stdout
tidyCmd.Stderr = os.Stdout
if err := tidyCmd.Run(); err != nil {
return fmt.Errorf("go mod tidy failed: %w", err)
}
return nil
}
// Errors returns any errors that were returned by Load, either from the call itself or any of the loaded packages. // Errors returns any errors that were returned by Load, either from the call itself or any of the loaded packages.
func (p *Packages) Errors() PkgErrors { func (p *Packages) Errors() PkgErrors {
var res []error //nolint:prealloc var res []error //nolint:prealloc
@@ -161,6 +207,10 @@ func (p *Packages) Errors() PkgErrors {
return res return res
} }
func (p *Packages) Count() int {
return len(p.packages)
}
type PkgErrors []error type PkgErrors []error
func (p PkgErrors) Error() string { func (p PkgErrors) Error() string {

View File

@@ -58,7 +58,7 @@ func (r *Rewriter) getFile(filename string) string {
if _, ok := r.files[filename]; !ok { if _, ok := r.files[filename]; !ok {
b, err := ioutil.ReadFile(filename) b, err := ioutil.ReadFile(filename)
if err != nil { if err != nil {
panic(fmt.Errorf("unable to load file, already exists: %s", err.Error())) panic(fmt.Errorf("unable to load file, already exists: %w", err))
} }
r.files[filename] = string(b) r.files[filename] = string(b)

View File

@@ -1,9 +1,190 @@
package main package main
import ( import (
"github.com/99designs/gqlgen/cmd" "bytes"
_ "embed"
"errors"
"fmt"
"html/template"
"io/fs"
"io/ioutil"
"log"
"os"
"path/filepath"
"github.com/99designs/gqlgen/api"
"github.com/99designs/gqlgen/codegen/config"
"github.com/99designs/gqlgen/graphql"
"github.com/99designs/gqlgen/internal/code"
"github.com/99designs/gqlgen/plugin/servergen"
"github.com/urfave/cli/v2"
) )
func main() { //go:embed init-templates/schema.graphqls
cmd.Execute() var schemaFileContent string
//go:embed init-templates/gqlgen.yml.gotmpl
var configFileTemplate string
func getConfigFileContent(pkgName string) string {
var buf bytes.Buffer
if err := template.Must(template.New("gqlgen.yml").Parse(configFileTemplate)).Execute(&buf, pkgName); err != nil {
panic(err)
}
return buf.String()
}
func fileExists(filename string) bool {
_, err := os.Stat(filename)
return !errors.Is(err, fs.ErrNotExist)
}
func initFile(filename, contents string) error {
if err := os.MkdirAll(filepath.Dir(filename), 0o755); err != nil {
return fmt.Errorf("unable to create directory for file '%s': %w\n", filename, err)
}
if err := ioutil.WriteFile(filename, []byte(contents), 0o644); err != nil {
return fmt.Errorf("unable to write file '%s': %w\n", filename, err)
}
return nil
}
var initCmd = &cli.Command{
Name: "init",
Usage: "create a new gqlgen project",
Flags: []cli.Flag{
&cli.BoolFlag{Name: "verbose, v", Usage: "show logs"},
&cli.StringFlag{Name: "config, c", Usage: "the config filename", Value: "gqlgen.yml"},
&cli.StringFlag{Name: "server", Usage: "where to write the server stub to", Value: "server.go"},
&cli.StringFlag{Name: "schema", Usage: "where to write the schema stub to", Value: "graph/schema.graphqls"},
},
Action: func(ctx *cli.Context) error {
configFilename := ctx.String("config")
serverFilename := ctx.String("server")
schemaFilename := ctx.String("schema")
pkgName := code.ImportPathForDir(".")
if pkgName == "" {
return fmt.Errorf("unable to determine import path for current directory, you probably need to run 'go mod init' first")
}
// check schema and config don't already exist
for _, filename := range []string{configFilename, schemaFilename, serverFilename} {
if fileExists(filename) {
return fmt.Errorf("%s already exists", filename)
}
}
_, err := config.LoadConfigFromDefaultLocations()
if err == nil {
return fmt.Errorf("gqlgen.yml already exists in a parent directory\n")
}
// create config
fmt.Println("Creating", configFilename)
if err := initFile(configFilename, getConfigFileContent(pkgName)); err != nil {
return err
}
// create schema
fmt.Println("Creating", schemaFilename)
if err := initFile(schemaFilename, schemaFileContent); err != nil {
return err
}
// create the package directory with a temporary file so that go recognises it as a package
// and autobinding doesn't error out
tmpPackageNameFile := "graph/model/_tmp_gqlgen_init.go"
if err := initFile(tmpPackageNameFile, "package model"); err != nil {
return err
}
defer os.Remove(tmpPackageNameFile)
var cfg *config.Config
if cfg, err = config.LoadConfig(configFilename); err != nil {
panic(err)
}
fmt.Println("Creating", serverFilename)
fmt.Println("Generating...")
if err := api.Generate(cfg, api.AddPlugin(servergen.New(serverFilename))); err != nil {
return err
}
fmt.Printf("\nExec \"go run ./%s\" to start GraphQL server\n", serverFilename)
return nil
},
}
var generateCmd = &cli.Command{
Name: "generate",
Usage: "generate a graphql server based on schema",
Flags: []cli.Flag{
&cli.BoolFlag{Name: "verbose, v", Usage: "show logs"},
&cli.StringFlag{Name: "config, c", Usage: "the config filename"},
},
Action: func(ctx *cli.Context) error {
var cfg *config.Config
var err error
if configFilename := ctx.String("config"); configFilename != "" {
cfg, err = config.LoadConfig(configFilename)
if err != nil {
return err
}
} else {
cfg, err = config.LoadConfigFromDefaultLocations()
if errors.Is(err, fs.ErrNotExist) {
cfg, err = config.LoadDefaultConfig()
}
if err != nil {
return err
}
}
if err = api.Generate(cfg); err != nil {
return err
}
return nil
},
}
var versionCmd = &cli.Command{
Name: "version",
Usage: "print the version string",
Action: func(ctx *cli.Context) error {
fmt.Println(graphql.Version)
return nil
},
}
func main() {
app := cli.NewApp()
app.Name = "gqlgen"
app.Usage = generateCmd.Usage
app.Description = "This is a library for quickly creating strictly typed graphql servers in golang. See https://gqlgen.com/ for a getting started guide."
app.HideVersion = true
app.Flags = generateCmd.Flags
app.Version = graphql.Version
app.Before = func(context *cli.Context) error {
if context.Bool("verbose") {
log.SetFlags(0)
} else {
log.SetOutput(ioutil.Discard)
}
return nil
}
app.Action = generateCmd.Action
app.Commands = []*cli.Command{
generateCmd,
initCmd,
versionCmd,
}
if err := app.Run(os.Args); err != nil {
fmt.Fprint(os.Stderr, err.Error()+"\n")
os.Exit(1)
}
} }

View File

@@ -11,6 +11,7 @@ import (
"github.com/99designs/gqlgen/codegen/config" "github.com/99designs/gqlgen/codegen/config"
"github.com/99designs/gqlgen/codegen/templates" "github.com/99designs/gqlgen/codegen/templates"
"github.com/99designs/gqlgen/plugin" "github.com/99designs/gqlgen/plugin"
"github.com/99designs/gqlgen/plugin/federation/fieldset"
) )
type federation struct { type federation struct {
@@ -75,8 +76,8 @@ scalar _FieldSet
directive @external on FIELD_DEFINITION directive @external on FIELD_DEFINITION
directive @requires(fields: _FieldSet!) on FIELD_DEFINITION directive @requires(fields: _FieldSet!) on FIELD_DEFINITION
directive @provides(fields: _FieldSet!) on FIELD_DEFINITION directive @provides(fields: _FieldSet!) on FIELD_DEFINITION
directive @key(fields: _FieldSet!) on OBJECT | INTERFACE directive @key(fields: _FieldSet!) repeatable on OBJECT | INTERFACE
directive @extends on OBJECT directive @extends on OBJECT | INTERFACE
`, `,
BuiltIn: true, BuiltIn: true,
} }
@@ -87,57 +88,79 @@ directive @extends on OBJECT
func (f *federation) InjectSourceLate(schema *ast.Schema) *ast.Source { func (f *federation) InjectSourceLate(schema *ast.Schema) *ast.Source {
f.setEntities(schema) f.setEntities(schema)
entities := "" var entities, resolvers, entityResolverInputDefinitions string
resolvers := ""
for i, e := range f.Entities { for i, e := range f.Entities {
if i != 0 { if i != 0 {
entities += " | " entities += " | "
} }
entities += e.Name entities += e.Name
if e.ResolverName != "" { for _, r := range e.Resolvers {
if e.Multi {
if entityResolverInputDefinitions != "" {
entityResolverInputDefinitions += "\n\n"
}
entityResolverInputDefinitions += "input " + r.InputType + " {\n"
for _, keyField := range r.KeyFields {
entityResolverInputDefinitions += fmt.Sprintf("\t%s: %s\n", keyField.Field.ToGo(), keyField.Definition.Type.String())
}
entityResolverInputDefinitions += "}"
resolvers += fmt.Sprintf("\t%s(reps: [%s!]!): [%s]\n", r.ResolverName, r.InputType, e.Name)
} else {
resolverArgs := "" resolverArgs := ""
for _, field := range e.KeyFields { for _, keyField := range r.KeyFields {
resolverArgs += fmt.Sprintf("%s: %s,", field.Field.Name, field.Field.Type.String()) resolverArgs += fmt.Sprintf("%s: %s,", keyField.Field.ToGoPrivate(), keyField.Definition.Type.String())
}
resolvers += fmt.Sprintf("\t%s(%s): %s!\n", r.ResolverName, resolverArgs, e.Name)
}
} }
resolvers += fmt.Sprintf("\t%s(%s): %s!\n", e.ResolverName, resolverArgs, e.Def.Name)
} }
} var blocks []string
if entities != "" {
if len(f.Entities) == 0 { entities = `# a union of all types that use the @key directive
// It's unusual for a service not to have any entities, but union _Entity = ` + entities
// possible if it only exports top-level queries and mutations. blocks = append(blocks, entities)
return nil
} }
// resolvers can be empty if a service defines only "empty // resolvers can be empty if a service defines only "empty
// extend" types. This should be rare. // extend" types. This should be rare.
if resolvers != "" { if resolvers != "" {
resolvers = ` if entityResolverInputDefinitions != "" {
# fake type to build resolver interfaces for users to implement blocks = append(blocks, entityResolverInputDefinitions)
}
resolvers = `# fake type to build resolver interfaces for users to implement
type Entity { type Entity {
` + resolvers + ` ` + resolvers + `
}`
blocks = append(blocks, resolvers)
} }
_serviceTypeDef := `type _Service {
sdl: String
}`
blocks = append(blocks, _serviceTypeDef)
var additionalQueryFields string
// Quote from the Apollo Federation subgraph specification:
// If no types are annotated with the key directive, then the
// _Entity union and _entities field should be removed from the schema
if len(f.Entities) > 0 {
additionalQueryFields += ` _entities(representations: [_Any!]!): [_Entity]!
` `
} }
// _service field is required in any case
additionalQueryFields += ` _service: _Service!`
extendTypeQueryDef := `extend type ` + schema.Query.Name + ` {
` + additionalQueryFields + `
}`
blocks = append(blocks, extendTypeQueryDef)
return &ast.Source{ return &ast.Source{
Name: "federation/entity.graphql", Name: "federation/entity.graphql",
BuiltIn: true, BuiltIn: true,
Input: ` Input: "\n" + strings.Join(blocks, "\n\n") + "\n",
# a union of all types that use the @key directive
union _Entity = ` + entities + `
` + resolvers + `
type _Service {
sdl: String
}
extend type Query {
_entities(representations: [_Any!]!): [_Entity]!
_service: _Service!
}
`,
} }
} }
@@ -145,29 +168,29 @@ extend type Query {
// that was declared in the GQL schema. // that was declared in the GQL schema.
type Entity struct { type Entity struct {
Name string // The same name as the type declaration Name string // The same name as the type declaration
KeyFields []*KeyField // The fields declared in @key.
ResolverName string // The resolver name, such as FindUserByID
Def *ast.Definition Def *ast.Definition
Resolvers []*EntityResolver
Requires []*Requires Requires []*Requires
Multi bool
}
type EntityResolver struct {
ResolverName string // The resolver name, such as FindUserByID
KeyFields []*KeyField // The fields declared in @key.
InputType string // The Go generated input type for multi entity resolvers
} }
type KeyField struct { type KeyField struct {
Field *ast.FieldDefinition Definition *ast.FieldDefinition
TypeReference *config.TypeReference // The Go representation of that field type Field fieldset.Field // len > 1 for nested fields
Type *config.TypeReference // The Go representation of that field type
} }
// Requires represents an @requires clause // Requires represents an @requires clause
type Requires struct { type Requires struct {
Name string // the name of the field Name string // the name of the field
Fields []*RequireField // the name of the sibling fields Field fieldset.Field // source Field, len > 1 for nested fields
} Type *config.TypeReference // The Go representation of that field type
// RequireField is similar to an entity but it is a field not
// an object
type RequireField struct {
Name string // The same name as the type declaration
NameGo string // The Go struct field name
TypeReference *config.TypeReference // The Go representation of that field type
} }
func (e *Entity) allFieldsAreExternal() bool { func (e *Entity) allFieldsAreExternal() bool {
@@ -186,22 +209,31 @@ func (f *federation) GenerateCode(data *codegen.Data) error {
} }
for _, e := range f.Entities { for _, e := range f.Entities {
obj := data.Objects.ByName(e.Def.Name) obj := data.Objects.ByName(e.Def.Name)
for _, field := range obj.Fields {
// Storing key fields in a slice rather than a map for _, r := range e.Resolvers {
// to preserve insertion order at the tradeoff of higher // fill in types for key fields
// lookup complexity. //
keyField := f.getKeyField(e.KeyFields, field.Name) for _, keyField := range r.KeyFields {
if keyField != nil { if len(keyField.Field) == 0 {
keyField.TypeReference = field.TypeReference fmt.Println(
"skipping @key field " + keyField.Definition.Name + " in " + r.ResolverName + " in " + e.Def.Name,
)
continue
} }
for _, r := range e.Requires { cgField := keyField.Field.TypeReference(obj, data.Objects)
for _, rf := range r.Fields { keyField.Type = cgField.TypeReference
if rf.Name == field.Name {
rf.TypeReference = field.TypeReference
rf.NameGo = field.GoFieldName
} }
} }
// fill in types for requires fields
//
for _, reqField := range e.Requires {
if len(reqField.Field) == 0 {
fmt.Println("skipping @requires field " + reqField.Name + " in " + e.Def.Name)
continue
} }
cgField := reqField.Field.TypeReference(obj, data.Objects)
reqField.Type = cgField.TypeReference
} }
} }
} }
@@ -215,68 +247,29 @@ func (f *federation) GenerateCode(data *codegen.Data) error {
}) })
} }
func (f *federation) getKeyField(keyFields []*KeyField, fieldName string) *KeyField {
for _, field := range keyFields {
if field.Field.Name == fieldName {
return field
}
}
return nil
}
func (f *federation) setEntities(schema *ast.Schema) { func (f *federation) setEntities(schema *ast.Schema) {
for _, schemaType := range schema.Types { for _, schemaType := range schema.Types {
if schemaType.Kind == ast.Object { keys, ok := isFederatedEntity(schemaType)
dir := schemaType.Directives.ForName("key") // TODO: interfaces if !ok {
if dir != nil {
if len(dir.Arguments) > 1 {
panic("Multiple arguments are not currently supported in @key declaration.")
}
fieldName := dir.Arguments[0].Value.Raw // TODO: multiple arguments
if strings.Contains(fieldName, "{") {
panic("Nested fields are not currently supported in @key declaration.")
}
requires := []*Requires{}
for _, f := range schemaType.Fields {
dir := f.Directives.ForName("requires")
if dir == nil {
continue continue
} }
fields := strings.Split(dir.Arguments[0].Value.Raw, " ")
requireFields := []*RequireField{}
for _, f := range fields {
requireFields = append(requireFields, &RequireField{
Name: f,
})
}
requires = append(requires, &Requires{
Name: f.Name,
Fields: requireFields,
})
}
fieldNames := strings.Split(fieldName, " ")
keyFields := make([]*KeyField, len(fieldNames))
resolverName := fmt.Sprintf("find%sBy", schemaType.Name)
for i, f := range fieldNames {
field := schemaType.Fields.ForName(f)
keyFields[i] = &KeyField{Field: field}
if i > 0 {
resolverName += "And"
}
resolverName += templates.ToGo(f)
}
e := &Entity{ e := &Entity{
Name: schemaType.Name, Name: schemaType.Name,
KeyFields: keyFields,
Def: schemaType, Def: schemaType,
ResolverName: resolverName, Resolvers: nil,
Requires: requires, Requires: nil,
} }
// Let's process custom entity resolver settings.
dir := schemaType.Directives.ForName("entityResolver")
if dir != nil {
if dirArg := dir.Arguments.ForName("multi"); dirArg != nil {
if dirVal, err := dirArg.Value.Value(nil); err == nil {
e.Multi = dirVal.(bool)
}
}
}
// If our schema has a field with a type defined in // If our schema has a field with a type defined in
// another service, then we need to define an "empty // another service, then we need to define an "empty
// extend" of that type in this service, so this service // extend" of that type in this service, so this service
@@ -295,17 +288,91 @@ func (f *federation) setEntities(schema *ast.Schema) {
// extend TypeDefinedInOtherService @key(fields: "id") { // extend TypeDefinedInOtherService @key(fields: "id") {
// id: ID @external // id: ID @external
// } // }
if e.allFieldsAreExternal() { if !e.allFieldsAreExternal() {
e.ResolverName = "" for _, dir := range keys {
if len(dir.Arguments) != 1 || dir.Arguments[0].Name != "fields" {
panic("Exactly one `fields` argument needed for @key declaration.")
}
arg := dir.Arguments[0]
keyFieldSet := fieldset.New(arg.Value.Raw, nil)
keyFields := make([]*KeyField, len(keyFieldSet))
resolverFields := []string{}
for i, field := range keyFieldSet {
def := field.FieldDefinition(schemaType, schema)
if def == nil {
panic(fmt.Sprintf("no field for %v", field))
} }
keyFields[i] = &KeyField{Definition: def, Field: field}
resolverFields = append(resolverFields, keyFields[i].Field.ToGo())
}
resolverFieldsToGo := schemaType.Name + "By" + strings.Join(resolverFields, "And")
var resolverName string
if e.Multi {
resolverFieldsToGo += "s" // Pluralize for better API readability
resolverName = fmt.Sprintf("findMany%s", resolverFieldsToGo)
} else {
resolverName = fmt.Sprintf("find%s", resolverFieldsToGo)
}
e.Resolvers = append(e.Resolvers, &EntityResolver{
ResolverName: resolverName,
KeyFields: keyFields,
InputType: resolverFieldsToGo + "Input",
})
}
e.Requires = []*Requires{}
for _, f := range schemaType.Fields {
dir := f.Directives.ForName("requires")
if dir == nil {
continue
}
if len(dir.Arguments) != 1 || dir.Arguments[0].Name != "fields" {
panic("Exactly one `fields` argument needed for @requires declaration.")
}
requiresFieldSet := fieldset.New(dir.Arguments[0].Value.Raw, nil)
for _, field := range requiresFieldSet {
e.Requires = append(e.Requires, &Requires{
Name: field.ToGoPrivate(),
Field: field,
})
}
}
}
f.Entities = append(f.Entities, e) f.Entities = append(f.Entities, e)
} }
}
}
// make sure order remains stable across multiple builds // make sure order remains stable across multiple builds
sort.Slice(f.Entities, func(i, j int) bool { sort.Slice(f.Entities, func(i, j int) bool {
return f.Entities[i].Name < f.Entities[j].Name return f.Entities[i].Name < f.Entities[j].Name
}) })
} }
func isFederatedEntity(schemaType *ast.Definition) ([]*ast.Directive, bool) {
switch schemaType.Kind {
case ast.Object:
keys := schemaType.Directives.ForNames("key")
if len(keys) > 0 {
return keys, true
}
case ast.Interface:
// TODO: support @key and @extends for interfaces
if dir := schemaType.Directives.ForName("key"); dir != nil {
fmt.Printf("@key directive found on \"interface %s\". Will be ignored.\n", schemaType.Name)
}
if dir := schemaType.Directives.ForName("extends"); dir != nil {
panic(
fmt.Sprintf(
"@extends directive is not currently supported for interfaces, use \"extend interface %s\" instead.",
schemaType.Name,
))
}
default:
// ignore
}
return nil, false
}

View File

@@ -2,9 +2,15 @@
{{ reserveImport "errors" }} {{ reserveImport "errors" }}
{{ reserveImport "fmt" }} {{ reserveImport "fmt" }}
{{ reserveImport "strings" }} {{ reserveImport "strings" }}
{{ reserveImport "sync" }}
{{ reserveImport "github.com/99designs/gqlgen/plugin/federation/fedruntime" }} {{ reserveImport "github.com/99designs/gqlgen/plugin/federation/fedruntime" }}
var (
ErrUnknownType = errors.New("unknown type")
ErrTypeNotFound = errors.New("type not found")
)
func (ec *executionContext) __resolve__service(ctx context.Context) (fedruntime.Service, error) { func (ec *executionContext) __resolve__service(ctx context.Context) (fedruntime.Service, error) {
if ec.DisableIntrospection { if ec.DisableIntrospection {
return fedruntime.Service{}, errors.New("federated introspection disabled") return fedruntime.Service{}, errors.New("federated introspection disabled")
@@ -25,45 +31,229 @@ func (ec *executionContext) __resolve__service(ctx context.Context) (fedruntime.
} }
{{if .Entities}} {{if .Entities}}
func (ec *executionContext) __resolve_entities(ctx context.Context, representations []map[string]interface{}) ([]fedruntime.Entity, error) { func (ec *executionContext) __resolve_entities(ctx context.Context, representations []map[string]interface{}) []fedruntime.Entity {
list := []fedruntime.Entity{} list := make([]fedruntime.Entity, len(representations))
for _, rep := range representations {
repsMap := map[string]struct {
i []int
r []map[string]interface{}
}{}
// We group entities by typename so that we can parallelize their resolution.
// This is particularly helpful when there are entity groups in multi mode.
buildRepresentationGroups := func(reps []map[string]interface{}) {
for i, rep := range reps {
typeName, ok := rep["__typename"].(string) typeName, ok := rep["__typename"].(string)
if !ok { if !ok {
return nil, errors.New("__typename must be an existing string") // If there is no __typename, we just skip the representation;
// we just won't be resolving these unknown types.
ec.Error(ctx, errors.New("__typename must be an existing string"))
continue
} }
_r := repsMap[typeName]
_r.i = append(_r.i, i)
_r.r = append(_r.r, rep)
repsMap[typeName] = _r
}
}
isMulti := func(typeName string) bool {
switch typeName { switch typeName {
{{ range .Entities }} {{- range .Entities -}}
{{ if .ResolverName }} {{- if .Resolvers -}}
{{- if .Multi -}}
case "{{.Def.Name}}": case "{{.Def.Name}}":
{{ range $i, $keyField := .KeyFields -}} return true
id{{$i}}, err := ec.{{.TypeReference.UnmarshalFunc}}(ctx, rep["{{$keyField.Field.Name}}"])
if err != nil {
return nil, errors.New(fmt.Sprintf("Field %s undefined in schema.", "{{$keyField.Field.Name}}"))
}
{{end}}
entity, err := ec.resolvers.Entity().{{.ResolverName | go}}(ctx,
{{ range $i, $_ := .KeyFields -}} id{{$i}}, {{end}})
if err != nil {
return nil, err
}
{{ range .Requires }}
{{ range .Fields}}
entity.{{.NameGo}}, err = ec.{{.TypeReference.UnmarshalFunc}}(ctx, rep["{{.Name}}"])
if err != nil {
return nil, err
}
{{ end }}
{{ end }}
list = append(list, entity)
{{ end }}
{{ end }} {{ end }}
{{- end -}}
{{- end -}}
default: default:
return nil, errors.New("unknown type: "+typeName) return false
} }
} }
return list, nil
resolveEntity := func(ctx context.Context, typeName string, rep map[string]interface{}, idx []int, i int) (err error) {
// we need to do our own panic handling, because we may be called in a
// goroutine, where the usual panic handling can't catch us
defer func () {
if r := recover(); r != nil {
err = ec.Recover(ctx, r)
}
}()
switch typeName {
{{ range $_, $entity := .Entities }}
{{- if and .Resolvers (not .Multi) -}}
case "{{.Def.Name}}":
resolverName, err := entityResolverNameFor{{.Def.Name}}(ctx, rep)
if err != nil {
return fmt.Errorf(`finding resolver for Entity "{{.Def.Name}}": %w`, err)
}
switch resolverName {
{{ range $i, $resolver := .Resolvers }}
case "{{.ResolverName}}":
{{- range $j, $keyField := .KeyFields }}
id{{$j}}, err := ec.{{.Type.UnmarshalFunc}}(ctx, rep["{{.Field.Join `"].(map[string]interface{})["`}}"])
if err != nil {
return fmt.Errorf(`unmarshalling param {{$j}} for {{$resolver.ResolverName}}(): %w`, err)
}
{{- end}}
entity, err := ec.resolvers.Entity().{{.ResolverName | go}}(ctx, {{- range $j, $_ := .KeyFields -}} id{{$j}}, {{end}})
if err != nil {
return fmt.Errorf(`resolving Entity "{{$entity.Def.Name}}": %w`, err)
}
{{ range $entity.Requires }}
entity.{{.Field.JoinGo `.`}}, err = ec.{{.Type.UnmarshalFunc}}(ctx, rep["{{.Field.Join `"].(map[string]interface{})["`}}"])
if err != nil {
return err
}
{{- end }}
list[idx[i]] = entity
return nil
{{- end }}
} }
{{ end }} {{ end }}
{{- end }}
}
return fmt.Errorf("%w: %s", ErrUnknownType, typeName)
}
resolveManyEntities := func(ctx context.Context, typeName string, reps []map[string]interface{}, idx []int) (err error) {
// we need to do our own panic handling, because we may be called in a
// goroutine, where the usual panic handling can't catch us
defer func () {
if r := recover(); r != nil {
err = ec.Recover(ctx, r)
}
}()
switch typeName {
{{ range $_, $entity := .Entities }}
{{ if and .Resolvers .Multi -}}
case "{{.Def.Name}}":
{{range $i, $_ := .Resolvers -}}
_reps := make([]*{{.InputType}}, len(reps))
for i, rep := range reps {
{{ range $i, $keyField := .KeyFields -}}
id{{$i}}, err := ec.{{.Type.UnmarshalFunc}}(ctx, rep["{{.Field.Join `"].(map[string]interface{})["`}}"])
if err != nil {
return errors.New(fmt.Sprintf("Field %s undefined in schema.", "{{.Definition.Name}}"))
}
{{end}}
_reps[i] = &{{.InputType}} {
{{ range $i, $keyField := .KeyFields -}}
{{$keyField.Field.ToGo}}: id{{$i}},
{{end}}
}
}
entities, err := ec.resolvers.Entity().{{.ResolverName | go}}(ctx, _reps)
if err != nil {
return err
}
for i, entity := range entities {
{{- range $entity.Requires }}
entity.{{.Field.JoinGo `.`}}, err = ec.{{.Type.UnmarshalFunc}}(ctx, reps[i]["{{.Field.Join `"].(map[string]interface{})["`}}"])
if err != nil {
return err
}
{{- end}}
list[idx[i]] = entity
}
return nil
{{ end }}
{{ end }}
{{- end }}
default:
return errors.New("unknown type: "+typeName)
}
}
resolveEntityGroup := func(typeName string, reps []map[string]interface{}, idx []int) {
if isMulti(typeName) {
err := resolveManyEntities(ctx, typeName, reps, idx)
if err != nil {
ec.Error(ctx, err)
}
} else {
// if there are multiple entities to resolve, parallelize (similar to
// graphql.FieldSet.Dispatch)
var e sync.WaitGroup
e.Add(len(reps))
for i, rep := range reps {
i, rep := i, rep
go func(i int, rep map[string]interface{}) {
err := resolveEntity(ctx, typeName, rep, idx, i)
if err != nil {
ec.Error(ctx, err)
}
e.Done()
}(i, rep)
}
e.Wait()
}
}
buildRepresentationGroups(representations)
switch len(repsMap) {
case 0:
return list
case 1:
for typeName, reps := range repsMap {
resolveEntityGroup(typeName, reps.r, reps.i)
}
return list
default:
var g sync.WaitGroup
g.Add(len(repsMap))
for typeName, reps := range repsMap {
go func(typeName string, reps []map[string]interface{}, idx []int) {
resolveEntityGroup(typeName, reps, idx)
g.Done()
}(typeName, reps.r, reps.i)
}
g.Wait()
return list
}
}
{{- /* Make sure the required fields are in the given entity representation and return the name of the proper resolver. */ -}}
{{ range $_, $entity := .Entities }}
{{- if .Resolvers }}
func entityResolverNameFor{{$entity.Name}}(ctx context.Context, rep map[string]interface{}) (string, error) {
{{- range .Resolvers }}
for {
var (
m map[string]interface{}
val interface{}
ok bool
)
_ = val
{{- range $_, $keyField := .KeyFields }}
m = rep
{{- range $i, $field := .Field }}
if {{ if (ne $i $keyField.Field.LastIndex ) -}}val{{- else -}}_{{- end -}}, ok = m["{{.}}"]; !ok {
break
}
{{- if (ne $i $keyField.Field.LastIndex ) }}
if m, ok = val.(map[string]interface{}); !ok {
break
}
{{- end}}
{{- end}}
{{- end }}
return "{{.ResolverName}}", nil
}
{{- end }}
return "", fmt.Errorf("%w for {{$entity.Name}}", ErrTypeNotFound)
}
{{- end }}
{{- end }}
{{end}}

View File

@@ -0,0 +1,193 @@
package fieldset
import (
"fmt"
"strings"
"github.com/99designs/gqlgen/codegen"
"github.com/99designs/gqlgen/codegen/templates"
"github.com/vektah/gqlparser/v2/ast"
)
// Set represents a FieldSet that is used in federation directives @key and @requires.
// Would be happier to reuse FieldSet parsing from gqlparser, but this suits for now.
//
type Set []Field
// Field represents a single field in a FieldSet
//
type Field []string
// New parses a FieldSet string into a TinyFieldSet.
//
func New(raw string, prefix []string) Set {
if !strings.Contains(raw, "{") {
return parseUnnestedKeyFieldSet(raw, prefix)
}
var (
ret = Set{}
subPrefix = prefix
)
before, during, after := extractSubs(raw)
if before != "" {
befores := New(before, prefix)
if len(befores) > 0 {
subPrefix = befores[len(befores)-1]
ret = append(ret, befores[:len(befores)-1]...)
}
}
if during != "" {
ret = append(ret, New(during, subPrefix)...)
}
if after != "" {
ret = append(ret, New(after, prefix)...)
}
return ret
}
// FieldDefinition looks up a field in the type.
//
func (f Field) FieldDefinition(schemaType *ast.Definition, schema *ast.Schema) *ast.FieldDefinition {
objType := schemaType
def := objType.Fields.ForName(f[0])
for _, part := range f[1:] {
if objType.Kind != ast.Object {
panic(fmt.Sprintf(`invalid sub-field reference "%s" in %v: `, objType.Name, f))
}
x := def.Type.Name()
objType = schema.Types[x]
if objType == nil {
panic("invalid schema type: " + x)
}
def = objType.Fields.ForName(part)
}
if def == nil {
return nil
}
ret := *def // shallow copy
ret.Name = f.ToGoPrivate()
return &ret
}
// TypeReference looks up the type of a field.
//
func (f Field) TypeReference(obj *codegen.Object, objects codegen.Objects) *codegen.Field {
var def *codegen.Field
for _, part := range f {
def = fieldByName(obj, part)
if def == nil {
panic("unable to find field " + f[0])
}
obj = objects.ByName(def.TypeReference.Definition.Name)
}
return def
}
// ToGo converts a (possibly nested) field into a proper public Go name.
//
func (f Field) ToGo() string {
var ret string
for _, field := range f {
ret += templates.ToGo(field)
}
return ret
}
// ToGoPrivate converts a (possibly nested) field into a proper private Go name.
//
func (f Field) ToGoPrivate() string {
var ret string
for i, field := range f {
if i == 0 {
ret += templates.ToGoPrivate(field)
continue
}
ret += templates.ToGo(field)
}
return ret
}
// Join concatenates the field parts with a string separator between. Useful in templates.
//
func (f Field) Join(str string) string {
return strings.Join(f, str)
}
// JoinGo concatenates the Go name of field parts with a string separator between. Useful in templates.
//
func (f Field) JoinGo(str string) string {
strs := []string{}
for _, s := range f {
strs = append(strs, templates.ToGo(s))
}
return strings.Join(strs, str)
}
func (f Field) LastIndex() int {
return len(f) - 1
}
// local functions
// parseUnnestedKeyFieldSet // handles simple case where none of the fields are nested.
//
func parseUnnestedKeyFieldSet(raw string, prefix []string) Set {
ret := Set{}
for _, s := range strings.Fields(raw) {
next := append(prefix[:], s) //nolint:gocritic // slicing out on purpose
ret = append(ret, next)
}
return ret
}
// extractSubs splits out and trims sub-expressions from before, inside, and after "{}".
//
func extractSubs(str string) (string, string, string) {
start := strings.Index(str, "{")
end := matchingBracketIndex(str, start)
if start < 0 || end < 0 {
panic("invalid key fieldSet: " + str)
}
return strings.TrimSpace(str[:start]), strings.TrimSpace(str[start+1 : end]), strings.TrimSpace(str[end+1:])
}
// matchingBracketIndex returns the index of the closing bracket, assuming an open bracket at start.
//
func matchingBracketIndex(str string, start int) int {
if start < 0 || len(str) <= start+1 {
return -1
}
var depth int
for i, c := range str[start+1:] {
switch c {
case '{':
depth++
case '}':
if depth == 0 {
return start + 1 + i
}
depth--
}
}
return -1
}
func fieldByName(obj *codegen.Object, name string) *codegen.Field {
for _, field := range obj.Fields {
if field.Name == name {
return field
}
}
return nil
}

View File

@@ -0,0 +1,39 @@
# Federation plugin
Add support for graphql federation in your graphql Go server!
TODO(miguel): add details.
# Tests
There are several different tests. Some will process the configuration file directly. You can see those in the `federation_test.go`. There are also tests for entity resolvers, which will simulate requests from a federation server like Apollo Federation.
Running entity resolver tests.
1. Go to `plugin/federation`
2. Run the command `go generate`
3. Run the tests with `go test ./...`.
# Architecture
TODO(miguel): add details.
# Entity resolvers - GetMany entities
The federation plugin implements `GetMany` semantics in which entity resolvers get the entire list of representations that need to be resolved. This functionality is currently optin tho, and to enable it you need to specify the directive `@entityResolver` in the federated entity you want this feature for. E.g.
```
directive @entityResolver(multi: Boolean) on OBJECT
type MultiHello @key(fields: "name") @entityResolver(multi: true) {
name: String!
}
```
That allows the federation plugin to generate `GetMany` resolver function that can take a list of representations to be resolved.
From that entity type, the resolver function would be
```
func (r *entityResolver) FindManyMultiHellosByName(ctx context.Context, reps []*generated.ManyMultiHellosByNameInput) ([]*generated.MultiHello, error) {
/// <Your code to resolve the list of items>
}
```

View File

@@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"go/types" "go/types"
"sort" "sort"
"strings"
"github.com/99designs/gqlgen/codegen/config" "github.com/99designs/gqlgen/codegen/config"
"github.com/99designs/gqlgen/codegen/templates" "github.com/99designs/gqlgen/codegen/templates"
@@ -13,6 +14,13 @@ import (
type BuildMutateHook = func(b *ModelBuild) *ModelBuild type BuildMutateHook = func(b *ModelBuild) *ModelBuild
type FieldMutateHook = func(td *ast.Definition, fd *ast.FieldDefinition, f *Field) (*Field, error)
// defaultFieldMutateHook is the default hook for the Plugin which applies the GoTagFieldHook.
func defaultFieldMutateHook(td *ast.Definition, fd *ast.FieldDefinition, f *Field) (*Field, error) {
return GoTagFieldHook(td, fd, f)
}
func defaultBuildMutateHook(b *ModelBuild) *ModelBuild { func defaultBuildMutateHook(b *ModelBuild) *ModelBuild {
return b return b
} }
@@ -28,6 +36,7 @@ type ModelBuild struct {
type Interface struct { type Interface struct {
Description string Description string
Name string Name string
Implements []string
} }
type Object struct { type Object struct {
@@ -58,11 +67,13 @@ type EnumValue struct {
func New() plugin.Plugin { func New() plugin.Plugin {
return &Plugin{ return &Plugin{
MutateHook: defaultBuildMutateHook, MutateHook: defaultBuildMutateHook,
FieldHook: defaultFieldMutateHook,
} }
} }
type Plugin struct { type Plugin struct {
MutateHook BuildMutateHook MutateHook BuildMutateHook
FieldHook FieldMutateHook
} }
var _ plugin.ConfigMutator = &Plugin{} var _ plugin.ConfigMutator = &Plugin{}
@@ -87,6 +98,7 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error {
it := &Interface{ it := &Interface{
Description: schemaType.Description, Description: schemaType.Description,
Name: schemaType.Name, Name: schemaType.Name,
Implements: schemaType.Interfaces,
} }
b.Interfaces = append(b.Interfaces, it) b.Interfaces = append(b.Interfaces, it)
@@ -98,8 +110,23 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error {
Description: schemaType.Description, Description: schemaType.Description,
Name: schemaType.Name, Name: schemaType.Name,
} }
// If Interface A implements interface B, and Interface C also implements interface B
// then both A and C have methods of B.
// The reason for checking unique is to prevent the same method B from being generated twice.
uniqueMap := map[string]bool{}
for _, implementor := range cfg.Schema.GetImplements(schemaType) { for _, implementor := range cfg.Schema.GetImplements(schemaType) {
if !uniqueMap[implementor.Name] {
it.Implements = append(it.Implements, implementor.Name) it.Implements = append(it.Implements, implementor.Name)
uniqueMap[implementor.Name] = true
}
// for interface implements
for _, iface := range implementor.Interfaces {
if !uniqueMap[iface] {
it.Implements = append(it.Implements, iface)
uniqueMap[iface] = true
}
}
} }
for _, field := range schemaType.Fields { for _, field := range schemaType.Fields {
@@ -162,12 +189,22 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error {
typ = types.NewPointer(typ) typ = types.NewPointer(typ)
} }
it.Fields = append(it.Fields, &Field{ f := &Field{
Name: name, Name: name,
Type: typ, Type: typ,
Description: field.Description, Description: field.Description,
Tag: `json:"` + field.Name + `"`, Tag: `json:"` + field.Name + `"`,
}) }
if m.FieldHook != nil {
mf, err := m.FieldHook(schemaType, field, f)
if err != nil {
return fmt.Errorf("generror: field %v.%v: %w", it.Name, field.Name, err)
}
f = mf
}
it.Fields = append(it.Fields, f)
} }
b.Models = append(b.Models, it) b.Models = append(b.Models, it)
@@ -214,13 +251,52 @@ func (m *Plugin) MutateConfig(cfg *config.Config) error {
b = m.MutateHook(b) b = m.MutateHook(b)
} }
return templates.Render(templates.Options{ err := templates.Render(templates.Options{
PackageName: cfg.Model.Package, PackageName: cfg.Model.Package,
Filename: cfg.Model.Filename, Filename: cfg.Model.Filename,
Data: b, Data: b,
GeneratedHeader: true, GeneratedHeader: true,
Packages: cfg.Packages, Packages: cfg.Packages,
}) })
if err != nil {
return err
}
// We may have generated code in a package we already loaded, so we reload all packages
// to allow packages to be compared correctly
cfg.ReloadAllPackages()
return nil
}
// GoTagFieldHook applies the goTag directive to the generated Field f. When applying the Tag to the field, the field
// name is used when no value argument is present.
func GoTagFieldHook(td *ast.Definition, fd *ast.FieldDefinition, f *Field) (*Field, error) {
args := make([]string, 0)
for _, goTag := range fd.Directives.ForNames("goTag") {
key := ""
value := fd.Name
if arg := goTag.Arguments.ForName("key"); arg != nil {
if k, err := arg.Value.Value(nil); err == nil {
key = k.(string)
}
}
if arg := goTag.Arguments.ForName("value"); arg != nil {
if v, err := arg.Value.Value(nil); err == nil {
value = v.(string)
}
}
args = append(args, key+":\""+value+"\"")
}
if len(args) > 0 {
f.Tag = f.Tag + " " + strings.Join(args, " ")
}
return f, nil
} }
func isStruct(t types.Type) bool { func isStruct(t types.Type) bool {

View File

@@ -15,6 +15,9 @@
{{- range $model := .Interfaces }} {{- range $model := .Interfaces }}
{{ with .Description }} {{.|prefixLines "// "}} {{ end }} {{ with .Description }} {{.|prefixLines "// "}} {{ end }}
type {{.Name|go }} interface { type {{.Name|go }} interface {
{{- range $impl := .Implements }}
{{ $impl|go }}
{{- end }}
Is{{.Name|go }}() Is{{.Name|go }}()
} }
{{- end }} {{- end }}

View File

@@ -1,6 +1,8 @@
package resolvergen package resolvergen
import ( import (
"errors"
"io/fs"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
@@ -10,7 +12,6 @@ import (
"github.com/99designs/gqlgen/codegen/templates" "github.com/99designs/gqlgen/codegen/templates"
"github.com/99designs/gqlgen/internal/rewrite" "github.com/99designs/gqlgen/internal/rewrite"
"github.com/99designs/gqlgen/plugin" "github.com/99designs/gqlgen/plugin"
"github.com/pkg/errors"
) )
func New() plugin.Plugin { func New() plugin.Plugin {
@@ -86,7 +87,11 @@ func (m *Plugin) generatePerSchema(data *codegen.Data) error {
files := map[string]*File{} files := map[string]*File{}
for _, o := range data.Objects { objects := make(codegen.Objects, len(data.Objects)+len(data.Inputs))
copy(objects, data.Objects)
copy(objects[len(data.Objects):], data.Inputs)
for _, o := range objects {
if o.HasResolvers() { if o.HasResolvers() {
fn := gqlToResolverName(data.Config.Resolver.Dir(), o.Position.Src.Name, data.Config.Resolver.FilenameTemplate) fn := gqlToResolverName(data.Config.Resolver.Dir(), o.Position.Src.Name, data.Config.Resolver.FilenameTemplate)
if files[fn] == nil { if files[fn] == nil {
@@ -94,7 +99,7 @@ func (m *Plugin) generatePerSchema(data *codegen.Data) error {
} }
rewriter.MarkStructCopied(templates.LcFirst(o.Name) + templates.UcFirst(data.Config.Resolver.Type)) rewriter.MarkStructCopied(templates.LcFirst(o.Name) + templates.UcFirst(data.Config.Resolver.Type))
rewriter.GetMethodBody(data.Config.Resolver.Type, o.Name) rewriter.GetMethodBody(data.Config.Resolver.Type, strings.Title(o.Name))
files[fn].Objects = append(files[fn].Objects, o) files[fn].Objects = append(files[fn].Objects, o)
} }
for _, f := range o.Fields { for _, f := range o.Fields {
@@ -144,7 +149,7 @@ func (m *Plugin) generatePerSchema(data *codegen.Data) error {
} }
} }
if _, err := os.Stat(data.Config.Resolver.Filename); os.IsNotExist(errors.Cause(err)) { if _, err := os.Stat(data.Config.Resolver.Filename); errors.Is(err, fs.ErrNotExist) {
err := templates.Render(templates.Options{ err := templates.Render(templates.Options{
PackageName: data.Config.Resolver.Package, PackageName: data.Config.Resolver.Package,
FileNotice: ` FileNotice: `

View File

@@ -26,8 +26,8 @@
{{ end }} {{ end }}
{{ range $object := .Objects -}} {{ range $object := .Objects -}}
// {{$object.Name}} returns {{ $object.ResolverInterface | ref }} implementation. // {{ucFirst $object.Name}} returns {{ $object.ResolverInterface | ref }} implementation.
func (r *{{$.ResolverType}}) {{$object.Name}}() {{ $object.ResolverInterface | ref }} { return &{{lcFirst $object.Name}}{{ucFirst $.ResolverType}}{r} } func (r *{{$.ResolverType}}) {{ucFirst $object.Name}}() {{ $object.ResolverInterface | ref }} { return &{{lcFirst $object.Name}}{{ucFirst $.ResolverType}}{r} }
{{ end }} {{ end }}
{{ range $object := .Objects -}} {{ range $object := .Objects -}}

View File

@@ -1,13 +1,14 @@
package servergen package servergen
import ( import (
"errors"
"io/fs"
"log" "log"
"os" "os"
"github.com/99designs/gqlgen/codegen" "github.com/99designs/gqlgen/codegen"
"github.com/99designs/gqlgen/codegen/templates" "github.com/99designs/gqlgen/codegen/templates"
"github.com/99designs/gqlgen/plugin" "github.com/99designs/gqlgen/plugin"
"github.com/pkg/errors"
) )
func New(filename string) plugin.Plugin { func New(filename string) plugin.Plugin {
@@ -23,13 +24,14 @@ var _ plugin.CodeGenerator = &Plugin{}
func (m *Plugin) Name() string { func (m *Plugin) Name() string {
return "servergen" return "servergen"
} }
func (m *Plugin) GenerateCode(data *codegen.Data) error { func (m *Plugin) GenerateCode(data *codegen.Data) error {
serverBuild := &ServerBuild{ serverBuild := &ServerBuild{
ExecPackageName: data.Config.Exec.ImportPath(), ExecPackageName: data.Config.Exec.ImportPath(),
ResolverPackageName: data.Config.Resolver.ImportPath(), ResolverPackageName: data.Config.Resolver.ImportPath(),
} }
if _, err := os.Stat(m.filename); os.IsNotExist(errors.Cause(err)) { if _, err := os.Stat(m.filename); errors.Is(err, fs.ErrNotExist) {
return templates.Render(templates.Options{ return templates.Render(templates.Options{
PackageName: "main", PackageName: "main",
Filename: m.filename, Filename: m.filename,

Some files were not shown because too many files have changed in this diff Show More