mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 12:24:38 +03:00
Stash box client interface (#751)
* Add gql client generation files * Update dependencies * Add stash-box client generation to the makefile * Move scraped scene object matchers to models * Add stash-box to scrape with dropdown * Add scrape scene from fingerprint in UI
This commit is contained in:
13
.gqlgenc.yml
Normal file
13
.gqlgenc.yml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
model:
|
||||||
|
filename: ./pkg/scraper/stashbox/graphql/generated_models.go
|
||||||
|
client:
|
||||||
|
filename: ./pkg/scraper/stashbox/graphql/generated_client.go
|
||||||
|
models:
|
||||||
|
Date:
|
||||||
|
model: github.com/99designs/gqlgen/graphql.String
|
||||||
|
endpoint:
|
||||||
|
# This points to stashdb.org currently, but can be directed at any stash-box
|
||||||
|
# instance. It is used for generation only.
|
||||||
|
url: https://stashdb.org/graphql
|
||||||
|
query:
|
||||||
|
- "./graphql/stash-box/*.graphql"
|
||||||
5
Makefile
5
Makefile
@@ -63,6 +63,11 @@ generate:
|
|||||||
go generate -mod=vendor
|
go generate -mod=vendor
|
||||||
cd ui/v2.5 && yarn run gqlgen
|
cd ui/v2.5 && yarn run gqlgen
|
||||||
|
|
||||||
|
# Regenerates stash-box client files
|
||||||
|
.PHONY: generate-stash-box-client
|
||||||
|
generate-stash-box-client:
|
||||||
|
go run -mod=vendor github.com/Yamashou/gqlgenc
|
||||||
|
|
||||||
# Runs gofmt -w on the project's source code, modifying any files that do not match its style.
|
# Runs gofmt -w on the project's source code, modifying any files that do not match its style.
|
||||||
.PHONY: fmt
|
.PHONY: fmt
|
||||||
fmt:
|
fmt:
|
||||||
|
|||||||
14
go.mod
14
go.mod
@@ -1,7 +1,8 @@
|
|||||||
module github.com/stashapp/stash
|
module github.com/stashapp/stash
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/99designs/gqlgen v0.9.0
|
github.com/99designs/gqlgen v0.12.2
|
||||||
|
github.com/Yamashou/gqlgenc v0.0.0-20200902035953-4dbef3551953
|
||||||
github.com/antchfx/htmlquery v1.2.3
|
github.com/antchfx/htmlquery v1.2.3
|
||||||
github.com/bmatcuk/doublestar/v2 v2.0.1
|
github.com/bmatcuk/doublestar/v2 v2.0.1
|
||||||
github.com/chromedp/cdproto v0.0.0-20200608134039-8a80cdaf865c
|
github.com/chromedp/cdproto v0.0.0-20200608134039-8a80cdaf865c
|
||||||
@@ -14,7 +15,6 @@ require (
|
|||||||
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/h2non/filetype v1.0.8
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
|
||||||
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
|
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
|
||||||
github.com/jmoiron/sqlx v1.2.0
|
github.com/jmoiron/sqlx v1.2.0
|
||||||
github.com/json-iterator/go v1.1.9
|
github.com/json-iterator/go v1.1.9
|
||||||
@@ -27,13 +27,13 @@ require (
|
|||||||
github.com/spf13/viper v1.7.0
|
github.com/spf13/viper v1.7.0
|
||||||
github.com/stretchr/testify v1.5.1
|
github.com/stretchr/testify v1.5.1
|
||||||
github.com/tidwall/gjson v1.6.0
|
github.com/tidwall/gjson v1.6.0
|
||||||
github.com/vektah/gqlparser v1.1.2
|
github.com/vektah/gqlparser/v2 v2.0.1
|
||||||
github.com/vektra/mockery v1.1.2 // indirect
|
|
||||||
github.com/vektra/mockery/v2 v2.2.1
|
github.com/vektra/mockery/v2 v2.2.1
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b
|
||||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9
|
golang.org/x/net v0.0.0-20200822124328-c89045814202
|
||||||
gopkg.in/yaml.v2 v2.2.4
|
golang.org/x/tools v0.0.0-20200915031644-64986481280e // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.3.0
|
||||||
)
|
)
|
||||||
|
|
||||||
replace git.apache.org/thrift.git => github.com/apache/thrift v0.0.0-20180902110319-2566ecd5d999
|
replace git.apache.org/thrift.git => github.com/apache/thrift v0.0.0-20180902110319-2566ecd5d999
|
||||||
|
|||||||
91
go.sum
91
go.sum
@@ -18,8 +18,8 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
|
|||||||
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
|
dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
|
||||||
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
|
dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
|
||||||
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
|
dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
|
||||||
github.com/99designs/gqlgen v0.9.0 h1:g1arBPML74Vqv0L3Q+TqIhGXLspV+2MYtRLkBxuZrlE=
|
github.com/99designs/gqlgen v0.12.2 h1:aOdpsiCycFtCnAv8CAI1exnKrIDHMqtMzQoXeTziY4o=
|
||||||
github.com/99designs/gqlgen v0.9.0/go.mod h1:HrrG7ic9EgLPsULxsZh/Ti+p0HNWgR3XRuvnD0pb5KY=
|
github.com/99designs/gqlgen v0.12.2/go.mod h1:7zdGo6ry9u1YBp/qlb2uxSU5Mt2jQKLcBETQiKk+Bxo=
|
||||||
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=
|
||||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
@@ -30,8 +30,14 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8
|
|||||||
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/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||||
|
github.com/Yamashou/gqlgenc v0.0.0-20200902035953-4dbef3551953 h1:+iPJDL28FxZhEdtJ9qykrMt/oDiOvlzTa0zV06nUcFM=
|
||||||
|
github.com/Yamashou/gqlgenc v0.0.0-20200902035953-4dbef3551953/go.mod h1:kaTsk10p2hJWwrB2t7vMsk1lXj9KAHaDYRtJQiB+Ick=
|
||||||
github.com/agnivade/levenshtein v1.0.1 h1:3oJU7J3FGFmyhn8KHjmVaZCN5hxTr7GxgRue+sxIXdQ=
|
github.com/agnivade/levenshtein v1.0.1 h1:3oJU7J3FGFmyhn8KHjmVaZCN5hxTr7GxgRue+sxIXdQ=
|
||||||
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 h1:M5ZnqLOoZR8ygVq0FfkXsNOKzMCk0xRiow0R5+5VkQ0=
|
||||||
|
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/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
||||||
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/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=
|
||||||
@@ -44,6 +50,8 @@ github.com/antchfx/xpath v1.1.6 h1:6sVh6hB5T6phw1pFpHRQ+C4bd8sNI+O58flqtg7h0R0=
|
|||||||
github.com/antchfx/xpath v1.1.6/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
|
github.com/antchfx/xpath v1.1.6/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk=
|
||||||
github.com/apache/thrift v0.0.0-20180902110319-2566ecd5d999/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
github.com/apache/thrift v0.0.0-20180902110319-2566ecd5d999/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||||
|
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/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/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=
|
||||||
@@ -77,6 +85,8 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
|
|||||||
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/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-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
|
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.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/cznic/b v0.0.0-20180115125044-35e9bbe41f07/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8=
|
github.com/cznic/b v0.0.0-20180115125044-35e9bbe41f07/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8=
|
||||||
github.com/cznic/fileutil v0.0.0-20180108211300-6a051e75936f/go.mod h1:8S58EK26zhXSxzv7NQFpnliaOQsmDUxvoQO3rt154Vg=
|
github.com/cznic/fileutil v0.0.0-20180108211300-6a051e75936f/go.mod h1:8S58EK26zhXSxzv7NQFpnliaOQsmDUxvoQO3rt154Vg=
|
||||||
@@ -93,6 +103,9 @@ 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/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/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/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
|
||||||
github.com/dhui/dktest v0.3.0/go.mod h1:cyzIUfGsBEbZ6BT7tnXqAShHSXCZhSNmFl70sZ7c1yc=
|
github.com/dhui/dktest v0.3.0/go.mod h1:cyzIUfGsBEbZ6BT7tnXqAShHSXCZhSNmFl70sZ7c1yc=
|
||||||
github.com/disintegration/imaging v1.6.0 h1:nVPXRUUQ36Z7MNf0O77UzgnOb1mkMMor7lmJMJXc/mA=
|
github.com/disintegration/imaging v1.6.0 h1:nVPXRUUQ36Z7MNf0O77UzgnOb1mkMMor7lmJMJXc/mA=
|
||||||
github.com/disintegration/imaging v1.6.0/go.mod h1:xuIt+sRxDFrHS0drzXUlCJthkJ8k7lkkUojDSR247MQ=
|
github.com/disintegration/imaging v1.6.0/go.mod h1:xuIt+sRxDFrHS0drzXUlCJthkJ8k7lkkUojDSR247MQ=
|
||||||
@@ -372,6 +385,8 @@ github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Z
|
|||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
|
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
|
||||||
|
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
@@ -383,6 +398,7 @@ github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk
|
|||||||
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
|
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
|
||||||
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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
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=
|
||||||
@@ -396,8 +412,6 @@ github.com/gorilla/sessions v1.1.2/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE
|
|||||||
github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
|
github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
|
||||||
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.2.0 h1:VJtLvh6VQym50czpZzx07z/kw9EgAxI3x1ZB8taTMQQ=
|
|
||||||
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
|
||||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
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=
|
||||||
@@ -455,6 +469,7 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV
|
|||||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
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/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
github.com/jtolds/gls v4.20.0+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/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
|
||||||
@@ -482,6 +497,7 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
|||||||
github.com/kshvakov/clickhouse v1.3.5/go.mod h1:DMzX7FxRymoNkVgizH0DWAL8Cur7wHLgx3MUnGwJqpE=
|
github.com/kshvakov/clickhouse v1.3.5/go.mod h1:DMzX7FxRymoNkVgizH0DWAL8Cur7wHLgx3MUnGwJqpE=
|
||||||
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
|
||||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
|
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||||
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||||
@@ -510,9 +526,14 @@ github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI=
|
|||||||
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/markbates/sigtx v1.0.0/go.mod h1:QF1Hv6Ic6Ca6W+T+DL0Y/ypborFKyvUY9HmuCD4VeTc=
|
github.com/markbates/sigtx v1.0.0/go.mod h1:QF1Hv6Ic6Ca6W+T+DL0Y/ypborFKyvUY9HmuCD4VeTc=
|
||||||
github.com/markbates/willie v1.0.9/go.mod h1:fsrFVWl91+gXpx/6dv715j7i11fYPfZ9ZGfH0DQzY7w=
|
github.com/markbates/willie v1.0.9/go.mod h1:fsrFVWl91+gXpx/6dv715j7i11fYPfZ9ZGfH0DQzY7w=
|
||||||
|
github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007 h1:reVOUXwnhsYv/8UqjvhrMOu5CNT9UapHFLbQ2JcXsmg=
|
||||||
|
github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
|
||||||
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.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
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.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4=
|
github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4=
|
||||||
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.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
|
github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o=
|
||||||
@@ -571,6 +592,8 @@ github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi
|
|||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
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=
|
||||||
@@ -604,7 +627,11 @@ 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/zerolog v1.18.0 h1:CbAm3kP2Tptby1i9sYy2MGRg0uxIN9cyDb59Ys7W8z8=
|
github.com/rs/zerolog v1.18.0 h1:CbAm3kP2Tptby1i9sYy2MGRg0uxIN9cyDb59Ys7W8z8=
|
||||||
github.com/rs/zerolog v1.18.0/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF5+I=
|
github.com/rs/zerolog v1.18.0/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF5+I=
|
||||||
|
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
||||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
|
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
|
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||||
|
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.0.1/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/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||||
@@ -612,6 +639,8 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg
|
|||||||
github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs=
|
github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs=
|
||||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
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/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=
|
||||||
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
|
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
|
||||||
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
|
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
|
||||||
@@ -637,6 +666,7 @@ github.com/shurcooL/octicon v0.0.0-20180602230221-c42b0e3b24d9/go.mod h1:eWdoE5J
|
|||||||
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
|
github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
|
||||||
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
|
github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
|
||||||
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
|
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/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
|
github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
|
||||||
github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
|
github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
|
||||||
@@ -650,7 +680,9 @@ github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
|
|||||||
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=
|
||||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||||
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 v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
|
||||||
@@ -684,6 +716,7 @@ github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
|||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||||
@@ -701,14 +734,14 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr
|
|||||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||||
github.com/unrolled/secure v0.0.0-20180918153822-f340ee86eb8b/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA=
|
github.com/unrolled/secure v0.0.0-20180918153822-f340ee86eb8b/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA=
|
||||||
github.com/unrolled/secure v0.0.0-20181005190816-ff9db2ff917f/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA=
|
github.com/unrolled/secure v0.0.0-20181005190816-ff9db2ff917f/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA=
|
||||||
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
|
github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k=
|
||||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
||||||
github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e h1:+w0Zm/9gaWpEAyDlU1eKOuk5twTjAjuevXqcJJw8hrg=
|
github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e h1:+w0Zm/9gaWpEAyDlU1eKOuk5twTjAjuevXqcJJw8hrg=
|
||||||
github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U=
|
github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U=
|
||||||
github.com/vektah/gqlparser v1.1.2 h1:ZsyLGn7/7jDNI+y4SEhI4yAxRChlv15pUHMjijT+e68=
|
github.com/vektah/gqlparser v1.3.1 h1:8b0IcD3qZKWJQHSzynbDlrtP3IxVydZ2DZepCGofqfU=
|
||||||
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
|
github.com/vektah/gqlparser v1.3.1/go.mod h1:bkVf0FX+Stjg/MHnm8mEyubuaArhNEqfQhF+OTiAL74=
|
||||||
github.com/vektra/mockery v1.1.2 h1:uc0Yn67rJpjt8U/mAZimdCKn9AeA97BOkjpmtBSlfP4=
|
github.com/vektah/gqlparser/v2 v2.0.1 h1:xgl5abVnsd4hkN9rk65OJID9bfcLSMuTaTcZj777q1o=
|
||||||
github.com/vektra/mockery v1.1.2/go.mod h1:VcfZjKaFOPO+MpN4ZvwPjs4c48lkq1o3Ym8yHZJu0jU=
|
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 h1:EYgPvxyYkm/0JKs62qlVc9pO+ljb8biPbDWabk5/PmI=
|
||||||
github.com/vektra/mockery/v2 v2.2.1/go.mod h1:rBZUbbhMbiSX1WlCGsOgAi6xjuJGxB7KKbnoL0XNYW8=
|
github.com/vektra/mockery/v2 v2.2.1/go.mod h1:rBZUbbhMbiSX1WlCGsOgAi6xjuJGxB7KKbnoL0XNYW8=
|
||||||
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=
|
||||||
@@ -717,6 +750,8 @@ github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0
|
|||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
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/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
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.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
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/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
@@ -752,18 +787,16 @@ golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/Le
|
|||||||
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
|
|
||||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
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=
|
||||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||||
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
||||||
golang.org/x/image v0.0.0-20190118043309-183bebdce1b2 h1:FNSSV4jv1PrPsiM2iKGpqLPPgYACqh9Muav7Pollk1k=
|
|
||||||
golang.org/x/image v0.0.0-20190118043309-183bebdce1b2/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
|
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
@@ -779,8 +812,11 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU
|
|||||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||||
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
|
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
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-20180816102801-aaf60122140d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180816102801-aaf60122140d/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=
|
||||||
@@ -812,11 +848,13 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgP
|
|||||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
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-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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20200421231249-e086a090c8fd h1:QPwSajcTUrFriMF1nJ3XzgoqakqQEsnZf9LdXdi2nkI=
|
golang.org/x/net v0.0.0-20200421231249-e086a090c8fd h1:QPwSajcTUrFriMF1nJ3XzgoqakqQEsnZf9LdXdi2nkI=
|
||||||
golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM=
|
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
|
||||||
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
@@ -833,6 +871,8 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=
|
||||||
|
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -859,6 +899,7 @@ golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||||||
golang.org/x/sys v0.0.0-20190116161447-11f53e031339 h1:g/Jesu8+QLnA0CPzF3E1pURg0Byr7i6jLoX5sqjcAh0=
|
golang.org/x/sys v0.0.0-20190116161447-11f53e031339 h1:g/Jesu8+QLnA0CPzF3E1pURg0Byr7i6jLoX5sqjcAh0=
|
||||||
golang.org/x/sys v0.0.0-20190116161447-11f53e031339/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190116161447-11f53e031339/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -933,12 +974,24 @@ 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-20191112195655-aa38f8e97acc/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-20191119224855-298f0cb1881e/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=
|
||||||
|
golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589 h1:rjUrONFu4kLchcZTfp3/96bR8bW8dIa8uz3cR5n0cgM=
|
||||||
|
golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.0.0-20200323144430-8dcfad9e016e h1:ssd5ulOvVWlh4kDSUF2SqzmMeWfjmwDXM+uGw/aQjRE=
|
golang.org/x/tools v0.0.0-20200323144430-8dcfad9e016e h1:ssd5ulOvVWlh4kDSUF2SqzmMeWfjmwDXM+uGw/aQjRE=
|
||||||
golang.org/x/tools v0.0.0-20200323144430-8dcfad9e016e/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
golang.org/x/tools v0.0.0-20200323144430-8dcfad9e016e/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||||
|
golang.org/x/tools v0.0.0-20200827163409-021d7c6f1ec3 h1:OjYQxZBKJFs+sJbHkvSGIKNMkZXDJQ9JsMpebGhkafI=
|
||||||
|
golang.org/x/tools v0.0.0-20200827163409-021d7c6f1ec3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
|
golang.org/x/tools v0.0.0-20200915031644-64986481280e h1:tfSNPIxC48Azhz4nLSPskz/yE9R6ftFRK8pfgfqWUAc=
|
||||||
|
golang.org/x/tools v0.0.0-20200915031644-64986481280e/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
|
||||||
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=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||||
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||||
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
|
google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
|
||||||
@@ -956,6 +1009,7 @@ google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO50
|
|||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c=
|
google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c=
|
||||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
|
||||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
@@ -984,6 +1038,8 @@ gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod
|
|||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
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/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
|
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
|
||||||
@@ -1000,6 +1056,9 @@ gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
|||||||
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.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||||
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.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||||
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
|
||||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|||||||
@@ -66,3 +66,9 @@ query ScrapeMovieURL($url: String!) {
|
|||||||
...ScrapedMovieData
|
...ScrapedMovieData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query QueryStashBoxScene($input: StashBoxQueryInput!) {
|
||||||
|
queryStashBoxScene(input: $input) {
|
||||||
|
...ScrapedSceneData
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -79,6 +79,9 @@ type Query {
|
|||||||
"""Scrape a list of performers from a query"""
|
"""Scrape a list of performers from a query"""
|
||||||
scrapeFreeonesPerformerList(query: String!): [String!]!
|
scrapeFreeonesPerformerList(query: String!): [String!]!
|
||||||
|
|
||||||
|
"""Query StashBox for scenes"""
|
||||||
|
queryStashBoxScene(input: StashBoxQueryInput!): [ScrapedScene!]!
|
||||||
|
|
||||||
# Plugins
|
# Plugins
|
||||||
"""List loaded plugins"""
|
"""List loaded plugins"""
|
||||||
plugins: [Plugin!]
|
plugins: [Plugin!]
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ type Scraper {
|
|||||||
movie: ScraperSpec
|
movie: ScraperSpec
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type ScrapedScenePerformer {
|
type ScrapedScenePerformer {
|
||||||
"""Set if performer matched"""
|
"""Set if performer matched"""
|
||||||
stored_id: ID
|
stored_id: ID
|
||||||
@@ -88,3 +87,12 @@ type ScrapedScene {
|
|||||||
performers: [ScrapedScenePerformer!]
|
performers: [ScrapedScenePerformer!]
|
||||||
movies: [ScrapedSceneMovie!]
|
movies: [ScrapedSceneMovie!]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input StashBoxQueryInput {
|
||||||
|
"""Index of the configured stash-box instance to use"""
|
||||||
|
stash_box_index: Int!
|
||||||
|
"""Instructs query by scene fingerprints"""
|
||||||
|
scene_ids: [ID!]
|
||||||
|
"""Query by query string"""
|
||||||
|
q: String
|
||||||
|
}
|
||||||
|
|||||||
139
graphql/stash-box/query.graphql
Normal file
139
graphql/stash-box/query.graphql
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
fragment URLFragment on URL {
|
||||||
|
url
|
||||||
|
type
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment ImageFragment on Image {
|
||||||
|
id
|
||||||
|
url
|
||||||
|
width
|
||||||
|
height
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment StudioFragment on Studio {
|
||||||
|
name
|
||||||
|
id
|
||||||
|
urls {
|
||||||
|
...URLFragment
|
||||||
|
}
|
||||||
|
images {
|
||||||
|
...ImageFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment TagFragment on Tag {
|
||||||
|
name
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
disambiguation
|
||||||
|
aliases
|
||||||
|
gender
|
||||||
|
urls {
|
||||||
|
...URLFragment
|
||||||
|
}
|
||||||
|
images {
|
||||||
|
...ImageFragment
|
||||||
|
}
|
||||||
|
birthdate {
|
||||||
|
...FuzzyDateFragment
|
||||||
|
}
|
||||||
|
ethnicity
|
||||||
|
country
|
||||||
|
eye_color
|
||||||
|
hair_color
|
||||||
|
height
|
||||||
|
measurements {
|
||||||
|
...MeasurementsFragment
|
||||||
|
}
|
||||||
|
breast_type
|
||||||
|
career_start_year
|
||||||
|
career_end_year
|
||||||
|
tattoos {
|
||||||
|
...BodyModificationFragment
|
||||||
|
}
|
||||||
|
piercings {
|
||||||
|
...BodyModificationFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment PerformerAppearanceFragment on PerformerAppearance {
|
||||||
|
as
|
||||||
|
performer {
|
||||||
|
...PerformerFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query FindSceneByFingerprint($fingerprint: FingerprintQueryInput!) {
|
||||||
|
findSceneByFingerprint(fingerprint: $fingerprint) {
|
||||||
|
...SceneFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query FindScenesByFingerprints($fingerprints: [String!]!) {
|
||||||
|
findScenesByFingerprints(fingerprints: $fingerprints) {
|
||||||
|
...SceneFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
query SearchScene($term: String!) {
|
||||||
|
searchScene(term: $term) {
|
||||||
|
...SceneFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutation SubmitFingerprint($input: FingerprintSubmission!) {
|
||||||
|
submitFingerprint(input: $input)
|
||||||
|
}
|
||||||
@@ -2,10 +2,13 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/stashapp/stash/pkg/manager"
|
"github.com/stashapp/stash/pkg/manager"
|
||||||
|
"github.com/stashapp/stash/pkg/manager/config"
|
||||||
"github.com/stashapp/stash/pkg/models"
|
"github.com/stashapp/stash/pkg/models"
|
||||||
"github.com/stashapp/stash/pkg/scraper"
|
"github.com/stashapp/stash/pkg/scraper"
|
||||||
|
"github.com/stashapp/stash/pkg/scraper/stashbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
// deprecated
|
// deprecated
|
||||||
@@ -72,3 +75,23 @@ func (r *queryResolver) ScrapeSceneURL(ctx context.Context, url string) (*models
|
|||||||
func (r *queryResolver) ScrapeMovieURL(ctx context.Context, url string) (*models.ScrapedMovie, error) {
|
func (r *queryResolver) ScrapeMovieURL(ctx context.Context, url string) (*models.ScrapedMovie, error) {
|
||||||
return manager.GetInstance().ScraperCache.ScrapeMovieURL(url)
|
return manager.GetInstance().ScraperCache.ScrapeMovieURL(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *queryResolver) QueryStashBoxScene(ctx context.Context, input models.StashBoxQueryInput) ([]*models.ScrapedScene, error) {
|
||||||
|
boxes := config.GetStashBoxes()
|
||||||
|
|
||||||
|
if input.StashBoxIndex < 0 || input.StashBoxIndex >= len(boxes) {
|
||||||
|
return nil, fmt.Errorf("invalid stash_box_index %d", input.StashBoxIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
client := stashbox.NewClient(*boxes[input.StashBoxIndex])
|
||||||
|
|
||||||
|
if len(input.SceneIds) > 0 {
|
||||||
|
return client.FindStashBoxScenesByFingerprints(input.SceneIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
if input.Q != nil {
|
||||||
|
return client.QueryStashBoxScene(*input.Q)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -129,16 +129,12 @@ func Start() {
|
|||||||
message := fmt.Sprintf("Internal system error. Error <%v>", err)
|
message := fmt.Sprintf("Internal system error. Error <%v>", err)
|
||||||
return errors.New(message)
|
return errors.New(message)
|
||||||
})
|
})
|
||||||
requestMiddleware := handler.RequestMiddleware(func(ctx context.Context, next func(ctx context.Context) []byte) []byte {
|
|
||||||
//api.GetRequestContext(ctx).Variables[]
|
|
||||||
return next(ctx)
|
|
||||||
})
|
|
||||||
websocketUpgrader := handler.WebsocketUpgrader(websocket.Upgrader{
|
websocketUpgrader := handler.WebsocketUpgrader(websocket.Upgrader{
|
||||||
CheckOrigin: func(r *http.Request) bool {
|
CheckOrigin: func(r *http.Request) bool {
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
gqlHandler := handler.GraphQL(models.NewExecutableSchema(models.Config{Resolvers: &Resolver{}}), recoverFunc, requestMiddleware, websocketUpgrader)
|
gqlHandler := handler.GraphQL(models.NewExecutableSchema(models.Config{Resolvers: &Resolver{}}), recoverFunc, websocketUpgrader)
|
||||||
|
|
||||||
r.Handle("/graphql", gqlHandler)
|
r.Handle("/graphql", gqlHandler)
|
||||||
r.Handle("/playground", handler.Playground("GraphQL playground", "/graphql"))
|
r.Handle("/playground", handler.Playground("GraphQL playground", "/graphql"))
|
||||||
|
|||||||
87
pkg/models/scraped.go
Normal file
87
pkg/models/scraped.go
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
// MatchScrapedScenePerformer matches the provided performer with the
|
||||||
|
// performers in the database and sets the ID field if one is found.
|
||||||
|
func MatchScrapedScenePerformer(p *ScrapedScenePerformer) error {
|
||||||
|
qb := NewPerformerQueryBuilder()
|
||||||
|
|
||||||
|
performers, err := qb.FindByNames([]string{p.Name}, nil, true)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(performers) != 1 {
|
||||||
|
// ignore - cannot match
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
id := strconv.Itoa(performers[0].ID)
|
||||||
|
p.ID = &id
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MatchScrapedSceneStudio matches the provided studio with the studios
|
||||||
|
// in the database and sets the ID field if one is found.
|
||||||
|
func MatchScrapedSceneStudio(s *ScrapedSceneStudio) error {
|
||||||
|
qb := NewStudioQueryBuilder()
|
||||||
|
|
||||||
|
studio, err := qb.FindByName(s.Name, nil, true)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if studio == nil {
|
||||||
|
// ignore - cannot match
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
id := strconv.Itoa(studio.ID)
|
||||||
|
s.ID = &id
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MatchScrapedSceneMovie matches the provided movie with the movies
|
||||||
|
// in the database and sets the ID field if one is found.
|
||||||
|
func MatchScrapedSceneMovie(m *ScrapedSceneMovie) error {
|
||||||
|
qb := NewMovieQueryBuilder()
|
||||||
|
|
||||||
|
movies, err := qb.FindByNames([]string{m.Name}, nil, true)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(movies) != 1 {
|
||||||
|
// ignore - cannot match
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
id := strconv.Itoa(movies[0].ID)
|
||||||
|
m.ID = &id
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MatchScrapedSceneTag matches the provided tag with the tags
|
||||||
|
// in the database and sets the ID field if one is found.
|
||||||
|
func MatchScrapedSceneTag(s *ScrapedSceneTag) error {
|
||||||
|
qb := NewTagQueryBuilder()
|
||||||
|
|
||||||
|
tag, err := qb.FindByName(s.Name, nil, true)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if tag == nil {
|
||||||
|
// ignore - cannot match
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
id := strconv.Itoa(tag.ID)
|
||||||
|
s.ID = &id
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -214,106 +214,30 @@ func (c Cache) ScrapePerformerURL(url string) (*models.ScrapedPerformer, error)
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchPerformer(p *models.ScrapedScenePerformer) error {
|
|
||||||
qb := models.NewPerformerQueryBuilder()
|
|
||||||
|
|
||||||
performers, err := qb.FindByNames([]string{p.Name}, nil, true)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(performers) != 1 {
|
|
||||||
// ignore - cannot match
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
id := strconv.Itoa(performers[0].ID)
|
|
||||||
p.ID = &id
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func matchStudio(s *models.ScrapedSceneStudio) error {
|
|
||||||
qb := models.NewStudioQueryBuilder()
|
|
||||||
|
|
||||||
studio, err := qb.FindByName(s.Name, nil, true)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if studio == nil {
|
|
||||||
// ignore - cannot match
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
id := strconv.Itoa(studio.ID)
|
|
||||||
s.ID = &id
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func matchMovie(m *models.ScrapedSceneMovie) error {
|
|
||||||
qb := models.NewMovieQueryBuilder()
|
|
||||||
|
|
||||||
movies, err := qb.FindByNames([]string{m.Name}, nil, true)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(movies) != 1 {
|
|
||||||
// ignore - cannot match
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
id := strconv.Itoa(movies[0].ID)
|
|
||||||
m.ID = &id
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func matchTag(s *models.ScrapedSceneTag) error {
|
|
||||||
qb := models.NewTagQueryBuilder()
|
|
||||||
|
|
||||||
tag, err := qb.FindByName(s.Name, nil, true)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if tag == nil {
|
|
||||||
// ignore - cannot match
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
id := strconv.Itoa(tag.ID)
|
|
||||||
s.ID = &id
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Cache) postScrapeScene(ret *models.ScrapedScene) error {
|
func (c Cache) postScrapeScene(ret *models.ScrapedScene) error {
|
||||||
for _, p := range ret.Performers {
|
for _, p := range ret.Performers {
|
||||||
err := matchPerformer(p)
|
err := models.MatchScrapedScenePerformer(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, p := range ret.Movies {
|
for _, p := range ret.Movies {
|
||||||
err := matchMovie(p)
|
err := models.MatchScrapedSceneMovie(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, t := range ret.Tags {
|
for _, t := range ret.Tags {
|
||||||
err := matchTag(t)
|
err := models.MatchScrapedSceneTag(t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ret.Studio != nil {
|
if ret.Studio != nil {
|
||||||
err := matchStudio(ret.Studio)
|
err := models.MatchScrapedSceneStudio(ret.Studio)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
559
pkg/scraper/stashbox/graphql/generated_client.go
Normal file
559
pkg/scraper/stashbox/graphql/generated_client.go
Normal file
@@ -0,0 +1,559 @@
|
|||||||
|
// Code generated by github.com/Yamashou/gqlgenc, DO NOT EDIT.
|
||||||
|
|
||||||
|
package graphql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/Yamashou/gqlgenc/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
Client *client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient(cli *http.Client, baseURL string, options ...client.HTTPRequestOption) *Client {
|
||||||
|
return &Client{Client: client.NewClient(cli, baseURL, options...)}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Query struct {
|
||||||
|
FindPerformer *Performer "json:\"findPerformer\" graphql:\"findPerformer\""
|
||||||
|
QueryPerformers QueryPerformersResultType "json:\"queryPerformers\" graphql:\"queryPerformers\""
|
||||||
|
FindStudio *Studio "json:\"findStudio\" graphql:\"findStudio\""
|
||||||
|
QueryStudios QueryStudiosResultType "json:\"queryStudios\" graphql:\"queryStudios\""
|
||||||
|
FindTag *Tag "json:\"findTag\" graphql:\"findTag\""
|
||||||
|
QueryTags QueryTagsResultType "json:\"queryTags\" graphql:\"queryTags\""
|
||||||
|
FindScene *Scene "json:\"findScene\" graphql:\"findScene\""
|
||||||
|
FindSceneByFingerprint []*Scene "json:\"findSceneByFingerprint\" graphql:\"findSceneByFingerprint\""
|
||||||
|
FindScenesByFingerprints []*Scene "json:\"findScenesByFingerprints\" graphql:\"findScenesByFingerprints\""
|
||||||
|
QueryScenes QueryScenesResultType "json:\"queryScenes\" graphql:\"queryScenes\""
|
||||||
|
FindEdit *Edit "json:\"findEdit\" graphql:\"findEdit\""
|
||||||
|
QueryEdits QueryEditsResultType "json:\"queryEdits\" graphql:\"queryEdits\""
|
||||||
|
FindUser *User "json:\"findUser\" graphql:\"findUser\""
|
||||||
|
QueryUsers QueryUsersResultType "json:\"queryUsers\" graphql:\"queryUsers\""
|
||||||
|
Me *User "json:\"me\" graphql:\"me\""
|
||||||
|
SearchPerformer []*Performer "json:\"searchPerformer\" graphql:\"searchPerformer\""
|
||||||
|
SearchScene []*Scene "json:\"searchScene\" graphql:\"searchScene\""
|
||||||
|
Version Version "json:\"version\" graphql:\"version\""
|
||||||
|
}
|
||||||
|
|
||||||
|
type Mutation struct {
|
||||||
|
SceneCreate *Scene "json:\"sceneCreate\" graphql:\"sceneCreate\""
|
||||||
|
SceneUpdate *Scene "json:\"sceneUpdate\" graphql:\"sceneUpdate\""
|
||||||
|
SceneDestroy bool "json:\"sceneDestroy\" graphql:\"sceneDestroy\""
|
||||||
|
PerformerCreate *Performer "json:\"performerCreate\" graphql:\"performerCreate\""
|
||||||
|
PerformerUpdate *Performer "json:\"performerUpdate\" graphql:\"performerUpdate\""
|
||||||
|
PerformerDestroy bool "json:\"performerDestroy\" graphql:\"performerDestroy\""
|
||||||
|
StudioCreate *Studio "json:\"studioCreate\" graphql:\"studioCreate\""
|
||||||
|
StudioUpdate *Studio "json:\"studioUpdate\" graphql:\"studioUpdate\""
|
||||||
|
StudioDestroy bool "json:\"studioDestroy\" graphql:\"studioDestroy\""
|
||||||
|
TagCreate *Tag "json:\"tagCreate\" graphql:\"tagCreate\""
|
||||||
|
TagUpdate *Tag "json:\"tagUpdate\" graphql:\"tagUpdate\""
|
||||||
|
TagDestroy bool "json:\"tagDestroy\" graphql:\"tagDestroy\""
|
||||||
|
UserCreate *User "json:\"userCreate\" graphql:\"userCreate\""
|
||||||
|
UserUpdate *User "json:\"userUpdate\" graphql:\"userUpdate\""
|
||||||
|
UserDestroy bool "json:\"userDestroy\" graphql:\"userDestroy\""
|
||||||
|
ImageCreate *Image "json:\"imageCreate\" graphql:\"imageCreate\""
|
||||||
|
ImageUpdate *Image "json:\"imageUpdate\" graphql:\"imageUpdate\""
|
||||||
|
ImageDestroy bool "json:\"imageDestroy\" graphql:\"imageDestroy\""
|
||||||
|
RegenerateAPIKey string "json:\"regenerateAPIKey\" graphql:\"regenerateAPIKey\""
|
||||||
|
ChangePassword bool "json:\"changePassword\" graphql:\"changePassword\""
|
||||||
|
SceneEdit Edit "json:\"sceneEdit\" graphql:\"sceneEdit\""
|
||||||
|
PerformerEdit Edit "json:\"performerEdit\" graphql:\"performerEdit\""
|
||||||
|
StudioEdit Edit "json:\"studioEdit\" graphql:\"studioEdit\""
|
||||||
|
TagEdit Edit "json:\"tagEdit\" graphql:\"tagEdit\""
|
||||||
|
EditVote Edit "json:\"editVote\" graphql:\"editVote\""
|
||||||
|
EditComment Edit "json:\"editComment\" graphql:\"editComment\""
|
||||||
|
ApplyEdit Edit "json:\"applyEdit\" graphql:\"applyEdit\""
|
||||||
|
CancelEdit Edit "json:\"cancelEdit\" graphql:\"cancelEdit\""
|
||||||
|
SubmitFingerprint bool "json:\"submitFingerprint\" graphql:\"submitFingerprint\""
|
||||||
|
}
|
||||||
|
type URLFragment struct {
|
||||||
|
URL string "json:\"url\" graphql:\"url\""
|
||||||
|
Type string "json:\"type\" graphql:\"type\""
|
||||||
|
}
|
||||||
|
type ImageFragment struct {
|
||||||
|
ID string "json:\"id\" graphql:\"id\""
|
||||||
|
URL string "json:\"url\" graphql:\"url\""
|
||||||
|
Width *int "json:\"width\" graphql:\"width\""
|
||||||
|
Height *int "json:\"height\" graphql:\"height\""
|
||||||
|
}
|
||||||
|
type StudioFragment struct {
|
||||||
|
Name string "json:\"name\" graphql:\"name\""
|
||||||
|
ID string "json:\"id\" graphql:\"id\""
|
||||||
|
Urls []*URLFragment "json:\"urls\" graphql:\"urls\""
|
||||||
|
Images []*ImageFragment "json:\"images\" graphql:\"images\""
|
||||||
|
}
|
||||||
|
type TagFragment struct {
|
||||||
|
Name string "json:\"name\" graphql:\"name\""
|
||||||
|
ID string "json:\"id\" graphql:\"id\""
|
||||||
|
}
|
||||||
|
type FuzzyDateFragment struct {
|
||||||
|
Date string "json:\"date\" graphql:\"date\""
|
||||||
|
Accuracy DateAccuracyEnum "json:\"accuracy\" graphql:\"accuracy\""
|
||||||
|
}
|
||||||
|
type MeasurementsFragment struct {
|
||||||
|
BandSize *int "json:\"band_size\" graphql:\"band_size\""
|
||||||
|
CupSize *string "json:\"cup_size\" graphql:\"cup_size\""
|
||||||
|
Waist *int "json:\"waist\" graphql:\"waist\""
|
||||||
|
Hip *int "json:\"hip\" graphql:\"hip\""
|
||||||
|
}
|
||||||
|
type BodyModificationFragment struct {
|
||||||
|
Location string "json:\"location\" graphql:\"location\""
|
||||||
|
Description *string "json:\"description\" graphql:\"description\""
|
||||||
|
}
|
||||||
|
type PerformerFragment struct {
|
||||||
|
ID string "json:\"id\" graphql:\"id\""
|
||||||
|
Name string "json:\"name\" graphql:\"name\""
|
||||||
|
Disambiguation *string "json:\"disambiguation\" graphql:\"disambiguation\""
|
||||||
|
Aliases []string "json:\"aliases\" graphql:\"aliases\""
|
||||||
|
Gender *GenderEnum "json:\"gender\" graphql:\"gender\""
|
||||||
|
Urls []*URLFragment "json:\"urls\" graphql:\"urls\""
|
||||||
|
Images []*ImageFragment "json:\"images\" graphql:\"images\""
|
||||||
|
Birthdate *FuzzyDateFragment "json:\"birthdate\" graphql:\"birthdate\""
|
||||||
|
Ethnicity *EthnicityEnum "json:\"ethnicity\" graphql:\"ethnicity\""
|
||||||
|
Country *string "json:\"country\" graphql:\"country\""
|
||||||
|
EyeColor *EyeColorEnum "json:\"eye_color\" graphql:\"eye_color\""
|
||||||
|
HairColor *HairColorEnum "json:\"hair_color\" graphql:\"hair_color\""
|
||||||
|
Height *int "json:\"height\" graphql:\"height\""
|
||||||
|
Measurements MeasurementsFragment "json:\"measurements\" graphql:\"measurements\""
|
||||||
|
BreastType *BreastTypeEnum "json:\"breast_type\" graphql:\"breast_type\""
|
||||||
|
CareerStartYear *int "json:\"career_start_year\" graphql:\"career_start_year\""
|
||||||
|
CareerEndYear *int "json:\"career_end_year\" graphql:\"career_end_year\""
|
||||||
|
Tattoos []*BodyModificationFragment "json:\"tattoos\" graphql:\"tattoos\""
|
||||||
|
Piercings []*BodyModificationFragment "json:\"piercings\" graphql:\"piercings\""
|
||||||
|
}
|
||||||
|
type PerformerAppearanceFragment struct {
|
||||||
|
As *string "json:\"as\" graphql:\"as\""
|
||||||
|
Performer PerformerFragment "json:\"performer\" graphql:\"performer\""
|
||||||
|
}
|
||||||
|
type FingerprintFragment struct {
|
||||||
|
Algorithm FingerprintAlgorithm "json:\"algorithm\" graphql:\"algorithm\""
|
||||||
|
Hash string "json:\"hash\" graphql:\"hash\""
|
||||||
|
Duration int "json:\"duration\" graphql:\"duration\""
|
||||||
|
}
|
||||||
|
type SceneFragment struct {
|
||||||
|
ID string "json:\"id\" graphql:\"id\""
|
||||||
|
Title *string "json:\"title\" graphql:\"title\""
|
||||||
|
Details *string "json:\"details\" graphql:\"details\""
|
||||||
|
Duration *int "json:\"duration\" graphql:\"duration\""
|
||||||
|
Date *string "json:\"date\" graphql:\"date\""
|
||||||
|
Urls []*URLFragment "json:\"urls\" graphql:\"urls\""
|
||||||
|
Images []*ImageFragment "json:\"images\" graphql:\"images\""
|
||||||
|
Studio *StudioFragment "json:\"studio\" graphql:\"studio\""
|
||||||
|
Tags []*TagFragment "json:\"tags\" graphql:\"tags\""
|
||||||
|
Performers []*PerformerAppearanceFragment "json:\"performers\" graphql:\"performers\""
|
||||||
|
Fingerprints []*FingerprintFragment "json:\"fingerprints\" graphql:\"fingerprints\""
|
||||||
|
}
|
||||||
|
type FindSceneByFingerprint struct {
|
||||||
|
FindSceneByFingerprint []*SceneFragment "json:\"findSceneByFingerprint\" graphql:\"findSceneByFingerprint\""
|
||||||
|
}
|
||||||
|
type FindScenesByFingerprints struct {
|
||||||
|
FindScenesByFingerprints []*SceneFragment "json:\"findScenesByFingerprints\" graphql:\"findScenesByFingerprints\""
|
||||||
|
}
|
||||||
|
type SearchScene struct {
|
||||||
|
SearchScene []*SceneFragment "json:\"searchScene\" graphql:\"searchScene\""
|
||||||
|
}
|
||||||
|
type SubmitFingerprintPayload struct {
|
||||||
|
SubmitFingerprint bool "json:\"submitFingerprint\" graphql:\"submitFingerprint\""
|
||||||
|
}
|
||||||
|
|
||||||
|
const FindSceneByFingerprintQuery = `query FindSceneByFingerprint ($fingerprint: FingerprintQueryInput!) {
|
||||||
|
findSceneByFingerprint(fingerprint: $fingerprint) {
|
||||||
|
... SceneFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragment SceneFragment on Scene {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
details
|
||||||
|
duration
|
||||||
|
date
|
||||||
|
urls {
|
||||||
|
... URLFragment
|
||||||
|
}
|
||||||
|
images {
|
||||||
|
... ImageFragment
|
||||||
|
}
|
||||||
|
studio {
|
||||||
|
... StudioFragment
|
||||||
|
}
|
||||||
|
tags {
|
||||||
|
... TagFragment
|
||||||
|
}
|
||||||
|
performers {
|
||||||
|
... PerformerAppearanceFragment
|
||||||
|
}
|
||||||
|
fingerprints {
|
||||||
|
... FingerprintFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragment TagFragment on Tag {
|
||||||
|
name
|
||||||
|
id
|
||||||
|
}
|
||||||
|
fragment PerformerFragment on Performer {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
disambiguation
|
||||||
|
aliases
|
||||||
|
gender
|
||||||
|
urls {
|
||||||
|
... URLFragment
|
||||||
|
}
|
||||||
|
images {
|
||||||
|
... ImageFragment
|
||||||
|
}
|
||||||
|
birthdate {
|
||||||
|
... FuzzyDateFragment
|
||||||
|
}
|
||||||
|
ethnicity
|
||||||
|
country
|
||||||
|
eye_color
|
||||||
|
hair_color
|
||||||
|
height
|
||||||
|
measurements {
|
||||||
|
... MeasurementsFragment
|
||||||
|
}
|
||||||
|
breast_type
|
||||||
|
career_start_year
|
||||||
|
career_end_year
|
||||||
|
tattoos {
|
||||||
|
... BodyModificationFragment
|
||||||
|
}
|
||||||
|
piercings {
|
||||||
|
... BodyModificationFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragment BodyModificationFragment on BodyModification {
|
||||||
|
location
|
||||||
|
description
|
||||||
|
}
|
||||||
|
fragment MeasurementsFragment on Measurements {
|
||||||
|
band_size
|
||||||
|
cup_size
|
||||||
|
waist
|
||||||
|
hip
|
||||||
|
}
|
||||||
|
fragment FingerprintFragment on Fingerprint {
|
||||||
|
algorithm
|
||||||
|
hash
|
||||||
|
duration
|
||||||
|
}
|
||||||
|
fragment URLFragment on URL {
|
||||||
|
url
|
||||||
|
type
|
||||||
|
}
|
||||||
|
fragment ImageFragment on Image {
|
||||||
|
id
|
||||||
|
url
|
||||||
|
width
|
||||||
|
height
|
||||||
|
}
|
||||||
|
fragment StudioFragment on Studio {
|
||||||
|
name
|
||||||
|
id
|
||||||
|
urls {
|
||||||
|
... URLFragment
|
||||||
|
}
|
||||||
|
images {
|
||||||
|
... ImageFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragment PerformerAppearanceFragment on PerformerAppearance {
|
||||||
|
as
|
||||||
|
performer {
|
||||||
|
... PerformerFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragment FuzzyDateFragment on FuzzyDate {
|
||||||
|
date
|
||||||
|
accuracy
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
func (c *Client) FindSceneByFingerprint(ctx context.Context, fingerprint FingerprintQueryInput, httpRequestOptions ...client.HTTPRequestOption) (*FindSceneByFingerprint, error) {
|
||||||
|
vars := map[string]interface{}{
|
||||||
|
"fingerprint": fingerprint,
|
||||||
|
}
|
||||||
|
|
||||||
|
var res FindSceneByFingerprint
|
||||||
|
if err := c.Client.Post(ctx, FindSceneByFingerprintQuery, &res, vars, httpRequestOptions...); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const FindScenesByFingerprintsQuery = `query FindScenesByFingerprints ($fingerprints: [String!]!) {
|
||||||
|
findScenesByFingerprints(fingerprints: $fingerprints) {
|
||||||
|
... SceneFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragment ImageFragment on Image {
|
||||||
|
id
|
||||||
|
url
|
||||||
|
width
|
||||||
|
height
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
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 PerformerAppearanceFragment on PerformerAppearance {
|
||||||
|
as
|
||||||
|
performer {
|
||||||
|
... PerformerFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragment PerformerFragment on Performer {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
disambiguation
|
||||||
|
aliases
|
||||||
|
gender
|
||||||
|
urls {
|
||||||
|
... URLFragment
|
||||||
|
}
|
||||||
|
images {
|
||||||
|
... ImageFragment
|
||||||
|
}
|
||||||
|
birthdate {
|
||||||
|
... FuzzyDateFragment
|
||||||
|
}
|
||||||
|
ethnicity
|
||||||
|
country
|
||||||
|
eye_color
|
||||||
|
hair_color
|
||||||
|
height
|
||||||
|
measurements {
|
||||||
|
... MeasurementsFragment
|
||||||
|
}
|
||||||
|
breast_type
|
||||||
|
career_start_year
|
||||||
|
career_end_year
|
||||||
|
tattoos {
|
||||||
|
... BodyModificationFragment
|
||||||
|
}
|
||||||
|
piercings {
|
||||||
|
... BodyModificationFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragment FuzzyDateFragment on FuzzyDate {
|
||||||
|
date
|
||||||
|
accuracy
|
||||||
|
}
|
||||||
|
fragment FingerprintFragment on Fingerprint {
|
||||||
|
algorithm
|
||||||
|
hash
|
||||||
|
duration
|
||||||
|
}
|
||||||
|
fragment URLFragment on URL {
|
||||||
|
url
|
||||||
|
type
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
func (c *Client) FindScenesByFingerprints(ctx context.Context, fingerprints []string, httpRequestOptions ...client.HTTPRequestOption) (*FindScenesByFingerprints, error) {
|
||||||
|
vars := map[string]interface{}{
|
||||||
|
"fingerprints": fingerprints,
|
||||||
|
}
|
||||||
|
|
||||||
|
var res FindScenesByFingerprints
|
||||||
|
if err := c.Client.Post(ctx, FindScenesByFingerprintsQuery, &res, vars, httpRequestOptions...); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const SearchSceneQuery = `query SearchScene ($term: String!) {
|
||||||
|
searchScene(term: $term) {
|
||||||
|
... SceneFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragment FuzzyDateFragment on FuzzyDate {
|
||||||
|
date
|
||||||
|
accuracy
|
||||||
|
}
|
||||||
|
fragment MeasurementsFragment on Measurements {
|
||||||
|
band_size
|
||||||
|
cup_size
|
||||||
|
waist
|
||||||
|
hip
|
||||||
|
}
|
||||||
|
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 TagFragment on Tag {
|
||||||
|
name
|
||||||
|
id
|
||||||
|
}
|
||||||
|
fragment PerformerAppearanceFragment on PerformerAppearance {
|
||||||
|
as
|
||||||
|
performer {
|
||||||
|
... PerformerFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragment PerformerFragment on Performer {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
disambiguation
|
||||||
|
aliases
|
||||||
|
gender
|
||||||
|
urls {
|
||||||
|
... URLFragment
|
||||||
|
}
|
||||||
|
images {
|
||||||
|
... ImageFragment
|
||||||
|
}
|
||||||
|
birthdate {
|
||||||
|
... FuzzyDateFragment
|
||||||
|
}
|
||||||
|
ethnicity
|
||||||
|
country
|
||||||
|
eye_color
|
||||||
|
hair_color
|
||||||
|
height
|
||||||
|
measurements {
|
||||||
|
... MeasurementsFragment
|
||||||
|
}
|
||||||
|
breast_type
|
||||||
|
career_start_year
|
||||||
|
career_end_year
|
||||||
|
tattoos {
|
||||||
|
... BodyModificationFragment
|
||||||
|
}
|
||||||
|
piercings {
|
||||||
|
... BodyModificationFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragment URLFragment on URL {
|
||||||
|
url
|
||||||
|
type
|
||||||
|
}
|
||||||
|
fragment ImageFragment on Image {
|
||||||
|
id
|
||||||
|
url
|
||||||
|
width
|
||||||
|
height
|
||||||
|
}
|
||||||
|
fragment StudioFragment on Studio {
|
||||||
|
name
|
||||||
|
id
|
||||||
|
urls {
|
||||||
|
... URLFragment
|
||||||
|
}
|
||||||
|
images {
|
||||||
|
... ImageFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragment BodyModificationFragment on BodyModification {
|
||||||
|
location
|
||||||
|
description
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
func (c *Client) SearchScene(ctx context.Context, term string, httpRequestOptions ...client.HTTPRequestOption) (*SearchScene, error) {
|
||||||
|
vars := map[string]interface{}{
|
||||||
|
"term": term,
|
||||||
|
}
|
||||||
|
|
||||||
|
var res SearchScene
|
||||||
|
if err := c.Client.Post(ctx, SearchSceneQuery, &res, vars, httpRequestOptions...); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const SubmitFingerprintQuery = `mutation SubmitFingerprint ($input: FingerprintSubmission!) {
|
||||||
|
submitFingerprint(input: $input)
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
func (c *Client) SubmitFingerprint(ctx context.Context, input FingerprintSubmission, httpRequestOptions ...client.HTTPRequestOption) (*SubmitFingerprintPayload, error) {
|
||||||
|
vars := map[string]interface{}{
|
||||||
|
"input": input,
|
||||||
|
}
|
||||||
|
|
||||||
|
var res SubmitFingerprintPayload
|
||||||
|
if err := c.Client.Post(ctx, SubmitFingerprintQuery, &res, vars, httpRequestOptions...); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &res, nil
|
||||||
|
}
|
||||||
1427
pkg/scraper/stashbox/graphql/generated_models.go
Normal file
1427
pkg/scraper/stashbox/graphql/generated_models.go
Normal file
File diff suppressed because it is too large
Load Diff
315
pkg/scraper/stashbox/stash_box.go
Normal file
315
pkg/scraper/stashbox/stash_box.go
Normal file
@@ -0,0 +1,315 @@
|
|||||||
|
package stashbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Yamashou/gqlgenc/client"
|
||||||
|
|
||||||
|
"github.com/stashapp/stash/pkg/logger"
|
||||||
|
"github.com/stashapp/stash/pkg/models"
|
||||||
|
"github.com/stashapp/stash/pkg/scraper/stashbox/graphql"
|
||||||
|
"github.com/stashapp/stash/pkg/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Timeout to get the image. Includes transfer time. May want to make this
|
||||||
|
// configurable at some point.
|
||||||
|
const imageGetTimeout = time.Second * 30
|
||||||
|
|
||||||
|
// Client represents the client interface to a stash-box server instance.
|
||||||
|
type Client struct {
|
||||||
|
client *graphql.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient returns a new instance of a stash-box client.
|
||||||
|
func NewClient(box models.StashBox) *Client {
|
||||||
|
authHeader := func(req *http.Request) {
|
||||||
|
req.Header.Set("ApiKey", box.APIKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
client := &graphql.Client{
|
||||||
|
Client: client.NewClient(http.DefaultClient, box.Endpoint, authHeader),
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Client{
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryStashBoxScene queries stash-box for scenes using a query string.
|
||||||
|
func (c Client) QueryStashBoxScene(queryStr string) ([]*models.ScrapedScene, error) {
|
||||||
|
scenes, err := c.client.SearchScene(context.TODO(), queryStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sceneFragments := scenes.SearchScene
|
||||||
|
|
||||||
|
var ret []*models.ScrapedScene
|
||||||
|
for _, s := range sceneFragments {
|
||||||
|
ss, err := sceneFragmentToScrapedScene(s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ret = append(ret, ss)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindStashBoxScenesByFingerprints queries stash-box for scenes using every
|
||||||
|
// scene's MD5 checksum and/or oshash.
|
||||||
|
func (c Client) FindStashBoxScenesByFingerprints(sceneIDs []string) ([]*models.ScrapedScene, error) {
|
||||||
|
qb := models.NewSceneQueryBuilder()
|
||||||
|
|
||||||
|
var fingerprints []string
|
||||||
|
|
||||||
|
for _, sceneID := range sceneIDs {
|
||||||
|
idInt, _ := strconv.Atoi(sceneID)
|
||||||
|
scene, err := qb.Find(idInt)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if scene == nil {
|
||||||
|
return nil, fmt.Errorf("scene with id %d not found", idInt)
|
||||||
|
}
|
||||||
|
|
||||||
|
if scene.Checksum.Valid {
|
||||||
|
fingerprints = append(fingerprints, scene.Checksum.String)
|
||||||
|
}
|
||||||
|
|
||||||
|
if scene.OSHash.Valid {
|
||||||
|
fingerprints = append(fingerprints, scene.OSHash.String)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.findStashBoxScenesByFingerprints(fingerprints)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Client) findStashBoxScenesByFingerprints(fingerprints []string) ([]*models.ScrapedScene, error) {
|
||||||
|
scenes, err := c.client.FindScenesByFingerprints(context.TODO(), fingerprints)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sceneFragments := scenes.FindScenesByFingerprints
|
||||||
|
|
||||||
|
var ret []*models.ScrapedScene
|
||||||
|
for _, s := range sceneFragments {
|
||||||
|
ss, err := sceneFragmentToScrapedScene(s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ret = append(ret, ss)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func findURL(urls []*graphql.URLFragment, urlType string) *string {
|
||||||
|
for _, u := range urls {
|
||||||
|
if u.Type == urlType {
|
||||||
|
ret := u.URL
|
||||||
|
return &ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func enumToStringPtr(e fmt.Stringer) *string {
|
||||||
|
if e != nil {
|
||||||
|
ret := e.String()
|
||||||
|
return &ret
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatMeasurements(m graphql.MeasurementsFragment) *string {
|
||||||
|
if m.BandSize != nil && m.CupSize != nil && m.Hip != nil && m.Waist != nil {
|
||||||
|
ret := fmt.Sprintf("%d%s-%d-%d", *m.BandSize, *m.CupSize, *m.Waist, *m.Hip)
|
||||||
|
return &ret
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatCareerLength(start, end *int) *string {
|
||||||
|
if start == nil && end == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret string
|
||||||
|
if end == nil {
|
||||||
|
ret = fmt.Sprintf("%d -", *start)
|
||||||
|
} else {
|
||||||
|
ret = fmt.Sprintf("%d - %d", *start, *end)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatBodyModifications(m []*graphql.BodyModificationFragment) *string {
|
||||||
|
if len(m) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var retSlice []string
|
||||||
|
for _, f := range m {
|
||||||
|
if f.Description == nil {
|
||||||
|
retSlice = append(retSlice, f.Location)
|
||||||
|
} else {
|
||||||
|
retSlice = append(retSlice, fmt.Sprintf("%s, %s", f.Location, *f.Description))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := strings.Join(retSlice, "; ")
|
||||||
|
return &ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func fetchImage(url string) (*string, error) {
|
||||||
|
client := &http.Client{
|
||||||
|
Timeout: imageGetTimeout,
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine the image type and set the base64 type
|
||||||
|
contentType := resp.Header.Get("Content-Type")
|
||||||
|
if contentType == "" {
|
||||||
|
contentType = http.DetectContentType(body)
|
||||||
|
}
|
||||||
|
|
||||||
|
img := "data:" + contentType + ";base64," + utils.GetBase64StringFromData(body)
|
||||||
|
return &img, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func performerFragmentToScrapedScenePerformer(p graphql.PerformerFragment) *models.ScrapedScenePerformer {
|
||||||
|
sp := &models.ScrapedScenePerformer{
|
||||||
|
Name: p.Name,
|
||||||
|
Country: p.Country,
|
||||||
|
Measurements: formatMeasurements(p.Measurements),
|
||||||
|
CareerLength: formatCareerLength(p.CareerStartYear, p.CareerEndYear),
|
||||||
|
Tattoos: formatBodyModifications(p.Tattoos),
|
||||||
|
Piercings: formatBodyModifications(p.Piercings),
|
||||||
|
Twitter: findURL(p.Urls, "TWITTER"),
|
||||||
|
// TODO - Image - should be returned as a set of URLs. Will need a
|
||||||
|
// graphql schema change to accommodate this. Leave off for now.
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.Height != nil {
|
||||||
|
hs := strconv.Itoa(*p.Height)
|
||||||
|
sp.Height = &hs
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.Birthdate != nil {
|
||||||
|
b := p.Birthdate.Date
|
||||||
|
sp.Birthdate = &b
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.Gender != nil {
|
||||||
|
sp.Gender = enumToStringPtr(p.Gender)
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.Ethnicity != nil {
|
||||||
|
sp.Ethnicity = enumToStringPtr(p.Ethnicity)
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.EyeColor != nil {
|
||||||
|
sp.EyeColor = enumToStringPtr(p.EyeColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.BreastType != nil {
|
||||||
|
sp.FakeTits = enumToStringPtr(p.BreastType)
|
||||||
|
}
|
||||||
|
|
||||||
|
return sp
|
||||||
|
}
|
||||||
|
|
||||||
|
func getFirstImage(images []*graphql.ImageFragment) *string {
|
||||||
|
ret, err := fetchImage(images[0].URL)
|
||||||
|
if err != nil {
|
||||||
|
logger.Warnf("Error fetching image %s: %s", images[0].URL, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func sceneFragmentToScrapedScene(s *graphql.SceneFragment) (*models.ScrapedScene, error) {
|
||||||
|
ss := &models.ScrapedScene{
|
||||||
|
Title: s.Title,
|
||||||
|
Date: s.Date,
|
||||||
|
Details: s.Details,
|
||||||
|
URL: findURL(s.Urls, "STUDIO"),
|
||||||
|
// Image
|
||||||
|
// stash_id
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(s.Images) > 0 {
|
||||||
|
// TODO - #454 code sorts images by aspect ratio according to a wanted
|
||||||
|
// orientation. I'm just grabbing the first for now
|
||||||
|
ss.Image = getFirstImage(s.Images)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.Studio != nil {
|
||||||
|
ss.Studio = &models.ScrapedSceneStudio{
|
||||||
|
Name: s.Studio.Name,
|
||||||
|
URL: findURL(s.Studio.Urls, "HOME"),
|
||||||
|
}
|
||||||
|
|
||||||
|
err := models.MatchScrapedSceneStudio(ss.Studio)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range s.Performers {
|
||||||
|
sp := performerFragmentToScrapedScenePerformer(p.Performer)
|
||||||
|
|
||||||
|
err := models.MatchScrapedScenePerformer(sp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ss.Performers = append(ss.Performers, sp)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, t := range s.Tags {
|
||||||
|
st := &models.ScrapedSceneTag{
|
||||||
|
Name: t.Name,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := models.MatchScrapedSceneTag(st)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ss.Tags = append(ss.Tags, st)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ss, nil
|
||||||
|
}
|
||||||
1
tools.go
1
tools.go
@@ -4,5 +4,6 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
_ "github.com/99designs/gqlgen"
|
_ "github.com/99designs/gqlgen"
|
||||||
|
_ "github.com/Yamashou/gqlgenc"
|
||||||
_ "github.com/vektra/mockery/v2"
|
_ "github.com/vektra/mockery/v2"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import {
|
|||||||
useListSceneScrapers,
|
useListSceneScrapers,
|
||||||
useSceneUpdate,
|
useSceneUpdate,
|
||||||
mutateReloadScrapers,
|
mutateReloadScrapers,
|
||||||
|
useConfiguration,
|
||||||
|
queryStashBoxScene,
|
||||||
} from "src/core/StashService";
|
} from "src/core/StashService";
|
||||||
import {
|
import {
|
||||||
PerformerSelect,
|
PerformerSelect,
|
||||||
@@ -62,6 +64,8 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
|
|||||||
|
|
||||||
const [coverImagePreview, setCoverImagePreview] = useState<string>();
|
const [coverImagePreview, setCoverImagePreview] = useState<string>();
|
||||||
|
|
||||||
|
const stashConfig = useConfiguration();
|
||||||
|
|
||||||
// Network state
|
// Network state
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
|
||||||
@@ -117,7 +121,7 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
setQueryableScrapers(newQueryableScrapers);
|
setQueryableScrapers(newQueryableScrapers);
|
||||||
}, [Scrapers]);
|
}, [Scrapers, stashConfig]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let changed = false;
|
let changed = false;
|
||||||
@@ -251,11 +255,40 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
|
|||||||
ImageUtils.onImageChange(event, onImageLoad);
|
ImageUtils.onImageChange(event, onImageLoad);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function onScrapeStashBoxClicked(stashBoxIndex: number) {
|
||||||
|
setIsLoading(true);
|
||||||
|
try {
|
||||||
|
const result = await queryStashBoxScene(stashBoxIndex, props.scene.id);
|
||||||
|
if (!result.data || !result.data.queryStashBoxScene) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.data.queryStashBoxScene.length > 0) {
|
||||||
|
setScrapedScene(result.data.queryStashBoxScene[0]);
|
||||||
|
} else {
|
||||||
|
Toast.success({
|
||||||
|
content: "No scenes found",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
Toast.error(e);
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// function onStashBoxQueryClicked(/* stashBoxIndex: number */) {
|
||||||
|
// TODO
|
||||||
|
// }
|
||||||
|
|
||||||
async function onScrapeClicked(scraper: GQL.Scraper) {
|
async function onScrapeClicked(scraper: GQL.Scraper) {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
try {
|
||||||
const result = await queryScrapeScene(scraper.id, getSceneInput());
|
const result = await queryScrapeScene(scraper.id, getSceneInput());
|
||||||
if (!result.data || !result.data.scrapeScene) {
|
if (!result.data || !result.data.scrapeScene) {
|
||||||
|
Toast.success({
|
||||||
|
content: "No scenes found",
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setScrapedScene(result.data.scrapeScene);
|
setScrapedScene(result.data.scrapeScene);
|
||||||
@@ -309,8 +342,23 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderScraperMenu() {
|
function renderScraperMenu() {
|
||||||
|
const stashBoxes = stashConfig.data?.configuration.general.stashBoxes ?? [];
|
||||||
|
|
||||||
|
// TODO - change name based on stashbox configuration
|
||||||
return (
|
return (
|
||||||
<DropdownButton id="scene-scrape" title="Scrape with...">
|
<DropdownButton
|
||||||
|
className="d-inline-block"
|
||||||
|
id="scene-scrape"
|
||||||
|
title="Scrape with..."
|
||||||
|
>
|
||||||
|
{stashBoxes.map((s, index) => (
|
||||||
|
<Dropdown.Item
|
||||||
|
key={s.endpoint}
|
||||||
|
onClick={() => onScrapeStashBoxClicked(index)}
|
||||||
|
>
|
||||||
|
stash-box
|
||||||
|
</Dropdown.Item>
|
||||||
|
))}
|
||||||
{queryableScrapers.map((s) => (
|
{queryableScrapers.map((s) => (
|
||||||
<Dropdown.Item key={s.name} onClick={() => onScrapeClicked(s)}>
|
<Dropdown.Item key={s.name} onClick={() => onScrapeClicked(s)}>
|
||||||
{s.name}
|
{s.name}
|
||||||
@@ -326,6 +374,44 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function maybeRenderStashboxQueryButton() {
|
||||||
|
// const stashBoxes = stashConfig.data?.configuration.general.stashBoxes ?? [];
|
||||||
|
// if (stashBoxes.length === 0) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// TODO - hide this button for now, with the view to add it when we get
|
||||||
|
// the query dialog going
|
||||||
|
// if (stashBoxes.length === 1) {
|
||||||
|
// return (
|
||||||
|
// <Button
|
||||||
|
// className="mr-1"
|
||||||
|
// onClick={() => onStashBoxQueryClicked(0)}
|
||||||
|
// title="Query"
|
||||||
|
// >
|
||||||
|
// <Icon className="fa-fw" icon="search" />
|
||||||
|
// </Button>
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
// // TODO - change name based on stashbox configuration
|
||||||
|
// return (
|
||||||
|
// <Dropdown className="d-inline-block mr-1">
|
||||||
|
// <Dropdown.Toggle id="stashbox-query-dropdown">
|
||||||
|
// <Icon className="fa-fw" icon="search" />
|
||||||
|
// </Dropdown.Toggle>
|
||||||
|
// <Dropdown.Menu>
|
||||||
|
// {stashBoxes.map((s, index) => (
|
||||||
|
// <Dropdown.Item
|
||||||
|
// key={s.endpoint}
|
||||||
|
// onClick={() => onStashBoxQueryClicked(index)}
|
||||||
|
// >
|
||||||
|
// stash-box
|
||||||
|
// </Dropdown.Item>
|
||||||
|
// ))}
|
||||||
|
// </Dropdown.Menu>
|
||||||
|
// </Dropdown>
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
|
||||||
function urlScrapable(scrapedUrl: string): boolean {
|
function urlScrapable(scrapedUrl: string): boolean {
|
||||||
return (Scrapers?.data?.listSceneScrapers ?? []).some((s) =>
|
return (Scrapers?.data?.listSceneScrapers ?? []).some((s) =>
|
||||||
(s?.scene?.urls ?? []).some((u) => scrapedUrl.includes(u))
|
(s?.scene?.urls ?? []).some((u) => scrapedUrl.includes(u))
|
||||||
@@ -432,7 +518,7 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
|
|||||||
<div id="scene-edit-details">
|
<div id="scene-edit-details">
|
||||||
{maybeRenderScrapeDialog()}
|
{maybeRenderScrapeDialog()}
|
||||||
<div className="form-container row px-3 pt-3">
|
<div className="form-container row px-3 pt-3">
|
||||||
<div className="col edit-buttons mb-3 pl-0">
|
<div className="col-6 edit-buttons mb-3 pl-0">
|
||||||
<Button className="edit-button" variant="primary" onClick={onSave}>
|
<Button className="edit-button" variant="primary" onClick={onSave}>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
@@ -444,7 +530,10 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
|
|||||||
Delete
|
Delete
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
<Col xs={6} className="text-right">
|
||||||
|
{maybeRenderStashboxQueryButton()}
|
||||||
{renderScraperMenu()}
|
{renderScraperMenu()}
|
||||||
|
</Col>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-container row px-3">
|
<div className="form-container row px-3">
|
||||||
<div className="col-12 col-lg-6 col-xl-12">
|
<div className="col-12 col-lg-6 col-xl-12">
|
||||||
|
|||||||
@@ -498,6 +498,17 @@ export const queryScrapeScene = (
|
|||||||
fetchPolicy: "network-only",
|
fetchPolicy: "network-only",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const queryStashBoxScene = (stashBoxIndex: number, sceneID: string) =>
|
||||||
|
client.query<GQL.QueryStashBoxSceneQuery>({
|
||||||
|
query: GQL.QueryStashBoxSceneDocument,
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
stash_box_index: stashBoxIndex,
|
||||||
|
scene_ids: [sceneID],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export const mutateReloadScrapers = () =>
|
export const mutateReloadScrapers = () =>
|
||||||
client.mutate<GQL.ReloadScrapersMutation>({
|
client.mutate<GQL.ReloadScrapersMutation>({
|
||||||
mutation: GQL.ReloadScrapersDocument,
|
mutation: GQL.ReloadScrapersDocument,
|
||||||
|
|||||||
2
vendor/github.com/99designs/gqlgen/.gitignore
generated
vendored
2
vendor/github.com/99designs/gqlgen/.gitignore
generated
vendored
@@ -4,6 +4,8 @@
|
|||||||
/integration/node_modules
|
/integration/node_modules
|
||||||
/integration/schema-fetched.graphql
|
/integration/schema-fetched.graphql
|
||||||
/example/chat/package-lock.json
|
/example/chat/package-lock.json
|
||||||
|
/example/federation/package-lock.json
|
||||||
|
/example/federation/node_modules
|
||||||
/codegen/gen
|
/codegen/gen
|
||||||
/gen
|
/gen
|
||||||
|
|
||||||
|
|||||||
36
vendor/github.com/99designs/gqlgen/.golangci.yml
generated
vendored
36
vendor/github.com/99designs/gqlgen/.golangci.yml
generated
vendored
@@ -1,3 +1,39 @@
|
|||||||
|
run:
|
||||||
|
tests: true
|
||||||
|
skip-dirs:
|
||||||
|
- bin
|
||||||
|
|
||||||
linters-settings:
|
linters-settings:
|
||||||
errcheck:
|
errcheck:
|
||||||
ignore: fmt:.*,[rR]ead|[wW]rite|[cC]lose,io:Copy
|
ignore: fmt:.*,[rR]ead|[wW]rite|[cC]lose,io:Copy
|
||||||
|
|
||||||
|
linters:
|
||||||
|
disable-all: true
|
||||||
|
enable:
|
||||||
|
- bodyclose
|
||||||
|
- deadcode
|
||||||
|
- depguard
|
||||||
|
- dupl
|
||||||
|
- errcheck
|
||||||
|
- gocritic
|
||||||
|
- gofmt
|
||||||
|
- goimports
|
||||||
|
- gosimple
|
||||||
|
- govet
|
||||||
|
- ineffassign
|
||||||
|
- interfacer
|
||||||
|
- misspell
|
||||||
|
- nakedret
|
||||||
|
- prealloc
|
||||||
|
- staticcheck
|
||||||
|
- structcheck
|
||||||
|
- unconvert
|
||||||
|
- unused
|
||||||
|
- varcheck
|
||||||
|
|
||||||
|
issues:
|
||||||
|
exclude-rules:
|
||||||
|
# Exclude some linters from running on tests files.
|
||||||
|
- path: _test\.go
|
||||||
|
linters:
|
||||||
|
- dupl
|
||||||
|
|||||||
2
vendor/github.com/99designs/gqlgen/LICENSE
generated
vendored
2
vendor/github.com/99designs/gqlgen/LICENSE
generated
vendored
@@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2018 Adam Scarr
|
Copyright (c) 2020 gqlgen authors
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
108
vendor/github.com/99designs/gqlgen/README.md
generated
vendored
108
vendor/github.com/99designs/gqlgen/README.md
generated
vendored
@@ -1,20 +1,24 @@
|
|||||||
# gqlgen [](https://circleci.com/gh/99designs/gqlgen) [](http://gqlgen.com/)
|
# gqlgen [](https://github.com/99designs/gqlgen/actions) [](http://gqlgen.com/) [](https://godoc.org/github.com/99designs/gqlgen)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
## What is gqlgen?
|
## What is gqlgen?
|
||||||
|
|
||||||
[gqlgen](https://github.com/99designs/gqlgen) is a Go library for building GraphQL servers without any fuss. gqlgen is:
|
[gqlgen](https://github.com/99designs/gqlgen) is a Go library for building GraphQL servers without any fuss.<br/>
|
||||||
|
|
||||||
- **Schema first** — 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/).
|
||||||
- **Type safe** — You should never see `map[string]interface{}` here.
|
- **gqlgen priortizes Type safety** — You should never see `map[string]interface{}` here.
|
||||||
- **Codegen** — Let us generate the boring bits, so you can build your app quickly.
|
- **gqlgen enables Codegen** — We generate the boring bits, so you can focus on building your app quickly.
|
||||||
|
|
||||||
[Feature Comparison](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
|
## Getting Started
|
||||||
|
- To install gqlgen run the comand `go get github.com/99designs/gqlgen` in your project directory.<br/>
|
||||||
|
- You could initialize a new project using the recommended folder structure by running this command `go run github.com/99designs/gqlgen init`.
|
||||||
|
|
||||||
First work your way through the [Getting Started](https://gqlgen.com/getting-started/) tutorial.
|
You could find a more comprehensive guide to help you get started [here](https://gqlgen.com/getting-started/).<br/>
|
||||||
|
We also have a couple of real-world [examples](https://github.com/99designs/gqlgen/tree/master/example) that show how to GraphQL applicatons with **gqlgen** seamlessly,
|
||||||
If you can't find what your looking for, look at our [examples](https://github.com/99designs/gqlgen/tree/master/example) for example usage of gqlgen.
|
You can see these [examples](https://github.com/99designs/gqlgen/tree/master/example) here or visit [godoc](https://godoc.org/github.com/99designs/gqlgen).
|
||||||
|
|
||||||
## Reporting Issues
|
## Reporting Issues
|
||||||
|
|
||||||
@@ -22,10 +26,88 @@ If you think you've found a bug, or something isn't behaving the way you think i
|
|||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Read our [Contribution Guidelines](https://github.com/99designs/gqlgen/blob/master/CONTRIBUTING.md) for information on how you can help out gqlgen.
|
We welcome contributions, Read our [Contribution Guidelines](https://github.com/99designs/gqlgen/blob/master/CONTRIBUTING.md) to learn more about contributing to **gqlgen**
|
||||||
|
## Frequently asked questions
|
||||||
|
|
||||||
|
### How do I prevent fetching child objects that might not be used?
|
||||||
|
|
||||||
|
When you have nested or recursive schema like this:
|
||||||
|
|
||||||
|
```graphql
|
||||||
|
type User {
|
||||||
|
id: ID!
|
||||||
|
name: String!
|
||||||
|
friends: [User!]!
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You need to tell gqlgen that it should only fetch friends if the user requested it. There are two ways to do this;
|
||||||
|
|
||||||
|
- #### Using Custom Models
|
||||||
|
|
||||||
|
Write a custom model that omits the friends field:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type User struct {
|
||||||
|
ID int
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
And reference the model in `gqlgen.yml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# gqlgen.yml
|
||||||
|
models:
|
||||||
|
User:
|
||||||
|
model: github.com/you/pkg/model.User # go import path to the User struct above
|
||||||
|
```
|
||||||
|
|
||||||
|
- #### Using Explicit Resolvers
|
||||||
|
|
||||||
|
If you want to Keep using the generated model, mark the field as requiring a resolver explicitly in `gqlgen.yml` like this:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# gqlgen.yml
|
||||||
|
models:
|
||||||
|
User:
|
||||||
|
fields:
|
||||||
|
friends:
|
||||||
|
resolver: true # force a resolver to be generated
|
||||||
|
```
|
||||||
|
|
||||||
|
After doing either of the above and running generate we will need to provide a resolver for friends:
|
||||||
|
|
||||||
|
```go
|
||||||
|
func (r *userResolver) Friends(ctx context.Context, obj *User) ([]*User, error) {
|
||||||
|
// select * from user where friendid = obj.ID
|
||||||
|
return friends, nil
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Can I change the type of the ID from type String to Type Int?
|
||||||
|
|
||||||
|
Yes! You can by remapping it in config as seen below:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
models:
|
||||||
|
ID: # The GraphQL type ID is backed by
|
||||||
|
model:
|
||||||
|
- github.com/99designs/gqlgen/graphql.IntID # An go integer
|
||||||
|
- github.com/99designs/gqlgen/graphql.ID # or a go string
|
||||||
|
```
|
||||||
|
|
||||||
|
This means gqlgen will be able to automatically bind to strings or ints for models you have written yourself, but the
|
||||||
|
first model in this list is used as the default type and it will always be used when:
|
||||||
|
|
||||||
|
- Generating models based on schema
|
||||||
|
- As arguments in resolvers
|
||||||
|
|
||||||
|
There isnt any way around this, gqlgen has no way to know what you want in a given context.
|
||||||
|
|
||||||
## Other Resources
|
## Other Resources
|
||||||
|
|
||||||
- [Christopher Biscardi @ Gophercon UK 2018](https://youtu.be/FdURVezcdcw)
|
- [Christopher Biscardi @ Gophercon UK 2018](https://youtu.be/FdURVezcdcw)
|
||||||
- [Introducing gqlgen: a GraphQL Server Generator for Go](https://99designs.com.au/blog/engineering/gqlgen-a-graphql-server-generator-for-go/)
|
- [Introducing gqlgen: a GraphQL Server Generator for Go](https://99designs.com.au/blog/engineering/gqlgen-a-graphql-server-generator-for-go/)
|
||||||
- [GraphQL workshop for Golang developers by Iván Corrales Solera](https://graphql-go.wesovilabs.com)
|
- [Dive into GraphQL by Iván Corrales Solera](https://medium.com/@ivan.corrales.solera/dive-into-graphql-9bfedf22e1a)
|
||||||
|
- [Sample Project built on gqlgen with Postgres by Oleg Shalygin](https://github.com/oshalygin/gqlgen-pg-todo-example)
|
||||||
|
|||||||
59
vendor/github.com/99designs/gqlgen/api/generate.go
generated
vendored
59
vendor/github.com/99designs/gqlgen/api/generate.go
generated
vendored
@@ -6,25 +6,60 @@ import (
|
|||||||
"github.com/99designs/gqlgen/codegen"
|
"github.com/99designs/gqlgen/codegen"
|
||||||
"github.com/99designs/gqlgen/codegen/config"
|
"github.com/99designs/gqlgen/codegen/config"
|
||||||
"github.com/99designs/gqlgen/plugin"
|
"github.com/99designs/gqlgen/plugin"
|
||||||
|
"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"
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/tools/go/packages"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Generate(cfg *config.Config, option ...Option) error {
|
func Generate(cfg *config.Config, option ...Option) error {
|
||||||
_ = syscall.Unlink(cfg.Exec.Filename)
|
_ = syscall.Unlink(cfg.Exec.Filename)
|
||||||
|
if cfg.Model.IsDefined() {
|
||||||
_ = syscall.Unlink(cfg.Model.Filename)
|
_ = syscall.Unlink(cfg.Model.Filename)
|
||||||
|
}
|
||||||
|
|
||||||
plugins := []plugin.Plugin{
|
plugins := []plugin.Plugin{}
|
||||||
modelgen.New(),
|
if cfg.Model.IsDefined() {
|
||||||
resolvergen.New(),
|
plugins = append(plugins, modelgen.New())
|
||||||
|
}
|
||||||
|
plugins = append(plugins, resolvergen.New())
|
||||||
|
if cfg.Federation.IsDefined() {
|
||||||
|
plugins = append([]plugin.Plugin{federation.New()}, plugins...)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, o := range option {
|
for _, o := range option {
|
||||||
o(cfg, &plugins)
|
o(cfg, &plugins)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, p := range plugins {
|
||||||
|
if inj, ok := p.(plugin.EarlySourceInjector); ok {
|
||||||
|
if s := inj.InjectSourceEarly(); s != nil {
|
||||||
|
cfg.Sources = append(cfg.Sources, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cfg.LoadSchema(); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to load schema")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range plugins {
|
||||||
|
if inj, ok := p.(plugin.LateSourceInjector); ok {
|
||||||
|
if s := inj.InjectSourceLate(cfg.Schema); s != nil {
|
||||||
|
cfg.Sources = append(cfg.Sources, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadSchema again now we have everything
|
||||||
|
if err := cfg.LoadSchema(); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to load schema")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cfg.Init(); err != nil {
|
||||||
|
return errors.Wrap(err, "generating core failed")
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
@@ -36,7 +71,7 @@ func Generate(cfg *config.Config, option ...Option) error {
|
|||||||
// 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 failed")
|
return errors.Wrap(err, "merging type systems failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = codegen.GenerateCode(data); err != nil {
|
if err = codegen.GenerateCode(data); err != nil {
|
||||||
@@ -52,9 +87,15 @@ func Generate(cfg *config.Config, option ...Option) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = codegen.GenerateCode(data); err != nil {
|
||||||
|
return errors.Wrap(err, "generating core failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !cfg.SkipValidation {
|
||||||
if err := validate(cfg); err != nil {
|
if err := validate(cfg); err != nil {
|
||||||
return errors.Wrap(err, "validation failed")
|
return errors.Wrap(err, "validation failed")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -68,9 +109,11 @@ func validate(cfg *config.Config) error {
|
|||||||
if cfg.Resolver.IsDefined() {
|
if cfg.Resolver.IsDefined() {
|
||||||
roots = append(roots, cfg.Resolver.ImportPath())
|
roots = append(roots, cfg.Resolver.ImportPath())
|
||||||
}
|
}
|
||||||
_, err := packages.Load(&packages.Config{Mode: packages.LoadTypes | packages.LoadSyntax}, roots...)
|
|
||||||
if err != nil {
|
cfg.Packages.LoadAll(roots...)
|
||||||
return errors.Wrap(err, "validation failed")
|
errs := cfg.Packages.Errors()
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return errs
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
32
vendor/github.com/99designs/gqlgen/appveyor.yml
generated
vendored
32
vendor/github.com/99designs/gqlgen/appveyor.yml
generated
vendored
@@ -1,32 +0,0 @@
|
|||||||
version: "{build}"
|
|
||||||
|
|
||||||
# Source Config
|
|
||||||
|
|
||||||
skip_branch_with_pr: true
|
|
||||||
clone_folder: c:\projects\gqlgen
|
|
||||||
|
|
||||||
# Build host
|
|
||||||
|
|
||||||
environment:
|
|
||||||
GOPATH: c:\gopath
|
|
||||||
GOVERSION: 1.11.5
|
|
||||||
PATH: '%PATH%;c:\gopath\bin'
|
|
||||||
|
|
||||||
init:
|
|
||||||
- git config --global core.autocrlf input
|
|
||||||
|
|
||||||
# Build
|
|
||||||
|
|
||||||
install:
|
|
||||||
# Install the specific Go version.
|
|
||||||
- rmdir c:\go /s /q
|
|
||||||
- appveyor DownloadFile https://storage.googleapis.com/golang/go%GOVERSION%.windows-amd64.msi
|
|
||||||
- msiexec /i go%GOVERSION%.windows-amd64.msi /q
|
|
||||||
- go version
|
|
||||||
|
|
||||||
build: false
|
|
||||||
deploy: false
|
|
||||||
|
|
||||||
test_script:
|
|
||||||
- go generate ./...
|
|
||||||
- go test -timeout 20m ./...
|
|
||||||
4
vendor/github.com/99designs/gqlgen/cmd/ambient.go
generated
vendored
4
vendor/github.com/99designs/gqlgen/cmd/ambient.go
generated
vendored
@@ -5,6 +5,6 @@ import (
|
|||||||
// don't prune unused code for us. Both lists should be kept in sync.
|
// don't prune unused code for us. Both lists should be kept in sync.
|
||||||
_ "github.com/99designs/gqlgen/graphql"
|
_ "github.com/99designs/gqlgen/graphql"
|
||||||
_ "github.com/99designs/gqlgen/graphql/introspection"
|
_ "github.com/99designs/gqlgen/graphql/introspection"
|
||||||
_ "github.com/vektah/gqlparser"
|
_ "github.com/vektah/gqlparser/v2"
|
||||||
_ "github.com/vektah/gqlparser/ast"
|
_ "github.com/vektah/gqlparser/v2/ast"
|
||||||
)
|
)
|
||||||
|
|||||||
27
vendor/github.com/99designs/gqlgen/cmd/gen.go
generated
vendored
27
vendor/github.com/99designs/gqlgen/cmd/gen.go
generated
vendored
@@ -1,44 +1,43 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/api"
|
"github.com/99designs/gqlgen/api"
|
||||||
"github.com/99designs/gqlgen/codegen/config"
|
"github.com/99designs/gqlgen/codegen/config"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var genCmd = cli.Command{
|
var genCmd = &cli.Command{
|
||||||
Name: "generate",
|
Name: "generate",
|
||||||
Usage: "generate a graphql server based on schema",
|
Usage: "generate a graphql server based on schema",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
cli.BoolFlag{Name: "verbose, v", Usage: "show logs"},
|
&cli.BoolFlag{Name: "verbose, v", Usage: "show logs"},
|
||||||
cli.StringFlag{Name: "config, c", Usage: "the config filename"},
|
&cli.StringFlag{Name: "config, c", Usage: "the config filename"},
|
||||||
},
|
},
|
||||||
Action: func(ctx *cli.Context) {
|
Action: func(ctx *cli.Context) error {
|
||||||
var cfg *config.Config
|
var cfg *config.Config
|
||||||
var err error
|
var err error
|
||||||
if configFilename := ctx.String("config"); configFilename != "" {
|
if configFilename := ctx.String("config"); configFilename != "" {
|
||||||
cfg, err = config.LoadConfig(configFilename)
|
cfg, err = config.LoadConfig(configFilename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err.Error())
|
return err
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cfg, err = config.LoadConfigFromDefaultLocations()
|
cfg, err = config.LoadConfigFromDefaultLocations()
|
||||||
if os.IsNotExist(errors.Cause(err)) {
|
if os.IsNotExist(errors.Cause(err)) {
|
||||||
cfg = config.DefaultConfig()
|
cfg, err = config.LoadDefaultConfig()
|
||||||
} else if err != nil {
|
}
|
||||||
fmt.Fprintln(os.Stderr, err.Error())
|
|
||||||
os.Exit(2)
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = api.Generate(cfg); err != nil {
|
if err = api.Generate(cfg); err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err.Error())
|
return err
|
||||||
os.Exit(3)
|
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
183
vendor/github.com/99designs/gqlgen/cmd/init.go
generated
vendored
183
vendor/github.com/99designs/gqlgen/cmd/init.go
generated
vendored
@@ -3,28 +3,79 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"html/template"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/api"
|
"github.com/99designs/gqlgen/api"
|
||||||
"github.com/99designs/gqlgen/plugin/servergen"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/codegen/config"
|
"github.com/99designs/gqlgen/codegen/config"
|
||||||
"github.com/pkg/errors"
|
"github.com/99designs/gqlgen/internal/code"
|
||||||
"github.com/urfave/cli"
|
"github.com/99designs/gqlgen/plugin/servergen"
|
||||||
yaml "gopkg.in/yaml.v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var configComment = `
|
var configTemplate = template.Must(template.New("name").Parse(
|
||||||
# .gqlgen.yml example
|
`# Where are all the schema files located? globs are supported eg src/**/*.graphqls
|
||||||
#
|
schema:
|
||||||
# Refer to https://gqlgen.com/config/
|
- graph/*.graphqls
|
||||||
# for detailed .gqlgen.yml documentation.
|
|
||||||
`
|
|
||||||
|
|
||||||
var schemaDefault = `
|
# Where should the generated server code go?
|
||||||
# GraphQL schema example
|
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/
|
# https://gqlgen.com/getting-started/
|
||||||
|
|
||||||
@@ -54,91 +105,95 @@ type Mutation {
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
var initCmd = cli.Command{
|
var initCmd = &cli.Command{
|
||||||
Name: "init",
|
Name: "init",
|
||||||
Usage: "create a new gqlgen project",
|
Usage: "create a new gqlgen project",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
cli.BoolFlag{Name: "verbose, v", Usage: "show logs"},
|
&cli.BoolFlag{Name: "verbose, v", Usage: "show logs"},
|
||||||
cli.StringFlag{Name: "config, c", Usage: "the config filename"},
|
&cli.StringFlag{Name: "config, c", Usage: "the config filename"},
|
||||||
cli.StringFlag{Name: "server", Usage: "where to write the server stub to", Value: "server/server.go"},
|
&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: "schema.graphql"},
|
&cli.StringFlag{Name: "schema", Usage: "where to write the schema stub to", Value: "graph/schema.graphqls"},
|
||||||
},
|
},
|
||||||
Action: func(ctx *cli.Context) {
|
Action: func(ctx *cli.Context) error {
|
||||||
initSchema(ctx.String("schema"))
|
configFilename := ctx.String("config")
|
||||||
config := initConfig(ctx)
|
serverFilename := ctx.String("server")
|
||||||
|
|
||||||
GenerateGraphServer(config, 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(cfg *config.Config, serverFilename string) {
|
func GenerateGraphServer(serverFilename string) {
|
||||||
err := api.Generate(cfg, api.AddPlugin(servergen.New(serverFilename)))
|
cfg, err := config.LoadConfigFromDefaultLocations()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err.Error())
|
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)
|
fmt.Fprintf(os.Stdout, "Exec \"go run ./%s\" to start GraphQL server\n", serverFilename)
|
||||||
}
|
}
|
||||||
|
|
||||||
func initConfig(ctx *cli.Context) *config.Config {
|
func configExists(configFilename string) bool {
|
||||||
var cfg *config.Config
|
var cfg *config.Config
|
||||||
var err error
|
|
||||||
configFilename := ctx.String("config")
|
|
||||||
if configFilename != "" {
|
if configFilename != "" {
|
||||||
cfg, err = config.LoadConfig(configFilename)
|
cfg, _ = config.LoadConfig(configFilename)
|
||||||
} else {
|
} else {
|
||||||
cfg, err = config.LoadConfigFromDefaultLocations()
|
cfg, _ = config.LoadConfigFromDefaultLocations()
|
||||||
}
|
|
||||||
|
|
||||||
if cfg != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "init failed: a configuration file already exists\n")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !os.IsNotExist(errors.Cause(err)) {
|
|
||||||
fmt.Fprintln(os.Stderr, err.Error())
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
return cfg != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func initConfig(configFilename string, pkgName string) error {
|
||||||
if configFilename == "" {
|
if configFilename == "" {
|
||||||
configFilename = "gqlgen.yml"
|
configFilename = "gqlgen.yml"
|
||||||
}
|
}
|
||||||
cfg = config.DefaultConfig()
|
|
||||||
|
|
||||||
cfg.Resolver = config.PackageConfig{
|
if err := os.MkdirAll(filepath.Dir(configFilename), 0755); err != nil {
|
||||||
Filename: "resolver.go",
|
return fmt.Errorf("unable to create config dir: " + err.Error())
|
||||||
Type: "Resolver",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.WriteString(strings.TrimSpace(configComment))
|
if err := configTemplate.Execute(&buf, pkgName); err != nil {
|
||||||
buf.WriteString("\n\n")
|
panic(err)
|
||||||
var b []byte
|
|
||||||
b, err = yaml.Marshal(cfg)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, "unable to marshal yaml: "+err.Error())
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
buf.Write(b)
|
|
||||||
|
|
||||||
err = ioutil.WriteFile(configFilename, buf.Bytes(), 0644)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintln(os.Stderr, "unable to write cfg file: "+err.Error())
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cfg
|
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) {
|
func initSchema(schemaFilename string) error {
|
||||||
_, err := os.Stat(schemaFilename)
|
_, err := os.Stat(schemaFilename)
|
||||||
if !os.IsNotExist(err) {
|
if !os.IsNotExist(err) {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ioutil.WriteFile(schemaFilename, []byte(strings.TrimSpace(schemaDefault)), 0644)
|
if err := os.MkdirAll(filepath.Dir(schemaFilename), 0755); err != nil {
|
||||||
if err != nil {
|
return fmt.Errorf("unable to create schema dir: " + err.Error())
|
||||||
fmt.Fprintln(os.Stderr, "unable to write schema file: "+err.Error())
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = ioutil.WriteFile(schemaFilename, []byte(strings.TrimSpace(schemaDefault)), 0644); err != nil {
|
||||||
|
return fmt.Errorf("unable to write schema file: " + err.Error())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
5
vendor/github.com/99designs/gqlgen/cmd/root.go
generated
vendored
5
vendor/github.com/99designs/gqlgen/cmd/root.go
generated
vendored
@@ -7,9 +7,10 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/graphql"
|
"github.com/99designs/gqlgen/graphql"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
||||||
// Required since otherwise dep will prune away these unused packages before codegen has a chance to run
|
// 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"
|
_ "github.com/99designs/gqlgen/handler"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -31,7 +32,7 @@ func Execute() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.Action = genCmd.Action
|
app.Action = genCmd.Action
|
||||||
app.Commands = []cli.Command{
|
app.Commands = []*cli.Command{
|
||||||
genCmd,
|
genCmd,
|
||||||
initCmd,
|
initCmd,
|
||||||
versionCmd,
|
versionCmd,
|
||||||
|
|||||||
7
vendor/github.com/99designs/gqlgen/cmd/version.go
generated
vendored
7
vendor/github.com/99designs/gqlgen/cmd/version.go
generated
vendored
@@ -4,13 +4,14 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/graphql"
|
"github.com/99designs/gqlgen/graphql"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
var versionCmd = cli.Command{
|
var versionCmd = &cli.Command{
|
||||||
Name: "version",
|
Name: "version",
|
||||||
Usage: "print the version string",
|
Usage: "print the version string",
|
||||||
Action: func(ctx *cli.Context) {
|
Action: func(ctx *cli.Context) error {
|
||||||
fmt.Println(graphql.Version)
|
fmt.Println(graphql.Version)
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
18
vendor/github.com/99designs/gqlgen/codegen/args.go
generated
vendored
18
vendor/github.com/99designs/gqlgen/codegen/args.go
generated
vendored
@@ -8,7 +8,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/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/vektah/gqlparser/ast"
|
"github.com/vektah/gqlparser/v2/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ArgSet struct {
|
type ArgSet struct {
|
||||||
@@ -26,6 +26,22 @@ type FieldArgument struct {
|
|||||||
Value interface{} // value set in Data
|
Value interface{} // value set in Data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//ImplDirectives get not Builtin and location ARGUMENT_DEFINITION directive
|
||||||
|
func (f *FieldArgument) ImplDirectives() []*Directive {
|
||||||
|
d := make([]*Directive, 0)
|
||||||
|
for i := range f.Directives {
|
||||||
|
if !f.Directives[i].Builtin && f.Directives[i].IsLocation(ast.LocationArgumentDefinition) {
|
||||||
|
d = append(d, f.Directives[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *FieldArgument) DirectiveObjName() string {
|
||||||
|
return "rawArgs"
|
||||||
|
}
|
||||||
|
|
||||||
func (f *FieldArgument) Stream() bool {
|
func (f *FieldArgument) Stream() bool {
|
||||||
return f.Object != nil && f.Object.Stream
|
return f.Object != nil && f.Object.Stream
|
||||||
}
|
}
|
||||||
|
|||||||
25
vendor/github.com/99designs/gqlgen/codegen/args.gotpl
generated
vendored
25
vendor/github.com/99designs/gqlgen/codegen/args.gotpl
generated
vendored
@@ -5,27 +5,20 @@ 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 {
|
||||||
{{- if $arg.Directives }}
|
ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField({{$arg.Name|quote}}))
|
||||||
getArg0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, tmp) }
|
{{- if $arg.ImplDirectives }}
|
||||||
|
directive0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, tmp) }
|
||||||
{{- range $i, $directive := $arg.Directives }}
|
{{ template "implDirectives" $arg }}
|
||||||
getArg{{add $i 1}} := func(ctx context.Context) (res interface{}, err error) {
|
tmp, err = directive{{$arg.ImplDirectives|len}}(ctx)
|
||||||
{{- range $dArg := $directive.Args }}
|
|
||||||
{{- if and $dArg.TypeReference.IsPtr ( notNil "Value" $dArg ) }}
|
|
||||||
{{ $dArg.VarName }} := {{ $dArg.Value | dump }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
n := getArg{{$i}}
|
|
||||||
return ec.directives.{{$directive.Name|ucFirst}}({{$directive.ResolveArgs "tmp" "n" }})
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
tmp, err = getArg{{$arg.Directives|len}}(ctx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, 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
|
||||||
|
{{- if $arg.TypeReference.IsNilable }}
|
||||||
|
} else if tmp == nil {
|
||||||
|
arg{{$i}} = nil
|
||||||
|
{{- end }}
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf(`unexpected type %T from directive, should be {{ $arg.TypeReference.GO }}`, tmp)
|
return nil, fmt.Errorf(`unexpected type %T from directive, should be {{ $arg.TypeReference.GO }}`, tmp)
|
||||||
}
|
}
|
||||||
|
|||||||
110
vendor/github.com/99designs/gqlgen/codegen/config/binder.go
generated
vendored
110
vendor/github.com/99designs/gqlgen/codegen/config/binder.go
generated
vendored
@@ -8,37 +8,24 @@ import (
|
|||||||
"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/pkg/errors"
|
||||||
"github.com/vektah/gqlparser/ast"
|
"github.com/vektah/gqlparser/v2/ast"
|
||||||
"golang.org/x/tools/go/packages"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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 []*packages.Package
|
pkgs *code.Packages
|
||||||
schema *ast.Schema
|
schema *ast.Schema
|
||||||
cfg *Config
|
cfg *Config
|
||||||
References []*TypeReference
|
References []*TypeReference
|
||||||
|
SawInvalid bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) NewBinder(s *ast.Schema) (*Binder, error) {
|
func (c *Config) NewBinder() *Binder {
|
||||||
pkgs, err := packages.Load(&packages.Config{Mode: packages.LoadTypes | packages.LoadSyntax}, c.Models.ReferencedPackages()...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, p := range pkgs {
|
|
||||||
for _, e := range p.Errors {
|
|
||||||
if e.Kind == packages.ListError {
|
|
||||||
return nil, p.Errors[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &Binder{
|
return &Binder{
|
||||||
pkgs: pkgs,
|
pkgs: c.Packages,
|
||||||
schema: s,
|
schema: c.Schema,
|
||||||
cfg: c,
|
cfg: c,
|
||||||
}, nil
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Binder) TypePosition(typ types.Type) token.Position {
|
func (b *Binder) TypePosition(typ types.Type) token.Position {
|
||||||
@@ -58,11 +45,26 @@ func (b *Binder) ObjectPosition(typ types.Object) token.Position {
|
|||||||
Filename: "unknown",
|
Filename: "unknown",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pkg := b.getPkg(typ.Pkg().Path())
|
pkg := b.pkgs.Load(typ.Pkg().Path())
|
||||||
return pkg.Fset.Position(typ.Pos())
|
return pkg.Fset.Position(typ.Pos())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Binder) FindTypeFromName(name string) (types.Type, error) {
|
||||||
|
pkgName, typeName := code.PkgAndType(name)
|
||||||
|
return b.FindType(pkgName, typeName)
|
||||||
|
}
|
||||||
|
|
||||||
func (b *Binder) FindType(pkgName string, typeName string) (types.Type, error) {
|
func (b *Binder) FindType(pkgName string, typeName string) (types.Type, error) {
|
||||||
|
if pkgName == "" {
|
||||||
|
if typeName == "map[string]interface{}" {
|
||||||
|
return MapType, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if typeName == "interface{}" {
|
||||||
|
return InterfaceType, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
obj, err := b.FindObject(pkgName, typeName)
|
obj, err := b.FindObject(pkgName, typeName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -74,15 +76,6 @@ func (b *Binder) FindType(pkgName string, typeName string) (types.Type, error) {
|
|||||||
return obj.Type(), nil
|
return obj.Type(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Binder) getPkg(find string) *packages.Package {
|
|
||||||
for _, p := range b.pkgs {
|
|
||||||
if code.NormalizeVendor(find) == code.NormalizeVendor(p.PkgPath) {
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var MapType = types.NewMap(types.Typ[types.String], types.NewInterfaceType(nil, nil).Complete())
|
var MapType = types.NewMap(types.Typ[types.String], types.NewInterfaceType(nil, nil).Complete())
|
||||||
var InterfaceType = types.NewInterfaceType(nil, nil)
|
var InterfaceType = types.NewInterfaceType(nil, nil)
|
||||||
|
|
||||||
@@ -122,7 +115,7 @@ func (b *Binder) FindObject(pkgName string, typeName string) (types.Object, erro
|
|||||||
fullName = pkgName + "." + typeName
|
fullName = pkgName + "." + typeName
|
||||||
}
|
}
|
||||||
|
|
||||||
pkg := b.getPkg(pkgName)
|
pkg := b.pkgs.LoadWithTypes(pkgName)
|
||||||
if pkg == nil {
|
if pkg == nil {
|
||||||
return nil, errors.Errorf("required package was not loaded: %s", fullName)
|
return nil, errors.Errorf("required package was not loaded: %s", fullName)
|
||||||
}
|
}
|
||||||
@@ -173,7 +166,8 @@ func (b *Binder) PointerTo(ref *TypeReference) *TypeReference {
|
|||||||
type TypeReference struct {
|
type TypeReference struct {
|
||||||
Definition *ast.Definition
|
Definition *ast.Definition
|
||||||
GQL *ast.Type
|
GQL *ast.Type
|
||||||
GO types.Type
|
GO types.Type // Type of the field being bound. Could be a pointer or a value type of Target.
|
||||||
|
Target types.Type // The actual type that we know how to bind to. May require pointer juggling when traversing to fields.
|
||||||
CastType types.Type // Before calling marshalling functions cast from/to this base type
|
CastType types.Type // Before calling marshalling functions cast from/to this base type
|
||||||
Marshaler *types.Func // When using external marshalling functions this will point to the Marshal function
|
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
|
||||||
@@ -184,6 +178,7 @@ func (ref *TypeReference) Elem() *TypeReference {
|
|||||||
if p, isPtr := ref.GO.(*types.Pointer); isPtr {
|
if p, isPtr := ref.GO.(*types.Pointer); isPtr {
|
||||||
return &TypeReference{
|
return &TypeReference{
|
||||||
GO: p.Elem(),
|
GO: p.Elem(),
|
||||||
|
Target: ref.Target,
|
||||||
GQL: ref.GQL,
|
GQL: ref.GQL,
|
||||||
CastType: ref.CastType,
|
CastType: ref.CastType,
|
||||||
Definition: ref.Definition,
|
Definition: ref.Definition,
|
||||||
@@ -196,6 +191,7 @@ func (ref *TypeReference) Elem() *TypeReference {
|
|||||||
if ref.IsSlice() {
|
if ref.IsSlice() {
|
||||||
return &TypeReference{
|
return &TypeReference{
|
||||||
GO: ref.GO.(*types.Slice).Elem(),
|
GO: ref.GO.(*types.Slice).Elem(),
|
||||||
|
Target: ref.Target,
|
||||||
GQL: ref.GQL.Elem,
|
GQL: ref.GQL.Elem,
|
||||||
CastType: ref.CastType,
|
CastType: ref.CastType,
|
||||||
Definition: ref.Definition,
|
Definition: ref.Definition,
|
||||||
@@ -213,10 +209,7 @@ func (t *TypeReference) IsPtr() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *TypeReference) IsNilable() bool {
|
func (t *TypeReference) IsNilable() bool {
|
||||||
_, isPtr := t.GO.(*types.Pointer)
|
return IsNilable(t.GO)
|
||||||
_, isMap := t.GO.(*types.Map)
|
|
||||||
_, isInterface := t.GO.(*types.Interface)
|
|
||||||
return isPtr || isMap || isInterface
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TypeReference) IsSlice() bool {
|
func (t *TypeReference) IsSlice() bool {
|
||||||
@@ -244,7 +237,12 @@ func (t *TypeReference) UniquenessKey() string {
|
|||||||
nullability = "N"
|
nullability = "N"
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullability + t.Definition.Name + "2" + templates.TypeIdentifier(t.GO)
|
var elemNullability = ""
|
||||||
|
if t.GQL.Elem != nil && t.GQL.Elem.NonNull {
|
||||||
|
// Fix for #896
|
||||||
|
elemNullability = "ᚄ"
|
||||||
|
}
|
||||||
|
return nullability + t.Definition.Name + "2" + templates.TypeIdentifier(t.GO) + elemNullability
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TypeReference) MarshalFunc() string {
|
func (t *TypeReference) MarshalFunc() string {
|
||||||
@@ -271,6 +269,10 @@ func (t *TypeReference) UnmarshalFunc() string {
|
|||||||
return "unmarshal" + t.UniquenessKey()
|
return "unmarshal" + t.UniquenessKey()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *TypeReference) IsTargetNilable() bool {
|
||||||
|
return IsNilable(t.Target)
|
||||||
|
}
|
||||||
|
|
||||||
func (b *Binder) PushRef(ret *TypeReference) {
|
func (b *Binder) PushRef(ret *TypeReference) {
|
||||||
b.References = append(b.References, ret)
|
b.References = append(b.References, ret)
|
||||||
}
|
}
|
||||||
@@ -292,6 +294,11 @@ func isIntf(t types.Type) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *Binder) TypeReference(schemaType *ast.Type, bindTarget types.Type) (ret *TypeReference, err error) {
|
func (b *Binder) TypeReference(schemaType *ast.Type, bindTarget types.Type) (ret *TypeReference, err error) {
|
||||||
|
if !isValid(bindTarget) {
|
||||||
|
b.SawInvalid = true
|
||||||
|
return nil, fmt.Errorf("%s has an invalid type", schemaType.Name())
|
||||||
|
}
|
||||||
|
|
||||||
var pkgName, typeName string
|
var pkgName, typeName string
|
||||||
def := b.schema.Types[schemaType.Name()]
|
def := b.schema.Types[schemaType.Name()]
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -350,7 +357,7 @@ func (b *Binder) TypeReference(schemaType *ast.Type, bindTarget types.Type) (ret
|
|||||||
ref.GO = obj.Type()
|
ref.GO = obj.Type()
|
||||||
ref.IsMarshaler = true
|
ref.IsMarshaler = true
|
||||||
} else if underlying := basicUnderlying(obj.Type()); def.IsLeafType() && underlying != nil && underlying.Kind() == types.String {
|
} else if underlying := basicUnderlying(obj.Type()); def.IsLeafType() && underlying != nil && underlying.Kind() == types.String {
|
||||||
// Special case for named types wrapping strings. Used by default enum implementations.
|
// TODO delete before v1. Backwards compatibility case for named types wrapping strings (see #595)
|
||||||
|
|
||||||
ref.GO = obj.Type()
|
ref.GO = obj.Type()
|
||||||
ref.CastType = underlying
|
ref.CastType = underlying
|
||||||
@@ -366,6 +373,7 @@ func (b *Binder) TypeReference(schemaType *ast.Type, bindTarget types.Type) (ret
|
|||||||
ref.GO = obj.Type()
|
ref.GO = obj.Type()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ref.Target = ref.GO
|
||||||
ref.GO = b.CopyModifiersFromAst(schemaType, ref.GO)
|
ref.GO = b.CopyModifiersFromAst(schemaType, ref.GO)
|
||||||
|
|
||||||
if bindTarget != nil {
|
if bindTarget != nil {
|
||||||
@@ -378,13 +386,21 @@ func (b *Binder) TypeReference(schemaType *ast.Type, bindTarget types.Type) (ret
|
|||||||
return ref, nil
|
return ref, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("%s has type compatible with %s", schemaType.Name(), bindTarget.String())
|
return nil, fmt.Errorf("%s is incompatible with %s", schemaType.Name(), bindTarget.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func isValid(t types.Type) bool {
|
||||||
|
basic, isBasic := t.(*types.Basic)
|
||||||
|
if !isBasic {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return basic.Kind() != types.Invalid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Binder) CopyModifiersFromAst(t *ast.Type, base types.Type) types.Type {
|
func (b *Binder) CopyModifiersFromAst(t *ast.Type, base types.Type) types.Type {
|
||||||
if t.Elem != nil {
|
if t.Elem != nil {
|
||||||
child := b.CopyModifiersFromAst(t.Elem, base)
|
child := b.CopyModifiersFromAst(t.Elem, base)
|
||||||
if _, isStruct := child.Underlying().(*types.Struct); isStruct {
|
if _, isStruct := child.Underlying().(*types.Struct); isStruct && !b.cfg.OmitSliceElementPointers {
|
||||||
child = types.NewPointer(child)
|
child = types.NewPointer(child)
|
||||||
}
|
}
|
||||||
return types.NewSlice(child)
|
return types.NewSlice(child)
|
||||||
@@ -395,13 +411,25 @@ func (b *Binder) CopyModifiersFromAst(t *ast.Type, base types.Type) types.Type {
|
|||||||
_, isInterface = named.Underlying().(*types.Interface)
|
_, isInterface = named.Underlying().(*types.Interface)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isInterface && !t.NonNull {
|
if !isInterface && !IsNilable(base) && !t.NonNull {
|
||||||
return types.NewPointer(base)
|
return types.NewPointer(base)
|
||||||
}
|
}
|
||||||
|
|
||||||
return base
|
return base
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsNilable(t types.Type) bool {
|
||||||
|
if namedType, isNamed := t.(*types.Named); isNamed {
|
||||||
|
return IsNilable(namedType.Underlying())
|
||||||
|
}
|
||||||
|
_, isPtr := t.(*types.Pointer)
|
||||||
|
_, isMap := t.(*types.Map)
|
||||||
|
_, isInterface := t.(*types.Interface)
|
||||||
|
_, isSlice := t.(*types.Slice)
|
||||||
|
_, isChan := t.(*types.Chan)
|
||||||
|
return isPtr || isMap || isInterface || isSlice || isChan
|
||||||
|
}
|
||||||
|
|
||||||
func hasMethod(it types.Type, name string) bool {
|
func hasMethod(it types.Type, name string) bool {
|
||||||
if ptr, isPtr := it.(*types.Pointer); isPtr {
|
if ptr, isPtr := it.(*types.Pointer); isPtr {
|
||||||
it = ptr.Elem()
|
it = ptr.Elem()
|
||||||
|
|||||||
420
vendor/github.com/99designs/gqlgen/codegen/config/config.go
generated
vendored
420
vendor/github.com/99designs/gqlgen/codegen/config/config.go
generated
vendored
@@ -2,27 +2,38 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/types"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/internal/code"
|
"github.com/99designs/gqlgen/internal/code"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/vektah/gqlparser"
|
"github.com/vektah/gqlparser/v2"
|
||||||
"github.com/vektah/gqlparser/ast"
|
"github.com/vektah/gqlparser/v2/ast"
|
||||||
yaml "gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
SchemaFilename StringList `yaml:"schema,omitempty"`
|
SchemaFilename StringList `yaml:"schema,omitempty"`
|
||||||
Exec PackageConfig `yaml:"exec"`
|
Exec PackageConfig `yaml:"exec"`
|
||||||
Model PackageConfig `yaml:"model"`
|
Model PackageConfig `yaml:"model,omitempty"`
|
||||||
Resolver PackageConfig `yaml:"resolver,omitempty"`
|
Federation PackageConfig `yaml:"federation,omitempty"`
|
||||||
|
Resolver ResolverConfig `yaml:"resolver,omitempty"`
|
||||||
|
AutoBind []string `yaml:"autobind"`
|
||||||
Models TypeMap `yaml:"models,omitempty"`
|
Models TypeMap `yaml:"models,omitempty"`
|
||||||
StructTag string `yaml:"struct_tag,omitempty"`
|
StructTag string `yaml:"struct_tag,omitempty"`
|
||||||
|
Directives map[string]DirectiveConfig `yaml:"directives,omitempty"`
|
||||||
|
OmitSliceElementPointers bool `yaml:"omit_slice_element_pointers,omitempty"`
|
||||||
|
SkipValidation bool `yaml:"skip_validation,omitempty"`
|
||||||
|
Sources []*ast.Source `yaml:"-"`
|
||||||
|
Packages *code.Packages `yaml:"-"`
|
||||||
|
Schema *ast.Schema `yaml:"-"`
|
||||||
|
|
||||||
|
// Deprecated use Federation instead. Will be removed next release
|
||||||
|
Federated bool `yaml:"federated,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var cfgFilenames = []string{".gqlgen.yml", "gqlgen.yml", "gqlgen.yaml"}
|
var cfgFilenames = []string{".gqlgen.yml", "gqlgen.yml", "gqlgen.yaml"}
|
||||||
@@ -33,9 +44,30 @@ func DefaultConfig() *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: PackageConfig{Filename: "generated.go"},
|
||||||
|
Directives: map[string]DirectiveConfig{},
|
||||||
|
Models: TypeMap{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadDefaultConfig loads the default config so that it is ready to be used
|
||||||
|
func LoadDefaultConfig() (*Config, error) {
|
||||||
|
config := DefaultConfig()
|
||||||
|
|
||||||
|
for _, filename := range config.SchemaFilename {
|
||||||
|
filename = filepath.ToSlash(filename)
|
||||||
|
var err error
|
||||||
|
var schemaRaw []byte
|
||||||
|
schemaRaw, err = ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "unable to open schema")
|
||||||
|
}
|
||||||
|
|
||||||
|
config.Sources = append(config.Sources, &ast.Source{Name: filename, Input: string(schemaRaw)})
|
||||||
|
}
|
||||||
|
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
// LoadConfigFromDefaultLocations looks for a config file in the current directory, and all parent directories
|
// LoadConfigFromDefaultLocations looks for a config file in the current directory, and all parent directories
|
||||||
// walking up the tree. The closest config file will be returned.
|
// walking up the tree. The closest config file will be returned.
|
||||||
func LoadConfigFromDefaultLocations() (*Config, error) {
|
func LoadConfigFromDefaultLocations() (*Config, error) {
|
||||||
@@ -51,6 +83,13 @@ func LoadConfigFromDefaultLocations() (*Config, error) {
|
|||||||
return LoadConfig(cfgFile)
|
return LoadConfig(cfgFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var path2regex = strings.NewReplacer(
|
||||||
|
`.`, `\.`,
|
||||||
|
`*`, `.+`,
|
||||||
|
`\`, `[\\/]`,
|
||||||
|
`/`, `[\\/]`,
|
||||||
|
)
|
||||||
|
|
||||||
// LoadConfig reads the gqlgen.yml config file
|
// LoadConfig reads the gqlgen.yml config file
|
||||||
func LoadConfig(filename string) (*Config, error) {
|
func LoadConfig(filename string) (*Config, error) {
|
||||||
config := DefaultConfig()
|
config := DefaultConfig()
|
||||||
@@ -64,13 +103,51 @@ func LoadConfig(filename string) (*Config, error) {
|
|||||||
return nil, errors.Wrap(err, "unable to parse config")
|
return nil, errors.Wrap(err, "unable to parse config")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defaultDirectives := map[string]DirectiveConfig{
|
||||||
|
"skip": {SkipRuntime: true},
|
||||||
|
"include": {SkipRuntime: true},
|
||||||
|
"deprecated": {SkipRuntime: true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, value := range defaultDirectives {
|
||||||
|
if _, defined := config.Directives[key]; !defined {
|
||||||
|
config.Directives[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
preGlobbing := config.SchemaFilename
|
preGlobbing := config.SchemaFilename
|
||||||
config.SchemaFilename = StringList{}
|
config.SchemaFilename = StringList{}
|
||||||
for _, f := range preGlobbing {
|
for _, f := range preGlobbing {
|
||||||
matches, err := filepath.Glob(f)
|
var matches []string
|
||||||
|
|
||||||
|
// for ** we want to override default globbing patterns and walk all
|
||||||
|
// subdirectories to match schema files.
|
||||||
|
if strings.Contains(f, "**") {
|
||||||
|
pathParts := strings.SplitN(f, "**", 2)
|
||||||
|
rest := strings.TrimPrefix(strings.TrimPrefix(pathParts[1], `\`), `/`)
|
||||||
|
// turn the rest of the glob into a regex, anchored only at the end because ** allows
|
||||||
|
// for any number of dirs in between and walk will let us match against the full path name
|
||||||
|
globRe := regexp.MustCompile(path2regex.Replace(rest) + `$`)
|
||||||
|
|
||||||
|
if err := filepath.Walk(pathParts[0], func(path string, info os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if globRe.MatchString(strings.TrimPrefix(path, pathParts[0])) {
|
||||||
|
matches = append(matches, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to walk schema at root %s", pathParts[0])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
matches, err = filepath.Glob(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to glob schema filename %s", f)
|
return nil, errors.Wrapf(err, "failed to glob schema filename %s", f)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, m := range matches {
|
for _, m := range matches {
|
||||||
if config.SchemaFilename.Has(m) {
|
if config.SchemaFilename.Has(m) {
|
||||||
@@ -80,13 +157,126 @@ func LoadConfig(filename string) (*Config, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, filename := range config.SchemaFilename {
|
||||||
|
filename = filepath.ToSlash(filename)
|
||||||
|
var err error
|
||||||
|
var schemaRaw []byte
|
||||||
|
schemaRaw, err = ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "unable to open schema")
|
||||||
|
}
|
||||||
|
|
||||||
|
config.Sources = append(config.Sources, &ast.Source{Name: filename, Input: string(schemaRaw)})
|
||||||
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type PackageConfig struct {
|
func (c *Config) Init() error {
|
||||||
Filename string `yaml:"filename,omitempty"`
|
if c.Packages == nil {
|
||||||
Package string `yaml:"package,omitempty"`
|
c.Packages = &code.Packages{}
|
||||||
Type string `yaml:"type,omitempty"`
|
}
|
||||||
|
|
||||||
|
if c.Schema == nil {
|
||||||
|
if err := c.LoadSchema(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := c.injectTypesFromSchema()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.autobind()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.injectBuiltins()
|
||||||
|
|
||||||
|
// prefetch all packages in one big packages.Load call
|
||||||
|
pkgs := []string{
|
||||||
|
"github.com/99designs/gqlgen/graphql",
|
||||||
|
"github.com/99designs/gqlgen/graphql/introspection",
|
||||||
|
}
|
||||||
|
pkgs = append(pkgs, c.Models.ReferencedPackages()...)
|
||||||
|
pkgs = append(pkgs, c.AutoBind...)
|
||||||
|
c.Packages.LoadAll(pkgs...)
|
||||||
|
|
||||||
|
// check everything is valid on the way out
|
||||||
|
err = c.check()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) injectTypesFromSchema() error {
|
||||||
|
c.Directives["goModel"] = DirectiveConfig{
|
||||||
|
SkipRuntime: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Directives["goField"] = DirectiveConfig{
|
||||||
|
SkipRuntime: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, schemaType := range c.Schema.Types {
|
||||||
|
if schemaType == c.Schema.Query || schemaType == c.Schema.Mutation || schemaType == c.Schema.Subscription {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if bd := schemaType.Directives.ForName("goModel"); bd != nil {
|
||||||
|
if ma := bd.Arguments.ForName("model"); ma != nil {
|
||||||
|
if mv, err := ma.Value.Value(nil); err == nil {
|
||||||
|
c.Models.Add(schemaType.Name, mv.(string))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ma := bd.Arguments.ForName("models"); ma != nil {
|
||||||
|
if mvs, err := ma.Value.Value(nil); err == nil {
|
||||||
|
for _, mv := range mvs.([]interface{}) {
|
||||||
|
c.Models.Add(schemaType.Name, mv.(string))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if schemaType.Kind == ast.Object || schemaType.Kind == ast.InputObject {
|
||||||
|
for _, field := range schemaType.Fields {
|
||||||
|
if fd := field.Directives.ForName("goField"); fd != nil {
|
||||||
|
forceResolver := c.Models[schemaType.Name].Fields[field.Name].Resolver
|
||||||
|
fieldName := c.Models[schemaType.Name].Fields[field.Name].FieldName
|
||||||
|
|
||||||
|
if ra := fd.Arguments.ForName("forceResolver"); ra != nil {
|
||||||
|
if fr, err := ra.Value.Value(nil); err == nil {
|
||||||
|
forceResolver = fr.(bool)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if na := fd.Arguments.ForName("name"); na != nil {
|
||||||
|
if fr, err := na.Value.Value(nil); err == nil {
|
||||||
|
fieldName = fr.(string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Models[schemaType.Name].Fields == nil {
|
||||||
|
c.Models[schemaType.Name] = TypeMapEntry{
|
||||||
|
Model: c.Models[schemaType.Name].Model,
|
||||||
|
Fields: map[string]TypeMapField{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Models[schemaType.Name].Fields[field.Name] = TypeMapField{
|
||||||
|
FieldName: fieldName,
|
||||||
|
Resolver: forceResolver,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type TypeMapEntry struct {
|
type TypeMapEntry struct {
|
||||||
@@ -97,6 +287,7 @@ type TypeMapEntry struct {
|
|||||||
type TypeMapField struct {
|
type TypeMapField struct {
|
||||||
Resolver bool `yaml:"resolver"`
|
Resolver bool `yaml:"resolver"`
|
||||||
FieldName string `yaml:"fieldName"`
|
FieldName string `yaml:"fieldName"`
|
||||||
|
GeneratedMethod string `yaml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type StringList []string
|
type StringList []string
|
||||||
@@ -128,90 +319,85 @@ func (a StringList) Has(file string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PackageConfig) normalize() error {
|
func (c *Config) check() error {
|
||||||
if c.Filename == "" {
|
if c.Models == nil {
|
||||||
return errors.New("Filename is required")
|
c.Models = TypeMap{}
|
||||||
}
|
|
||||||
c.Filename = abs(c.Filename)
|
|
||||||
// If Package is not set, first attempt to load the package at the output dir. If that fails
|
|
||||||
// fallback to just the base dir name of the output filename.
|
|
||||||
if c.Package == "" {
|
|
||||||
c.Package = code.NameForDir(c.Dir())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
type FilenamePackage struct {
|
||||||
}
|
Filename string
|
||||||
|
Package string
|
||||||
func (c *PackageConfig) ImportPath() string {
|
Declaree string
|
||||||
return code.ImportPathForDir(c.Dir())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *PackageConfig) Dir() string {
|
|
||||||
return filepath.Dir(c.Filename)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *PackageConfig) Check() error {
|
|
||||||
if strings.ContainsAny(c.Package, "./\\") {
|
|
||||||
return fmt.Errorf("package should be the output package name only, do not include the output filename")
|
|
||||||
}
|
|
||||||
if c.Filename != "" && !strings.HasSuffix(c.Filename, ".go") {
|
|
||||||
return fmt.Errorf("filename should be path to a go source file")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.normalize()
|
fileList := map[string][]FilenamePackage{}
|
||||||
}
|
|
||||||
|
|
||||||
func (c *PackageConfig) Pkg() *types.Package {
|
|
||||||
return types.NewPackage(c.ImportPath(), c.Dir())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *PackageConfig) IsDefined() bool {
|
|
||||||
return c.Filename != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) Check() error {
|
|
||||||
if err := c.Models.Check(); err != nil {
|
if err := c.Models.Check(); err != nil {
|
||||||
return errors.Wrap(err, "config.models")
|
return errors.Wrap(err, "config.models")
|
||||||
}
|
}
|
||||||
if err := c.Exec.Check(); err != nil {
|
if err := c.Exec.Check(); err != nil {
|
||||||
return errors.Wrap(err, "config.exec")
|
return errors.Wrap(err, "config.exec")
|
||||||
}
|
}
|
||||||
|
fileList[c.Exec.ImportPath()] = append(fileList[c.Exec.ImportPath()], FilenamePackage{
|
||||||
|
Filename: c.Exec.Filename,
|
||||||
|
Package: c.Exec.Package,
|
||||||
|
Declaree: "exec",
|
||||||
|
})
|
||||||
|
|
||||||
|
if c.Model.IsDefined() {
|
||||||
if err := c.Model.Check(); err != nil {
|
if err := c.Model.Check(); err != nil {
|
||||||
return errors.Wrap(err, "config.model")
|
return errors.Wrap(err, "config.model")
|
||||||
}
|
}
|
||||||
|
fileList[c.Model.ImportPath()] = append(fileList[c.Model.ImportPath()], FilenamePackage{
|
||||||
|
Filename: c.Model.Filename,
|
||||||
|
Package: c.Model.Package,
|
||||||
|
Declaree: "model",
|
||||||
|
})
|
||||||
|
}
|
||||||
if c.Resolver.IsDefined() {
|
if c.Resolver.IsDefined() {
|
||||||
if err := c.Resolver.Check(); err != nil {
|
if err := c.Resolver.Check(); err != nil {
|
||||||
return errors.Wrap(err, "config.resolver")
|
return errors.Wrap(err, "config.resolver")
|
||||||
}
|
}
|
||||||
|
fileList[c.Resolver.ImportPath()] = append(fileList[c.Resolver.ImportPath()], FilenamePackage{
|
||||||
|
Filename: c.Resolver.Filename,
|
||||||
|
Package: c.Resolver.Package,
|
||||||
|
Declaree: "resolver",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if c.Federation.IsDefined() {
|
||||||
|
if err := c.Federation.Check(); err != nil {
|
||||||
|
return errors.Wrap(err, "config.federation")
|
||||||
|
}
|
||||||
|
fileList[c.Federation.ImportPath()] = append(fileList[c.Federation.ImportPath()], FilenamePackage{
|
||||||
|
Filename: c.Federation.Filename,
|
||||||
|
Package: c.Federation.Package,
|
||||||
|
Declaree: "federation",
|
||||||
|
})
|
||||||
|
if c.Federation.ImportPath() != c.Exec.ImportPath() {
|
||||||
|
return fmt.Errorf("federation and exec must be in the same package")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c.Federated {
|
||||||
|
return fmt.Errorf("federated has been removed, instead use\nfederation:\n filename: path/to/federated.go")
|
||||||
}
|
}
|
||||||
|
|
||||||
// check packages names against conflict, if present in the same dir
|
for importPath, pkg := range fileList {
|
||||||
// and check filenames for uniqueness
|
for _, file1 := range pkg {
|
||||||
packageConfigList := []PackageConfig{
|
for _, file2 := range pkg {
|
||||||
c.Model,
|
if file1.Package != file2.Package {
|
||||||
c.Exec,
|
return fmt.Errorf("%s and %s define the same import path (%s) with different package names (%s vs %s)",
|
||||||
c.Resolver,
|
file1.Declaree,
|
||||||
|
file2.Declaree,
|
||||||
|
importPath,
|
||||||
|
file1.Package,
|
||||||
|
file2.Package,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
filesMap := make(map[string]bool)
|
|
||||||
pkgConfigsByDir := make(map[string]PackageConfig)
|
|
||||||
for _, current := range packageConfigList {
|
|
||||||
_, fileFound := filesMap[current.Filename]
|
|
||||||
if fileFound {
|
|
||||||
return fmt.Errorf("filename %s defined more than once", current.Filename)
|
|
||||||
}
|
}
|
||||||
filesMap[current.Filename] = true
|
|
||||||
previous, inSameDir := pkgConfigsByDir[current.Dir()]
|
|
||||||
if inSameDir && current.Package != previous.Package {
|
|
||||||
return fmt.Errorf("filenames %s and %s are in the same directory but have different package definitions", stripPath(current.Filename), stripPath(previous.Filename))
|
|
||||||
}
|
}
|
||||||
pkgConfigsByDir[current.Dir()] = current
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.normalize()
|
return nil
|
||||||
}
|
|
||||||
|
|
||||||
func stripPath(path string) string {
|
|
||||||
return filepath.Base(path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type TypeMap map[string]TypeMapEntry
|
type TypeMap map[string]TypeMapEntry
|
||||||
@@ -259,10 +445,14 @@ func (tm TypeMap) ReferencedPackages() []string {
|
|||||||
return pkgs
|
return pkgs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tm TypeMap) Add(Name string, goType string) {
|
func (tm TypeMap) Add(name string, goType string) {
|
||||||
modelCfg := tm[Name]
|
modelCfg := tm[name]
|
||||||
modelCfg.Model = append(modelCfg.Model, goType)
|
modelCfg.Model = append(modelCfg.Model, goType)
|
||||||
tm[Name] = modelCfg
|
tm[name] = modelCfg
|
||||||
|
}
|
||||||
|
|
||||||
|
type DirectiveConfig struct {
|
||||||
|
SkipRuntime bool `yaml:"skip_runtime"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func inStrSlice(haystack []string, needle string) bool {
|
func inStrSlice(haystack []string, needle string) bool {
|
||||||
@@ -307,29 +497,54 @@ func findCfgInDir(dir string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) normalize() error {
|
func (c *Config) autobind() error {
|
||||||
if err := c.Model.normalize(); err != nil {
|
if len(c.AutoBind) == 0 {
|
||||||
return errors.Wrap(err, "model")
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.Exec.normalize(); err != nil {
|
ps := c.Packages.LoadAll(c.AutoBind...)
|
||||||
return errors.Wrap(err, "exec")
|
|
||||||
|
for _, t := range c.Schema.Types {
|
||||||
|
if c.Models.UserDefined(t.Name) {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Resolver.IsDefined() {
|
for i, p := range ps {
|
||||||
if err := c.Resolver.normalize(); err != nil {
|
if p == nil {
|
||||||
return errors.Wrap(err, "resolver")
|
return fmt.Errorf("unable to load %s - make sure you're using an import path to a package that exists", c.AutoBind[i])
|
||||||
|
}
|
||||||
|
if t := p.Types.Scope().Lookup(t.Name); t != nil {
|
||||||
|
c.Models.Add(t.Name(), t.Pkg().Path()+"."+t.Name())
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Models == nil {
|
for i, t := range c.Models {
|
||||||
c.Models = TypeMap{}
|
for j, m := range t.Model {
|
||||||
|
pkg, typename := code.PkgAndType(m)
|
||||||
|
|
||||||
|
// skip anything that looks like an import path
|
||||||
|
if strings.Contains(pkg, "/") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range ps {
|
||||||
|
if p.Name != pkg {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if t := p.Types.Scope().Lookup(typename); t != nil {
|
||||||
|
c.Models[i].Model[j] = t.Pkg().Path() + "." + t.Name()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) InjectBuiltins(s *ast.Schema) {
|
func (c *Config) injectBuiltins() {
|
||||||
builtins := TypeMap{
|
builtins := TypeMap{
|
||||||
"__Directive": {Model: StringList{"github.com/99designs/gqlgen/graphql/introspection.Directive"}},
|
"__Directive": {Model: StringList{"github.com/99designs/gqlgen/graphql/introspection.Directive"}},
|
||||||
"__DirectiveLocation": {Model: StringList{"github.com/99designs/gqlgen/graphql.String"}},
|
"__DirectiveLocation": {Model: StringList{"github.com/99designs/gqlgen/graphql.String"}},
|
||||||
@@ -370,35 +585,36 @@ func (c *Config) InjectBuiltins(s *ast.Schema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for typeName, entry := range extraBuiltins {
|
for typeName, entry := range extraBuiltins {
|
||||||
if t, ok := s.Types[typeName]; !c.Models.Exists(typeName) && ok && t.Kind == ast.Scalar {
|
if t, ok := c.Schema.Types[typeName]; !c.Models.Exists(typeName) && ok && t.Kind == ast.Scalar {
|
||||||
c.Models[typeName] = entry
|
c.Models[typeName] = entry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) LoadSchema() (*ast.Schema, map[string]string, error) {
|
func (c *Config) LoadSchema() error {
|
||||||
schemaStrings := map[string]string{}
|
if c.Packages != nil {
|
||||||
|
c.Packages = &code.Packages{}
|
||||||
|
}
|
||||||
|
|
||||||
var sources []*ast.Source
|
if err := c.check(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
for _, filename := range c.SchemaFilename {
|
schema, err := gqlparser.LoadSchema(c.Sources...)
|
||||||
filename = filepath.ToSlash(filename)
|
|
||||||
var err error
|
|
||||||
var schemaRaw []byte
|
|
||||||
schemaRaw, err = ioutil.ReadFile(filename)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, "unable to open schema: "+err.Error())
|
return err
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
schemaStrings[filename] = string(schemaRaw)
|
|
||||||
sources = append(sources, &ast.Source{Name: filename, Input: schemaStrings[filename]})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
schema, err := gqlparser.LoadSchema(sources...)
|
if schema.Query == nil {
|
||||||
if err != nil {
|
schema.Query = &ast.Definition{
|
||||||
return nil, nil, err
|
Kind: ast.Object,
|
||||||
|
Name: "Query",
|
||||||
}
|
}
|
||||||
return schema, schemaStrings, nil
|
schema.Types["Query"] = schema.Query
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Schema = schema
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func abs(path string) string {
|
func abs(path string) string {
|
||||||
|
|||||||
62
vendor/github.com/99designs/gqlgen/codegen/config/package.go
generated
vendored
Normal file
62
vendor/github.com/99designs/gqlgen/codegen/config/package.go
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go/types"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/99designs/gqlgen/internal/code"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PackageConfig struct {
|
||||||
|
Filename string `yaml:"filename,omitempty"`
|
||||||
|
Package string `yaml:"package,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PackageConfig) ImportPath() string {
|
||||||
|
if !c.IsDefined() {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return code.ImportPathForDir(c.Dir())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PackageConfig) Dir() string {
|
||||||
|
if !c.IsDefined() {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return filepath.Dir(c.Filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PackageConfig) Pkg() *types.Package {
|
||||||
|
if !c.IsDefined() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return types.NewPackage(c.ImportPath(), c.Package)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PackageConfig) IsDefined() bool {
|
||||||
|
return c.Filename != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PackageConfig) Check() error {
|
||||||
|
if strings.ContainsAny(c.Package, "./\\") {
|
||||||
|
return fmt.Errorf("package should be the output package name only, do not include the output filename")
|
||||||
|
}
|
||||||
|
if c.Filename == "" {
|
||||||
|
return fmt.Errorf("filename must be specified")
|
||||||
|
}
|
||||||
|
if !strings.HasSuffix(c.Filename, ".go") {
|
||||||
|
return fmt.Errorf("filename should be path to a go source file")
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Filename = abs(c.Filename)
|
||||||
|
|
||||||
|
// If Package is not set, first attempt to load the package at the output dir. If that fails
|
||||||
|
// fallback to just the base dir name of the output filename.
|
||||||
|
if c.Package == "" {
|
||||||
|
c.Package = code.NameForDir(c.Dir())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
100
vendor/github.com/99designs/gqlgen/codegen/config/resolver.go
generated
vendored
Normal file
100
vendor/github.com/99designs/gqlgen/codegen/config/resolver.go
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go/types"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/99designs/gqlgen/internal/code"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ResolverConfig struct {
|
||||||
|
Filename string `yaml:"filename,omitempty"`
|
||||||
|
FilenameTemplate string `yaml:"filename_template,omitempty"`
|
||||||
|
Package string `yaml:"package,omitempty"`
|
||||||
|
Type string `yaml:"type,omitempty"`
|
||||||
|
Layout ResolverLayout `yaml:"layout,omitempty"`
|
||||||
|
DirName string `yaml:"dir"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResolverLayout string
|
||||||
|
|
||||||
|
var (
|
||||||
|
LayoutSingleFile ResolverLayout = "single-file"
|
||||||
|
LayoutFollowSchema ResolverLayout = "follow-schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (r *ResolverConfig) Check() error {
|
||||||
|
if r.Layout == "" {
|
||||||
|
r.Layout = LayoutSingleFile
|
||||||
|
}
|
||||||
|
if r.Type == "" {
|
||||||
|
r.Type = "Resolver"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch r.Layout {
|
||||||
|
case LayoutSingleFile:
|
||||||
|
if r.Filename == "" {
|
||||||
|
return fmt.Errorf("filename must be specified with layout=%s", r.Layout)
|
||||||
|
}
|
||||||
|
if !strings.HasSuffix(r.Filename, ".go") {
|
||||||
|
return fmt.Errorf("filename should be path to a go source file with layout=%s", r.Layout)
|
||||||
|
}
|
||||||
|
r.Filename = abs(r.Filename)
|
||||||
|
case LayoutFollowSchema:
|
||||||
|
if r.DirName == "" {
|
||||||
|
return fmt.Errorf("dirname must be specified with layout=%s", r.Layout)
|
||||||
|
}
|
||||||
|
r.DirName = abs(r.DirName)
|
||||||
|
if r.Filename == "" {
|
||||||
|
r.Filename = filepath.Join(r.DirName, "resolver.go")
|
||||||
|
} else {
|
||||||
|
r.Filename = abs(r.Filename)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid layout %s. must be %s or %s", r.Layout, LayoutSingleFile, LayoutFollowSchema)
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.ContainsAny(r.Package, "./\\") {
|
||||||
|
return fmt.Errorf("package should be the output package name only, do not include the output filename")
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Package == "" && r.Dir() != "" {
|
||||||
|
r.Package = code.NameForDir(r.Dir())
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ResolverConfig) ImportPath() string {
|
||||||
|
if r.Dir() == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return code.ImportPathForDir(r.Dir())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ResolverConfig) Dir() string {
|
||||||
|
switch r.Layout {
|
||||||
|
case LayoutSingleFile:
|
||||||
|
if r.Filename == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return filepath.Dir(r.Filename)
|
||||||
|
case LayoutFollowSchema:
|
||||||
|
return r.DirName
|
||||||
|
default:
|
||||||
|
panic("invalid layout " + r.Layout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ResolverConfig) Pkg() *types.Package {
|
||||||
|
if r.Dir() == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return types.NewPackage(r.ImportPath(), r.Package)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *ResolverConfig) IsDefined() bool {
|
||||||
|
return r.Filename != "" || r.DirName != ""
|
||||||
|
}
|
||||||
51
vendor/github.com/99designs/gqlgen/codegen/data.go
generated
vendored
51
vendor/github.com/99designs/gqlgen/codegen/data.go
generated
vendored
@@ -4,9 +4,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/codegen/config"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/vektah/gqlparser/ast"
|
"github.com/vektah/gqlparser/v2/ast"
|
||||||
|
|
||||||
|
"github.com/99designs/gqlgen/codegen/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Data is a unified model of the code to be generated. Plugins may modify this structure to do things like implement
|
// Data is a unified model of the code to be generated. Plugins may modify this structure to do things like implement
|
||||||
@@ -14,8 +15,7 @@ import (
|
|||||||
type Data struct {
|
type Data struct {
|
||||||
Config *config.Config
|
Config *config.Config
|
||||||
Schema *ast.Schema
|
Schema *ast.Schema
|
||||||
SchemaStr map[string]string
|
Directives DirectiveList
|
||||||
Directives map[string]*Directive
|
|
||||||
Objects Objects
|
Objects Objects
|
||||||
Inputs Objects
|
Inputs Objects
|
||||||
Interfaces map[string]*Interface
|
Interfaces map[string]*Interface
|
||||||
@@ -30,7 +30,6 @@ type Data struct {
|
|||||||
type builder struct {
|
type builder struct {
|
||||||
Config *config.Config
|
Config *config.Config
|
||||||
Schema *ast.Schema
|
Schema *ast.Schema
|
||||||
SchemaStr map[string]string
|
|
||||||
Binder *config.Binder
|
Binder *config.Binder
|
||||||
Directives map[string]*Directive
|
Directives map[string]*Directive
|
||||||
}
|
}
|
||||||
@@ -38,26 +37,12 @@ type builder struct {
|
|||||||
func BuildData(cfg *config.Config) (*Data, error) {
|
func BuildData(cfg *config.Config) (*Data, error) {
|
||||||
b := builder{
|
b := builder{
|
||||||
Config: cfg,
|
Config: cfg,
|
||||||
|
Schema: cfg.Schema,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b.Binder = b.Config.NewBinder()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
b.Schema, b.SchemaStr, err = cfg.LoadSchema()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = cfg.Check()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg.InjectBuiltins(b.Schema)
|
|
||||||
|
|
||||||
b.Binder, err = b.Config.NewBinder(b.Schema)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
b.Directives, err = b.buildDirectives()
|
b.Directives, err = b.buildDirectives()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -74,7 +59,6 @@ func BuildData(cfg *config.Config) (*Data, error) {
|
|||||||
Config: cfg,
|
Config: cfg,
|
||||||
Directives: dataDirectives,
|
Directives: dataDirectives,
|
||||||
Schema: b.Schema,
|
Schema: b.Schema,
|
||||||
SchemaStr: b.SchemaStr,
|
|
||||||
Interfaces: map[string]*Interface{},
|
Interfaces: map[string]*Interface{},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +80,10 @@ func BuildData(cfg *config.Config) (*Data, error) {
|
|||||||
s.Inputs = append(s.Inputs, input)
|
s.Inputs = append(s.Inputs, input)
|
||||||
|
|
||||||
case ast.Union, ast.Interface:
|
case ast.Union, ast.Interface:
|
||||||
s.Interfaces[schemaType.Name] = b.buildInterface(schemaType)
|
s.Interfaces[schemaType.Name], err = b.buildInterface(schemaType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "unable to bind to interface")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,10 +105,7 @@ func BuildData(cfg *config.Config) (*Data, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.ReferencedTypes, err = b.buildTypes()
|
s.ReferencedTypes = b.buildTypes()
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Slice(s.Objects, func(i, j int) bool {
|
sort.Slice(s.Objects, func(i, j int) bool {
|
||||||
return s.Objects[i].Definition.Name < s.Objects[j].Definition.Name
|
return s.Objects[i].Definition.Name < s.Objects[j].Definition.Name
|
||||||
@@ -131,6 +115,17 @@ func BuildData(cfg *config.Config) (*Data, error) {
|
|||||||
return s.Inputs[i].Definition.Name < s.Inputs[j].Definition.Name
|
return s.Inputs[i].Definition.Name < s.Inputs[j].Definition.Name
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if b.Binder.SawInvalid {
|
||||||
|
// if we have a syntax error, show it
|
||||||
|
err := cfg.Packages.Errors()
|
||||||
|
if len(err) > 0 {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise show a generic error message
|
||||||
|
return nil, fmt.Errorf("invalid types were encountered while traversing the go source code, this probably means the invalid code generated isnt correct. add try adding -v to debug")
|
||||||
|
}
|
||||||
|
|
||||||
return &s, nil
|
return &s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
59
vendor/github.com/99designs/gqlgen/codegen/directive.go
generated
vendored
59
vendor/github.com/99designs/gqlgen/codegen/directive.go
generated
vendored
@@ -7,15 +7,46 @@ import (
|
|||||||
|
|
||||||
"github.com/99designs/gqlgen/codegen/templates"
|
"github.com/99designs/gqlgen/codegen/templates"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/vektah/gqlparser/ast"
|
"github.com/vektah/gqlparser/v2/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type DirectiveList map[string]*Directive
|
||||||
|
|
||||||
|
//LocationDirectives filter directives by location
|
||||||
|
func (dl DirectiveList) LocationDirectives(location string) DirectiveList {
|
||||||
|
return locationDirectives(dl, ast.DirectiveLocation(location))
|
||||||
|
}
|
||||||
|
|
||||||
type Directive struct {
|
type Directive struct {
|
||||||
|
*ast.DirectiveDefinition
|
||||||
Name string
|
Name string
|
||||||
Args []*FieldArgument
|
Args []*FieldArgument
|
||||||
Builtin bool
|
Builtin bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//IsLocation check location directive
|
||||||
|
func (d *Directive) IsLocation(location ...ast.DirectiveLocation) bool {
|
||||||
|
for _, l := range d.Locations {
|
||||||
|
for _, a := range location {
|
||||||
|
if l == a {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func locationDirectives(directives DirectiveList, location ...ast.DirectiveLocation) map[string]*Directive {
|
||||||
|
mDirectives := make(map[string]*Directive)
|
||||||
|
for name, d := range directives {
|
||||||
|
if d.IsLocation(location...) {
|
||||||
|
mDirectives[name] = d
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mDirectives
|
||||||
|
}
|
||||||
|
|
||||||
func (b *builder) buildDirectives() (map[string]*Directive, error) {
|
func (b *builder) buildDirectives() (map[string]*Directive, error) {
|
||||||
directives := make(map[string]*Directive, len(b.Schema.Directives))
|
directives := make(map[string]*Directive, len(b.Schema.Directives))
|
||||||
|
|
||||||
@@ -24,11 +55,6 @@ func (b *builder) buildDirectives() (map[string]*Directive, error) {
|
|||||||
return nil, errors.Errorf("directive with name %s already exists", name)
|
return nil, errors.Errorf("directive with name %s already exists", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
var builtin bool
|
|
||||||
if name == "skip" || name == "include" || name == "deprecated" {
|
|
||||||
builtin = true
|
|
||||||
}
|
|
||||||
|
|
||||||
var args []*FieldArgument
|
var args []*FieldArgument
|
||||||
for _, arg := range dir.Arguments {
|
for _, arg := range dir.Arguments {
|
||||||
tr, err := b.Binder.TypeReference(arg.Type, nil)
|
tr, err := b.Binder.TypeReference(arg.Type, nil)
|
||||||
@@ -53,9 +79,10 @@ func (b *builder) buildDirectives() (map[string]*Directive, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
directives[name] = &Directive{
|
directives[name] = &Directive{
|
||||||
|
DirectiveDefinition: dir,
|
||||||
Name: name,
|
Name: name,
|
||||||
Args: args,
|
Args: args,
|
||||||
Builtin: builtin,
|
Builtin: b.Config.Directives[name].SkipRuntime,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,6 +121,8 @@ func (b *builder) getDirectives(list ast.DirectiveList) ([]*Directive, error) {
|
|||||||
dirs[i] = &Directive{
|
dirs[i] = &Directive{
|
||||||
Name: d.Name,
|
Name: d.Name,
|
||||||
Args: args,
|
Args: args,
|
||||||
|
DirectiveDefinition: list[i].Definition,
|
||||||
|
Builtin: b.Config.Directives[d.Name].SkipRuntime,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -119,18 +148,12 @@ func (d *Directive) CallArgs() string {
|
|||||||
return strings.Join(args, ", ")
|
return strings.Join(args, ", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Directive) ResolveArgs(obj string, next string) string {
|
func (d *Directive) ResolveArgs(obj string, next int) string {
|
||||||
args := []string{"ctx", obj, next}
|
args := []string{"ctx", obj, fmt.Sprintf("directive%d", next)}
|
||||||
|
|
||||||
for _, arg := range d.Args {
|
for _, arg := range d.Args {
|
||||||
dArg := "&" + arg.VarName
|
dArg := arg.VarName
|
||||||
if !arg.TypeReference.IsPtr() {
|
if arg.Value == nil && arg.Default == nil {
|
||||||
if arg.Value != nil {
|
|
||||||
dArg = templates.Dump(arg.Value)
|
|
||||||
} else {
|
|
||||||
dArg = templates.Dump(arg.Default)
|
|
||||||
}
|
|
||||||
} else if arg.Value == nil && arg.Default == nil {
|
|
||||||
dArg = "nil"
|
dArg = "nil"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,7 +167,7 @@ func (d *Directive) Declaration() string {
|
|||||||
res := ucFirst(d.Name) + " func(ctx context.Context, obj interface{}, next graphql.Resolver"
|
res := ucFirst(d.Name) + " func(ctx context.Context, obj interface{}, next graphql.Resolver"
|
||||||
|
|
||||||
for _, arg := range d.Args {
|
for _, arg := range d.Args {
|
||||||
res += fmt.Sprintf(", %s %s", arg.Name, templates.CurrentImports.LookupType(arg.TypeReference.GO))
|
res += fmt.Sprintf(", %s %s", templates.ToGoPrivate(arg.Name), templates.CurrentImports.LookupType(arg.TypeReference.GO))
|
||||||
}
|
}
|
||||||
|
|
||||||
res += ") (res interface{}, err error)"
|
res += ") (res interface{}, err error)"
|
||||||
|
|||||||
149
vendor/github.com/99designs/gqlgen/codegen/directives.gotpl
generated
vendored
Normal file
149
vendor/github.com/99designs/gqlgen/codegen/directives.gotpl
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
{{ define "implDirectives" }}{{ $in := .DirectiveObjName }}
|
||||||
|
{{- range $i, $directive := .ImplDirectives -}}
|
||||||
|
directive{{add $i 1}} := func(ctx context.Context) (interface{}, error) {
|
||||||
|
{{- range $arg := $directive.Args }}
|
||||||
|
{{- if notNil "Value" $arg }}
|
||||||
|
{{ $arg.VarName }}, err := ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, {{ $arg.Value | dump }})
|
||||||
|
if err != nil{
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
{{- else if notNil "Default" $arg }}
|
||||||
|
{{ $arg.VarName }}, err := ec.{{ $arg.TypeReference.UnmarshalFunc }}(ctx, {{ $arg.Default | dump }})
|
||||||
|
if err != nil{
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
if ec.directives.{{$directive.Name|ucFirst}} == nil {
|
||||||
|
return nil, errors.New("directive {{$directive.Name}} is not implemented")
|
||||||
|
}
|
||||||
|
return ec.directives.{{$directive.Name|ucFirst}}({{$directive.ResolveArgs $in $i }})
|
||||||
|
}
|
||||||
|
{{ end -}}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{define "queryDirectives"}}
|
||||||
|
for _, d := range obj.Directives {
|
||||||
|
switch d.Name {
|
||||||
|
{{- range $directive := . }}
|
||||||
|
case "{{$directive.Name}}":
|
||||||
|
{{- if $directive.Args }}
|
||||||
|
rawArgs := d.ArgumentMap(ec.Variables)
|
||||||
|
args, err := ec.{{ $directive.ArgsFunc }}(ctx,rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
n := next
|
||||||
|
next = func(ctx context.Context) (interface{}, error) {
|
||||||
|
if ec.directives.{{$directive.Name|ucFirst}} == nil {
|
||||||
|
return nil, errors.New("directive {{$directive.Name}} is not implemented")
|
||||||
|
}
|
||||||
|
return ec.directives.{{$directive.Name|ucFirst}}({{$directive.CallArgs}})
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tmp, err := next(ctx)
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
if data, ok := tmp.(graphql.Marshaler); ok {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
ec.Errorf(ctx, `unexpected type %T from directive, should be graphql.Marshaler`, tmp)
|
||||||
|
return graphql.Null
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{ if .Directives.LocationDirectives "QUERY" }}
|
||||||
|
func (ec *executionContext) _queryMiddleware(ctx context.Context, obj *ast.OperationDefinition, next func(ctx context.Context) (interface{}, error)) graphql.Marshaler {
|
||||||
|
{{ template "queryDirectives" .Directives.LocationDirectives "QUERY" }}
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ if .Directives.LocationDirectives "MUTATION" }}
|
||||||
|
func (ec *executionContext) _mutationMiddleware(ctx context.Context, obj *ast.OperationDefinition, next func(ctx context.Context) (interface{}, error)) graphql.Marshaler {
|
||||||
|
{{ template "queryDirectives" .Directives.LocationDirectives "MUTATION" }}
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ if .Directives.LocationDirectives "SUBSCRIPTION" }}
|
||||||
|
func (ec *executionContext) _subscriptionMiddleware(ctx context.Context, obj *ast.OperationDefinition, next func(ctx context.Context) (interface{}, error)) func() graphql.Marshaler {
|
||||||
|
for _, d := range obj.Directives {
|
||||||
|
switch d.Name {
|
||||||
|
{{- range $directive := .Directives.LocationDirectives "SUBSCRIPTION" }}
|
||||||
|
case "{{$directive.Name}}":
|
||||||
|
{{- if $directive.Args }}
|
||||||
|
rawArgs := d.ArgumentMap(ec.Variables)
|
||||||
|
args, err := ec.{{ $directive.ArgsFunc }}(ctx,rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return func() graphql.Marshaler {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
n := next
|
||||||
|
next = func(ctx context.Context) (interface{}, error) {
|
||||||
|
if ec.directives.{{$directive.Name|ucFirst}} == nil {
|
||||||
|
return nil, errors.New("directive {{$directive.Name}} is not implemented")
|
||||||
|
}
|
||||||
|
return ec.directives.{{$directive.Name|ucFirst}}({{$directive.CallArgs}})
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tmp, err := next(ctx)
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return func() graphql.Marshaler {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if data, ok := tmp.(func() graphql.Marshaler); ok {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
ec.Errorf(ctx, `unexpected type %T from directive, should be graphql.Marshaler`, tmp)
|
||||||
|
return func() graphql.Marshaler {
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ if .Directives.LocationDirectives "FIELD" }}
|
||||||
|
func (ec *executionContext) _fieldMiddleware(ctx context.Context, obj interface{}, next graphql.Resolver) interface{} {
|
||||||
|
{{- if .Directives.LocationDirectives "FIELD" }}
|
||||||
|
fc := graphql.GetFieldContext(ctx)
|
||||||
|
for _, d := range fc.Field.Directives {
|
||||||
|
switch d.Name {
|
||||||
|
{{- range $directive := .Directives.LocationDirectives "FIELD" }}
|
||||||
|
case "{{$directive.Name}}":
|
||||||
|
{{- if $directive.Args }}
|
||||||
|
rawArgs := d.ArgumentMap(ec.Variables)
|
||||||
|
args, err := ec.{{ $directive.ArgsFunc }}(ctx,rawArgs)
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
n := next
|
||||||
|
next = func(ctx context.Context) (interface{}, error) {
|
||||||
|
if ec.directives.{{$directive.Name|ucFirst}} == nil {
|
||||||
|
return nil, errors.New("directive {{$directive.Name}} is not implemented")
|
||||||
|
}
|
||||||
|
return ec.directives.{{$directive.Name|ucFirst}}({{$directive.CallArgs}})
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
res, err := ec.ResolverMiddleware(ctx, next)
|
||||||
|
if err != nil {
|
||||||
|
ec.Error(ctx, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
275
vendor/github.com/99designs/gqlgen/codegen/field.go
generated
vendored
275
vendor/github.com/99designs/gqlgen/codegen/field.go
generated
vendored
@@ -11,7 +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/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/vektah/gqlparser/ast"
|
"github.com/vektah/gqlparser/v2/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Field struct {
|
type Field struct {
|
||||||
@@ -27,6 +27,7 @@ type Field struct {
|
|||||||
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
|
||||||
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?
|
||||||
Directives []*Directive
|
Directives []*Directive
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,17 +74,26 @@ func (b *builder) buildField(obj *Object, field *ast.FieldDefinition) (*Field, e
|
|||||||
return &f, nil
|
return &f, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *builder) bindField(obj *Object, f *Field) error {
|
func (b *builder) bindField(obj *Object, f *Field) (errret error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if f.TypeReference == nil {
|
if f.TypeReference == nil {
|
||||||
tr, err := b.Binder.TypeReference(f.Type, nil)
|
tr, err := b.Binder.TypeReference(f.Type, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
errret = err
|
||||||
}
|
}
|
||||||
f.TypeReference = tr
|
f.TypeReference = tr
|
||||||
}
|
}
|
||||||
|
if f.TypeReference != nil {
|
||||||
|
dirs, err := b.getDirectives(f.TypeReference.Definition.Directives)
|
||||||
|
if err != nil {
|
||||||
|
errret = err
|
||||||
|
}
|
||||||
|
f.Directives = append(dirs, f.Directives...)
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
f.Stream = obj.Stream
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case f.Name == "__schema":
|
case f.Name == "__schema":
|
||||||
f.GoFieldType = GoFieldMethod
|
f.GoFieldType = GoFieldMethod
|
||||||
@@ -95,6 +105,18 @@ func (b *builder) bindField(obj *Object, f *Field) error {
|
|||||||
f.GoReceiverName = "ec"
|
f.GoReceiverName = "ec"
|
||||||
f.GoFieldName = "introspectType"
|
f.GoFieldName = "introspectType"
|
||||||
return nil
|
return nil
|
||||||
|
case f.Name == "_entities":
|
||||||
|
f.GoFieldType = GoFieldMethod
|
||||||
|
f.GoReceiverName = "ec"
|
||||||
|
f.GoFieldName = "__resolve_entities"
|
||||||
|
f.MethodHasContext = true
|
||||||
|
return nil
|
||||||
|
case f.Name == "_service":
|
||||||
|
f.GoFieldType = GoFieldMethod
|
||||||
|
f.GoReceiverName = "ec"
|
||||||
|
f.GoFieldName = "__resolve__service"
|
||||||
|
f.MethodHasContext = true
|
||||||
|
return nil
|
||||||
case obj.Root:
|
case obj.Root:
|
||||||
f.IsResolver = true
|
f.IsResolver = true
|
||||||
return nil
|
return nil
|
||||||
@@ -181,75 +203,155 @@ func (b *builder) bindField(obj *Object, f *Field) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// findField attempts to match the name to a struct field with the following
|
// findBindTarget attempts to match the name to a field or method on a Type
|
||||||
// priorites:
|
// with the following priorites:
|
||||||
// 1. Any method with a matching name
|
// 1. Any Fields with a struct tag (see config.StructTag). Errors if more than one match is found
|
||||||
// 2. Any Fields with a struct tag (see config.StructTag)
|
// 2. Any method or field with a matching name. Errors if more than one match is found
|
||||||
// 3. Any fields with a matching name
|
// 3. Same logic again for embedded fields
|
||||||
// 4. Same logic again for embedded fields
|
func (b *builder) findBindTarget(t types.Type, name string) (types.Object, error) {
|
||||||
func (b *builder) findBindTarget(named *types.Named, name string) (types.Object, error) {
|
// NOTE: a struct tag will override both methods and fields
|
||||||
for i := 0; i < named.NumMethods(); i++ {
|
// Bind to struct tag
|
||||||
method := named.Method(i)
|
found, err := b.findBindStructTagTarget(t, name)
|
||||||
if !method.Exported() {
|
if found != nil || err != nil {
|
||||||
continue
|
return found, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.EqualFold(method.Name(), name) {
|
// Search for a method to bind to
|
||||||
continue
|
foundMethod, err := b.findBindMethodTarget(t, name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return method, nil
|
// Search for a field to bind to
|
||||||
|
foundField, err := b.findBindFieldTarget(t, name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
strukt, ok := named.Underlying().(*types.Struct)
|
switch {
|
||||||
if !ok {
|
case foundField == nil && foundMethod != nil:
|
||||||
return nil, fmt.Errorf("not a struct")
|
// Bind to method
|
||||||
|
return foundMethod, nil
|
||||||
|
case foundField != nil && foundMethod == nil:
|
||||||
|
// Bind to field
|
||||||
|
return foundField, nil
|
||||||
|
case foundField != nil && foundMethod != nil:
|
||||||
|
// Error
|
||||||
|
return nil, errors.Errorf("found more than one way to bind for %s", name)
|
||||||
}
|
}
|
||||||
return b.findBindStructTarget(strukt, name)
|
|
||||||
|
// Search embeds
|
||||||
|
return b.findBindEmbedsTarget(t, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *builder) findBindStructTarget(strukt *types.Struct, name string) (types.Object, error) {
|
func (b *builder) findBindStructTagTarget(in types.Type, name string) (types.Object, error) {
|
||||||
// struct tags have the highest priority
|
if b.Config.StructTag == "" {
|
||||||
if b.Config.StructTag != "" {
|
return nil, nil
|
||||||
var foundField *types.Var
|
}
|
||||||
for i := 0; i < strukt.NumFields(); i++ {
|
|
||||||
field := strukt.Field(i)
|
switch t := in.(type) {
|
||||||
if !field.Exported() {
|
case *types.Named:
|
||||||
|
return b.findBindStructTagTarget(t.Underlying(), name)
|
||||||
|
case *types.Struct:
|
||||||
|
var found types.Object
|
||||||
|
for i := 0; i < t.NumFields(); i++ {
|
||||||
|
field := t.Field(i)
|
||||||
|
if !field.Exported() || field.Embedded() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
tags := reflect.StructTag(strukt.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 foundField != 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, errors.Errorf("tag %s is ambigious; multiple fields have the same tag value of %s", b.Config.StructTag, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
foundField = field
|
found = field
|
||||||
}
|
|
||||||
}
|
|
||||||
if foundField != nil {
|
|
||||||
return foundField, nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then matching field names
|
return found, nil
|
||||||
for i := 0; i < strukt.NumFields(); i++ {
|
|
||||||
field := strukt.Field(i)
|
|
||||||
if !field.Exported() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if equalFieldName(field.Name(), name) { // aqui!
|
|
||||||
return field, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then look in embedded structs
|
return nil, nil
|
||||||
for i := 0; i < strukt.NumFields(); i++ {
|
}
|
||||||
field := strukt.Field(i)
|
|
||||||
if !field.Exported() {
|
func (b *builder) findBindMethodTarget(in types.Type, name string) (types.Object, error) {
|
||||||
|
switch t := in.(type) {
|
||||||
|
case *types.Named:
|
||||||
|
if _, ok := t.Underlying().(*types.Interface); ok {
|
||||||
|
return b.findBindMethodTarget(t.Underlying(), name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.findBindMethoderTarget(t.Method, t.NumMethods(), name)
|
||||||
|
case *types.Interface:
|
||||||
|
// FIX-ME: Should use ExplicitMethod here? What's the difference?
|
||||||
|
return b.findBindMethoderTarget(t.Method, t.NumMethods(), name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *builder) findBindMethoderTarget(methodFunc func(i int) *types.Func, methodCount int, name string) (types.Object, error) {
|
||||||
|
var found types.Object
|
||||||
|
for i := 0; i < methodCount; i++ {
|
||||||
|
method := methodFunc(i)
|
||||||
|
if !method.Exported() || !strings.EqualFold(method.Name(), name) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !field.Anonymous() {
|
if found != nil {
|
||||||
|
return nil, errors.Errorf("found more than one matching method to bind for %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
found = method
|
||||||
|
}
|
||||||
|
|
||||||
|
return found, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *builder) findBindFieldTarget(in types.Type, name string) (types.Object, error) {
|
||||||
|
switch t := in.(type) {
|
||||||
|
case *types.Named:
|
||||||
|
return b.findBindFieldTarget(t.Underlying(), name)
|
||||||
|
case *types.Struct:
|
||||||
|
var found types.Object
|
||||||
|
for i := 0; i < t.NumFields(); i++ {
|
||||||
|
field := t.Field(i)
|
||||||
|
if !field.Exported() || !equalFieldName(field.Name(), name) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if found != nil {
|
||||||
|
return nil, errors.Errorf("found more than one matching field to bind for %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
found = field
|
||||||
|
}
|
||||||
|
|
||||||
|
return found, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *builder) findBindEmbedsTarget(in types.Type, name string) (types.Object, error) {
|
||||||
|
switch t := in.(type) {
|
||||||
|
case *types.Named:
|
||||||
|
return b.findBindEmbedsTarget(t.Underlying(), name)
|
||||||
|
case *types.Struct:
|
||||||
|
return b.findBindStructEmbedsTarget(t, name)
|
||||||
|
case *types.Interface:
|
||||||
|
return b.findBindInterfaceEmbedsTarget(t, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *builder) findBindStructEmbedsTarget(strukt *types.Struct, name string) (types.Object, error) {
|
||||||
|
var found types.Object
|
||||||
|
for i := 0; i < strukt.NumFields(); i++ {
|
||||||
|
field := strukt.Field(i)
|
||||||
|
if !field.Embedded() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,33 +360,68 @@ func (b *builder) findBindStructTarget(strukt *types.Struct, name string) (types
|
|||||||
fieldType = ptr.Elem()
|
fieldType = ptr.Elem()
|
||||||
}
|
}
|
||||||
|
|
||||||
switch fieldType := fieldType.(type) {
|
|
||||||
case *types.Named:
|
|
||||||
f, err := b.findBindTarget(fieldType, name)
|
f, err := b.findBindTarget(fieldType, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if f != nil {
|
|
||||||
return f, nil
|
if f != nil && found != nil {
|
||||||
|
return nil, errors.Errorf("found more than one way to bind for %s", name)
|
||||||
}
|
}
|
||||||
case *types.Struct:
|
|
||||||
f, err := b.findBindStructTarget(fieldType, name)
|
if f != nil {
|
||||||
|
found = f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return found, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *builder) findBindInterfaceEmbedsTarget(iface *types.Interface, name string) (types.Object, error) {
|
||||||
|
var found types.Object
|
||||||
|
for i := 0; i < iface.NumEmbeddeds(); i++ {
|
||||||
|
embeddedType := iface.EmbeddedType(i)
|
||||||
|
|
||||||
|
f, err := b.findBindTarget(embeddedType, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if f != nil {
|
|
||||||
return f, nil
|
if f != nil && found != nil {
|
||||||
|
return nil, errors.Errorf("found more than one way to bind for %s", name)
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
panic(fmt.Errorf("unknown embedded field type %T", field.Type()))
|
if f != nil {
|
||||||
|
found = f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return found, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Field) HasDirectives() bool {
|
func (f *Field) HasDirectives() bool {
|
||||||
return len(f.Directives) > 0
|
return len(f.ImplDirectives()) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Field) DirectiveObjName() string {
|
||||||
|
if f.Object.Root {
|
||||||
|
return "nil"
|
||||||
|
}
|
||||||
|
return f.GoReceiverName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Field) ImplDirectives() []*Directive {
|
||||||
|
var d []*Directive
|
||||||
|
loc := ast.LocationFieldDefinition
|
||||||
|
if f.Object.IsInputType() {
|
||||||
|
loc = ast.LocationInputFieldDefinition
|
||||||
|
}
|
||||||
|
for i := range f.Directives {
|
||||||
|
if !f.Directives[i].Builtin && f.Directives[i].IsLocation(loc, ast.LocationObject) {
|
||||||
|
d = append(d, f.Directives[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Field) IsReserved() bool {
|
func (f *Field) IsReserved() bool {
|
||||||
@@ -338,7 +475,7 @@ func (f *Field) ShortResolverDeclaration() string {
|
|||||||
res := "(ctx context.Context"
|
res := "(ctx context.Context"
|
||||||
|
|
||||||
if !f.Object.Root {
|
if !f.Object.Root {
|
||||||
res += fmt.Sprintf(", obj *%s", templates.CurrentImports.LookupType(f.Object.Type))
|
res += fmt.Sprintf(", obj %s", templates.CurrentImports.LookupType(f.Object.Reference()))
|
||||||
}
|
}
|
||||||
for _, arg := range f.Args {
|
for _, arg := range f.Args {
|
||||||
res += fmt.Sprintf(", %s %s", arg.VarName, templates.CurrentImports.LookupType(arg.TypeReference.GO))
|
res += fmt.Sprintf(", %s %s", arg.VarName, templates.CurrentImports.LookupType(arg.TypeReference.GO))
|
||||||
@@ -354,7 +491,7 @@ func (f *Field) ShortResolverDeclaration() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *Field) ComplexitySignature() string {
|
func (f *Field) ComplexitySignature() string {
|
||||||
res := fmt.Sprintf("func(childComplexity int")
|
res := "func(childComplexity int"
|
||||||
for _, arg := range f.Args {
|
for _, arg := range f.Args {
|
||||||
res += fmt.Sprintf(", %s %s", arg.VarName, templates.CurrentImports.LookupType(arg.TypeReference.GO))
|
res += fmt.Sprintf(", %s %s", arg.VarName, templates.CurrentImports.LookupType(arg.TypeReference.GO))
|
||||||
}
|
}
|
||||||
@@ -363,16 +500,16 @@ func (f *Field) ComplexitySignature() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *Field) ComplexityArgs() string {
|
func (f *Field) ComplexityArgs() string {
|
||||||
var args []string
|
args := make([]string, len(f.Args))
|
||||||
for _, arg := range f.Args {
|
for i, arg := range f.Args {
|
||||||
args = append(args, "args["+strconv.Quote(arg.Name)+"].("+templates.CurrentImports.LookupType(arg.TypeReference.GO)+")")
|
args[i] = "args[" + strconv.Quote(arg.Name) + "].(" + templates.CurrentImports.LookupType(arg.TypeReference.GO) + ")"
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(args, ", ")
|
return strings.Join(args, ", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Field) CallArgs() string {
|
func (f *Field) CallArgs() string {
|
||||||
var args []string
|
args := make([]string, 0, len(f.Args)+2)
|
||||||
|
|
||||||
if f.IsResolver {
|
if f.IsResolver {
|
||||||
args = append(args, "rctx")
|
args = append(args, "rctx")
|
||||||
@@ -380,11 +517,9 @@ func (f *Field) CallArgs() string {
|
|||||||
if !f.Object.Root {
|
if !f.Object.Root {
|
||||||
args = append(args, "obj")
|
args = append(args, "obj")
|
||||||
}
|
}
|
||||||
} else {
|
} else if f.MethodHasContext {
|
||||||
if f.MethodHasContext {
|
|
||||||
args = append(args, "ctx")
|
args = append(args, "ctx")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for _, arg := range f.Args {
|
for _, arg := range f.Args {
|
||||||
args = append(args, "args["+strconv.Quote(arg.Name)+"].("+templates.CurrentImports.LookupType(arg.TypeReference.GO)+")")
|
args = append(args, "args["+strconv.Quote(arg.Name)+"].("+templates.CurrentImports.LookupType(arg.TypeReference.GO)+")")
|
||||||
|
|||||||
160
vendor/github.com/99designs/gqlgen/codegen/field.gotpl
generated
vendored
160
vendor/github.com/99designs/gqlgen/codegen/field.gotpl
generated
vendored
@@ -1,29 +1,57 @@
|
|||||||
{{- range $object := .Objects }}{{- range $field := $object.Fields }}
|
{{- range $object := .Objects }}{{- range $field := $object.Fields }}
|
||||||
|
|
||||||
{{- if $object.Stream }}
|
func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Context, field graphql.CollectedField{{ if not $object.Root }}, obj {{$object.Reference | ref}}{{end}}) (ret {{ if $object.Stream }}func(){{ end }}graphql.Marshaler) {
|
||||||
func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Context, field graphql.CollectedField) func() graphql.Marshaler {
|
{{- $null := "graphql.Null" }}
|
||||||
ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{
|
{{- if $object.Stream }}
|
||||||
|
{{- $null = "nil" }}
|
||||||
|
{{- end }}
|
||||||
|
defer func () {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
ret = {{ $null }}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
fc := &graphql.FieldContext{
|
||||||
|
Object: {{$object.Name|quote}},
|
||||||
Field: field,
|
Field: field,
|
||||||
Args: nil,
|
Args: nil,
|
||||||
})
|
IsMethod: {{or $field.IsMethod $field.IsResolver}},
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithFieldContext(ctx, fc)
|
||||||
{{- if $field.Args }}
|
{{- if $field.Args }}
|
||||||
rawArgs := field.ArgumentMap(ec.Variables)
|
rawArgs := field.ArgumentMap(ec.Variables)
|
||||||
args, err := ec.{{ $field.ArgsFunc }}(ctx,rawArgs)
|
args, err := ec.{{ $field.ArgsFunc }}(ctx,rawArgs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ec.Error(ctx, err)
|
ec.Error(ctx, err)
|
||||||
return nil
|
return {{ $null }}
|
||||||
}
|
}
|
||||||
|
fc.Args = args
|
||||||
{{- end }}
|
{{- end }}
|
||||||
// FIXME: subscriptions are missing request middleware stack https://github.com/99designs/gqlgen/issues/259
|
{{- if $.Directives.LocationDirectives "FIELD" }}
|
||||||
// and Tracer stack
|
resTmp := ec._fieldMiddleware(ctx, {{if $object.Root}}nil{{else}}obj{{end}}, func(rctx context.Context) (interface{}, error) {
|
||||||
rctx := ctx
|
{{ template "field" $field }}
|
||||||
results, err := ec.resolvers.{{ $field.ShortInvocation }}
|
})
|
||||||
|
{{ else }}
|
||||||
|
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
|
||||||
|
{{ template "field" $field }}
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ec.Error(ctx, err)
|
ec.Error(ctx, err)
|
||||||
return nil
|
return {{ $null }}
|
||||||
}
|
}
|
||||||
|
{{- end }}
|
||||||
|
if resTmp == nil {
|
||||||
|
{{- if $field.TypeReference.GQL.NonNull }}
|
||||||
|
if !graphql.HasFieldError(ctx, fc) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
return {{ $null }}
|
||||||
|
}
|
||||||
|
{{- if $object.Stream }}
|
||||||
return func() graphql.Marshaler {
|
return func() graphql.Marshaler {
|
||||||
res, ok := <-results
|
res, ok := <-resTmp.(<-chan {{$field.TypeReference.GO | ref}})
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -35,66 +63,60 @@
|
|||||||
w.Write([]byte{'}'})
|
w.Write([]byte{'}'})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
{{ else }}
|
|
||||||
func (ec *executionContext) _{{$object.Name}}_{{$field.Name}}(ctx context.Context, field graphql.CollectedField{{ if not $object.Root }}, obj {{$object.Reference | ref}}{{end}}) graphql.Marshaler {
|
|
||||||
ctx = ec.Tracer.StartFieldExecution(ctx, field)
|
|
||||||
defer func () { ec.Tracer.EndFieldExecution(ctx) }()
|
|
||||||
rctx := &graphql.ResolverContext{
|
|
||||||
Object: {{$object.Name|quote}},
|
|
||||||
Field: field,
|
|
||||||
Args: nil,
|
|
||||||
IsMethod: {{or $field.IsMethod $field.IsResolver}},
|
|
||||||
}
|
|
||||||
ctx = graphql.WithResolverContext(ctx, rctx)
|
|
||||||
{{- if $field.Args }}
|
|
||||||
rawArgs := field.ArgumentMap(ec.Variables)
|
|
||||||
args, err := ec.{{ $field.ArgsFunc }}(ctx,rawArgs)
|
|
||||||
if err != nil {
|
|
||||||
ec.Error(ctx, err)
|
|
||||||
return graphql.Null
|
|
||||||
}
|
|
||||||
rctx.Args = args
|
|
||||||
{{- end }}
|
|
||||||
ctx = ec.Tracer.StartFieldResolverExecution(ctx, rctx)
|
|
||||||
resTmp := ec.FieldMiddleware(ctx, {{if $object.Root}}nil{{else}}obj{{end}}, func(rctx context.Context) (interface{}, error) {
|
|
||||||
ctx = rctx // use context from middleware stack in children
|
|
||||||
{{- if $field.IsResolver }}
|
|
||||||
return ec.resolvers.{{ $field.ShortInvocation }}
|
|
||||||
{{- else if $field.IsMap }}
|
|
||||||
switch v := {{$field.GoReceiverName}}[{{$field.Name|quote}}].(type) {
|
|
||||||
case {{$field.TypeReference.GO | ref}}:
|
|
||||||
return v, nil
|
|
||||||
case {{$field.TypeReference.Elem.GO | ref}}:
|
|
||||||
return &v, nil
|
|
||||||
case nil:
|
|
||||||
return ({{$field.TypeReference.GO | ref}})(nil), nil
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unexpected type %T for field %s", v, {{ $field.Name | quote}})
|
|
||||||
}
|
|
||||||
{{- else if $field.IsMethod }}
|
|
||||||
{{- if $field.NoErr }}
|
|
||||||
return {{$field.GoReceiverName}}.{{$field.GoFieldName}}({{ $field.CallArgs }}), nil
|
|
||||||
{{- else }}
|
{{- else }}
|
||||||
return {{$field.GoReceiverName}}.{{$field.GoFieldName}}({{ $field.CallArgs }})
|
|
||||||
{{- end }}
|
|
||||||
{{- else if $field.IsVariable }}
|
|
||||||
return {{$field.GoReceiverName}}.{{$field.GoFieldName}}, nil
|
|
||||||
{{- end }}
|
|
||||||
})
|
|
||||||
if resTmp == nil {
|
|
||||||
{{- if $field.TypeReference.GQL.NonNull }}
|
|
||||||
if !ec.HasError(rctx) {
|
|
||||||
ec.Errorf(ctx, "must not be null")
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
return graphql.Null
|
|
||||||
}
|
|
||||||
res := resTmp.({{$field.TypeReference.GO | ref}})
|
res := resTmp.({{$field.TypeReference.GO | ref}})
|
||||||
rctx.Result = res
|
fc.Result = res
|
||||||
ctx = ec.Tracer.StartFieldChildExecution(ctx)
|
|
||||||
return ec.{{ $field.TypeReference.MarshalFunc }}(ctx, field.Selections, res)
|
return ec.{{ $field.TypeReference.MarshalFunc }}(ctx, field.Selections, res)
|
||||||
}
|
{{- end }}
|
||||||
{{ end }}
|
}
|
||||||
|
|
||||||
{{- end }}{{- end}}
|
{{- end }}{{- end}}
|
||||||
|
|
||||||
|
{{ define "field" }}
|
||||||
|
{{- if .HasDirectives -}}
|
||||||
|
directive0 := func(rctx context.Context) (interface{}, error) {
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
{{ template "fieldDefinition" . }}
|
||||||
|
}
|
||||||
|
{{ template "implDirectives" . }}
|
||||||
|
tmp, err := directive{{.ImplDirectives|len}}(rctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if tmp == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if data, ok := tmp.({{if .Stream}}<-chan {{end}}{{ .TypeReference.GO | ref }}) ; ok {
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf(`unexpected type %T from directive, should be {{if .Stream}}<-chan {{end}}{{ .TypeReference.GO }}`, tmp)
|
||||||
|
{{- else -}}
|
||||||
|
ctx = rctx // use context from middleware stack in children
|
||||||
|
{{ template "fieldDefinition" . }}
|
||||||
|
{{- end -}}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ define "fieldDefinition" }}
|
||||||
|
{{- if .IsResolver -}}
|
||||||
|
return ec.resolvers.{{ .ShortInvocation }}
|
||||||
|
{{- else if .IsMap -}}
|
||||||
|
switch v := {{.GoReceiverName}}[{{.Name|quote}}].(type) {
|
||||||
|
case {{if .Stream}}<-chan {{end}}{{.TypeReference.GO | ref}}:
|
||||||
|
return v, nil
|
||||||
|
case {{if .Stream}}<-chan {{end}}{{.TypeReference.Elem.GO | ref}}:
|
||||||
|
return &v, nil
|
||||||
|
case nil:
|
||||||
|
return ({{.TypeReference.GO | ref}})(nil), nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unexpected type %T for field %s", v, {{ .Name | quote}})
|
||||||
|
}
|
||||||
|
{{- else if .IsMethod -}}
|
||||||
|
{{- if .NoErr -}}
|
||||||
|
return {{.GoReceiverName}}.{{.GoFieldName}}({{ .CallArgs }}), nil
|
||||||
|
{{- else -}}
|
||||||
|
return {{.GoReceiverName}}.{{.GoFieldName}}({{ .CallArgs }})
|
||||||
|
{{- end -}}
|
||||||
|
{{- else if .IsVariable -}}
|
||||||
|
return {{.GoReceiverName}}.{{.GoFieldName}}, nil
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|||||||
1
vendor/github.com/99designs/gqlgen/codegen/generate.go
generated
vendored
1
vendor/github.com/99designs/gqlgen/codegen/generate.go
generated
vendored
@@ -11,5 +11,6 @@ func GenerateCode(data *Data) error {
|
|||||||
Data: data,
|
Data: data,
|
||||||
RegionTags: true,
|
RegionTags: true,
|
||||||
GeneratedHeader: true,
|
GeneratedHeader: true,
|
||||||
|
Packages: data.Config.Packages,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
156
vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl
generated
vendored
156
vendor/github.com/99designs/gqlgen/codegen/generated!.gotpl
generated
vendored
@@ -8,8 +8,8 @@
|
|||||||
{{ reserveImport "errors" }}
|
{{ reserveImport "errors" }}
|
||||||
{{ reserveImport "bytes" }}
|
{{ reserveImport "bytes" }}
|
||||||
|
|
||||||
{{ reserveImport "github.com/vektah/gqlparser" }}
|
{{ reserveImport "github.com/vektah/gqlparser/v2" "gqlparser" }}
|
||||||
{{ reserveImport "github.com/vektah/gqlparser/ast" }}
|
{{ reserveImport "github.com/vektah/gqlparser/v2/ast" }}
|
||||||
{{ reserveImport "github.com/99designs/gqlgen/graphql" }}
|
{{ reserveImport "github.com/99designs/gqlgen/graphql" }}
|
||||||
{{ reserveImport "github.com/99designs/gqlgen/graphql/introspection" }}
|
{{ reserveImport "github.com/99designs/gqlgen/graphql/introspection" }}
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ type ResolverRoot interface {
|
|||||||
|
|
||||||
type DirectiveRoot struct {
|
type DirectiveRoot struct {
|
||||||
{{ range $directive := .Directives }}
|
{{ range $directive := .Directives }}
|
||||||
{{ $directive.Declaration }}
|
{{- $directive.Declaration }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,60 +112,63 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
|
|||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *executableSchema) Query(ctx context.Context, op *ast.OperationDefinition) *graphql.Response {
|
func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
|
||||||
{{- if .QueryRoot }}
|
rc := graphql.GetOperationContext(ctx)
|
||||||
ec := executionContext{graphql.GetRequestContext(ctx), e}
|
ec := executionContext{rc, e}
|
||||||
|
first := true
|
||||||
|
|
||||||
buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte {
|
switch rc.Operation.Operation {
|
||||||
data := ec._{{.QueryRoot.Name}}(ctx, op.SelectionSet)
|
{{- 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
|
var buf bytes.Buffer
|
||||||
data.MarshalGQL(&buf)
|
data.MarshalGQL(&buf)
|
||||||
return buf.Bytes()
|
|
||||||
})
|
|
||||||
|
|
||||||
return &graphql.Response{
|
return &graphql.Response{
|
||||||
Data: buf,
|
Data: buf.Bytes(),
|
||||||
Errors: ec.Errors,
|
|
||||||
Extensions: ec.Extensions,
|
|
||||||
}
|
}
|
||||||
{{- else }}
|
}
|
||||||
return graphql.ErrorResponse(ctx, "queries are not supported")
|
{{ 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 }}
|
{{- end }}
|
||||||
}
|
|
||||||
|
|
||||||
func (e *executableSchema) Mutation(ctx context.Context, op *ast.OperationDefinition) *graphql.Response {
|
|
||||||
{{- if .MutationRoot }}
|
|
||||||
ec := executionContext{graphql.GetRequestContext(ctx), e}
|
|
||||||
|
|
||||||
buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte {
|
|
||||||
data := ec._{{.MutationRoot.Name}}(ctx, op.SelectionSet)
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
data.MarshalGQL(&buf)
|
data.MarshalGQL(&buf)
|
||||||
return buf.Bytes()
|
|
||||||
})
|
|
||||||
|
|
||||||
return &graphql.Response{
|
return &graphql.Response{
|
||||||
Data: buf,
|
Data: buf.Bytes(),
|
||||||
Errors: ec.Errors,
|
|
||||||
Extensions: ec.Extensions,
|
|
||||||
}
|
}
|
||||||
{{- else }}
|
}
|
||||||
return graphql.ErrorResponse(ctx, "mutations are not supported")
|
{{ 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 }}
|
{{- end }}
|
||||||
}
|
|
||||||
|
|
||||||
func (e *executableSchema) Subscription(ctx context.Context, op *ast.OperationDefinition) func() *graphql.Response {
|
|
||||||
{{- if .SubscriptionRoot }}
|
|
||||||
ec := executionContext{graphql.GetRequestContext(ctx), e}
|
|
||||||
|
|
||||||
next := ec._{{.SubscriptionRoot.Name}}(ctx, op.SelectionSet)
|
|
||||||
if ec.Errors != nil {
|
|
||||||
return graphql.OneShot(&graphql.Response{Data: []byte("null"), Errors: ec.Errors})
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
return func() *graphql.Response {
|
return func(ctx context.Context) *graphql.Response {
|
||||||
buf := ec.RequestMiddleware(ctx, func(ctx context.Context) []byte {
|
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
data := next()
|
data := next()
|
||||||
|
|
||||||
@@ -173,68 +176,22 @@ func (e *executableSchema) Subscription(ctx context.Context, op *ast.OperationDe
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
data.MarshalGQL(&buf)
|
data.MarshalGQL(&buf)
|
||||||
return buf.Bytes()
|
|
||||||
})
|
|
||||||
|
|
||||||
if buf == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &graphql.Response{
|
return &graphql.Response{
|
||||||
Data: buf,
|
Data: buf.Bytes(),
|
||||||
Errors: ec.Errors,
|
|
||||||
Extensions: ec.Extensions,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{{- else }}
|
{{ end }}
|
||||||
return graphql.OneShot(graphql.ErrorResponse(ctx, "subscriptions are not supported"))
|
default:
|
||||||
{{- end }}
|
return graphql.OneShot(graphql.ErrorResponse(ctx, "unsupported GraphQL operation"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type executionContext struct {
|
type executionContext struct {
|
||||||
*graphql.RequestContext
|
*graphql.OperationContext
|
||||||
*executableSchema
|
*executableSchema
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) FieldMiddleware(ctx context.Context, obj interface{}, next graphql.Resolver) (ret interface{}) {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
ec.Error(ctx, ec.Recover(ctx, r))
|
|
||||||
ret = nil
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
{{- if .Directives }}
|
|
||||||
rctx := graphql.GetResolverContext(ctx)
|
|
||||||
for _, d := range rctx.Field.Definition.Directives {
|
|
||||||
switch d.Name {
|
|
||||||
{{- range $directive := .Directives }}
|
|
||||||
case "{{$directive.Name}}":
|
|
||||||
if ec.directives.{{$directive.Name|ucFirst}} != nil {
|
|
||||||
{{- if $directive.Args }}
|
|
||||||
rawArgs := d.ArgumentMap(ec.Variables)
|
|
||||||
args, err := ec.{{ $directive.ArgsFunc }}(ctx,rawArgs)
|
|
||||||
if err != nil {
|
|
||||||
ec.Error(ctx, err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
n := next
|
|
||||||
next = func(ctx context.Context) (interface{}, error) {
|
|
||||||
return ec.directives.{{$directive.Name|ucFirst}}({{$directive.CallArgs}})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
res, err := ec.ResolverMiddleware(ctx, next)
|
|
||||||
if err != nil {
|
|
||||||
ec.Error(ctx, err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
|
func (ec *executionContext) introspectSchema() (*introspection.Schema, error) {
|
||||||
if ec.DisableIntrospection {
|
if ec.DisableIntrospection {
|
||||||
return nil, errors.New("introspection disabled")
|
return nil, errors.New("introspection disabled")
|
||||||
@@ -249,8 +206,9 @@ func (ec *executionContext) introspectType(name string) (*introspection.Type, er
|
|||||||
return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
|
return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var parsedSchema = gqlparser.MustLoadSchema(
|
var sources = []*ast.Source{
|
||||||
{{- range $filename, $schema := .SchemaStr }}
|
{{- range $source := .Config.Sources }}
|
||||||
&ast.Source{Name: {{$filename|quote}}, Input: {{$schema|rawQuote}}},
|
{Name: {{$source.Name|quote}}, Input: {{$source.Input|rawQuote}}, BuiltIn: {{$source.BuiltIn}}},
|
||||||
{{- end }}
|
{{- end }}
|
||||||
)
|
}
|
||||||
|
var parsedSchema = gqlparser.MustLoadSchema(sources...)
|
||||||
|
|||||||
28
vendor/github.com/99designs/gqlgen/codegen/input.gotpl
generated
vendored
28
vendor/github.com/99designs/gqlgen/codegen/input.gotpl
generated
vendored
@@ -1,8 +1,8 @@
|
|||||||
{{- range $input := .Inputs }}
|
{{- range $input := .Inputs }}
|
||||||
{{- if not .HasUnmarshal }}
|
{{- if not .HasUnmarshal }}
|
||||||
func (ec *executionContext) unmarshalInput{{ .Name }}(ctx context.Context, v interface{}) ({{.Type | ref}}, error) {
|
func (ec *executionContext) unmarshalInput{{ .Name }}(ctx context.Context, obj interface{}) ({{.Type | ref}}, error) {
|
||||||
var it {{.Type | ref}}
|
var it {{.Type | ref}}
|
||||||
var asMap = v.(map[string]interface{})
|
var asMap = obj.(map[string]interface{})
|
||||||
{{ range $field := .Fields}}
|
{{ range $field := .Fields}}
|
||||||
{{- if $field.Default}}
|
{{- if $field.Default}}
|
||||||
if _, present := asMap[{{$field.Name|quote}}] ; !present {
|
if _, present := asMap[{{$field.Name|quote}}] ; !present {
|
||||||
@@ -16,27 +16,21 @@
|
|||||||
{{- range $field := .Fields }}
|
{{- range $field := .Fields }}
|
||||||
case {{$field.Name|quote}}:
|
case {{$field.Name|quote}}:
|
||||||
var err error
|
var err error
|
||||||
{{- if $field.Directives }}
|
|
||||||
getField0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $field.TypeReference.UnmarshalFunc }}(ctx, v) }
|
|
||||||
|
|
||||||
{{- range $i, $directive := $field.Directives }}
|
ctx := graphql.WithFieldInputContext(ctx, graphql.NewFieldInputWithField({{$field.Name|quote}}))
|
||||||
getField{{add $i 1}} := func(ctx context.Context) (res interface{}, err error) {
|
{{- if $field.ImplDirectives }}
|
||||||
{{- range $dArg := $directive.Args }}
|
directive0 := func(ctx context.Context) (interface{}, error) { return ec.{{ $field.TypeReference.UnmarshalFunc }}(ctx, v) }
|
||||||
{{- if and $dArg.TypeReference.IsPtr ( notNil "Value" $dArg ) }}
|
{{ template "implDirectives" $field }}
|
||||||
{{ $dArg.VarName }} := {{ $dArg.Value | dump }}
|
tmp, err := directive{{$field.ImplDirectives|len}}(ctx)
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
n := getField{{$i}}
|
|
||||||
return ec.directives.{{$directive.Name|ucFirst}}({{$directive.ResolveArgs "it" "n" }})
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
tmp, err := getField{{$field.Directives|len}}(ctx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return it, err
|
return it, err
|
||||||
}
|
}
|
||||||
if data, ok := tmp.({{ $field.TypeReference.GO | ref }}) ; ok {
|
if data, ok := tmp.({{ $field.TypeReference.GO | ref }}) ; ok {
|
||||||
it.{{$field.GoFieldName}} = data
|
it.{{$field.GoFieldName}} = data
|
||||||
|
{{- if $field.TypeReference.IsNilable }}
|
||||||
|
} else if tmp == nil {
|
||||||
|
it.{{$field.GoFieldName}} = nil
|
||||||
|
{{- end }}
|
||||||
} else {
|
} else {
|
||||||
return it, fmt.Errorf(`unexpected type %T from directive, should be {{ $field.TypeReference.GO }}`, tmp)
|
return it, fmt.Errorf(`unexpected type %T from directive, should be {{ $field.TypeReference.GO }}`, tmp)
|
||||||
}
|
}
|
||||||
|
|||||||
61
vendor/github.com/99designs/gqlgen/codegen/interface.go
generated
vendored
61
vendor/github.com/99designs/gqlgen/codegen/interface.go
generated
vendored
@@ -1,9 +1,13 @@
|
|||||||
package codegen
|
package codegen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"go/types"
|
"go/types"
|
||||||
|
|
||||||
"github.com/vektah/gqlparser/ast"
|
"github.com/pkg/errors"
|
||||||
|
"github.com/vektah/gqlparser/v2/ast"
|
||||||
|
|
||||||
|
"github.com/99designs/gqlgen/codegen/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Interface struct {
|
type Interface struct {
|
||||||
@@ -16,11 +20,11 @@ type Interface struct {
|
|||||||
type InterfaceImplementor struct {
|
type InterfaceImplementor struct {
|
||||||
*ast.Definition
|
*ast.Definition
|
||||||
|
|
||||||
Interface *Interface
|
|
||||||
Type types.Type
|
Type types.Type
|
||||||
|
TakeRef bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *builder) buildInterface(typ *ast.Definition) *Interface {
|
func (b *builder) buildInterface(typ *ast.Definition) (*Interface, error) {
|
||||||
obj, err := b.Binder.DefaultUserObject(typ.Name)
|
obj, err := b.Binder.DefaultUserObject(typ.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -32,32 +36,53 @@ func (b *builder) buildInterface(typ *ast.Definition) *Interface {
|
|||||||
InTypemap: b.Config.Models.UserDefined(typ.Name),
|
InTypemap: b.Config.Models.UserDefined(typ.Name),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interfaceType, err := findGoInterface(i.Type)
|
||||||
|
if interfaceType == nil || err != nil {
|
||||||
|
return nil, fmt.Errorf("%s is not an interface", i.Type)
|
||||||
|
}
|
||||||
|
|
||||||
for _, implementor := range b.Schema.GetPossibleTypes(typ) {
|
for _, implementor := range b.Schema.GetPossibleTypes(typ) {
|
||||||
obj, err := b.Binder.DefaultUserObject(implementor.Name)
|
obj, err := b.Binder.DefaultUserObject(implementor.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return nil, fmt.Errorf("%s has no backing go type", implementor.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
implementorType, err := findGoNamedType(obj)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "can not find backing go type %s", obj.String())
|
||||||
|
} else if implementorType == nil {
|
||||||
|
return nil, fmt.Errorf("can not find backing go type %s", obj.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
anyValid := false
|
||||||
|
|
||||||
|
// first check if the value receiver can be nil, eg can we type switch on case Thing:
|
||||||
|
if types.Implements(implementorType, interfaceType) {
|
||||||
i.Implementors = append(i.Implementors, InterfaceImplementor{
|
i.Implementors = append(i.Implementors, InterfaceImplementor{
|
||||||
Definition: implementor,
|
Definition: implementor,
|
||||||
Type: obj,
|
Type: obj,
|
||||||
Interface: i,
|
TakeRef: !types.IsInterface(obj),
|
||||||
})
|
})
|
||||||
|
anyValid = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return i
|
// then check if the pointer receiver can be nil, eg can we type switch on case *Thing:
|
||||||
|
if types.Implements(types.NewPointer(implementorType), interfaceType) {
|
||||||
|
i.Implementors = append(i.Implementors, InterfaceImplementor{
|
||||||
|
Definition: implementor,
|
||||||
|
Type: types.NewPointer(obj),
|
||||||
|
})
|
||||||
|
anyValid = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if !anyValid {
|
||||||
|
return nil, fmt.Errorf("%s does not satisfy the interface %s", implementorType.String(), i.Type.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return i, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *InterfaceImplementor) ValueReceiver() bool {
|
func (i *InterfaceImplementor) CanBeNil() bool {
|
||||||
interfaceType, err := findGoInterface(i.Interface.Type)
|
return config.IsNilable(i.Type)
|
||||||
if interfaceType == nil || err != nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
implementorType, err := findGoNamedType(i.Type)
|
|
||||||
if implementorType == nil || err != nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return types.Implements(implementorType, interfaceType)
|
|
||||||
}
|
}
|
||||||
|
|||||||
15
vendor/github.com/99designs/gqlgen/codegen/interface.gotpl
generated
vendored
15
vendor/github.com/99designs/gqlgen/codegen/interface.gotpl
generated
vendored
@@ -1,16 +1,17 @@
|
|||||||
{{- range $interface := .Interfaces }}
|
{{- range $interface := .Interfaces }}
|
||||||
|
|
||||||
func (ec *executionContext) _{{$interface.Name}}(ctx context.Context, sel ast.SelectionSet, obj *{{$interface.Type | ref}}) graphql.Marshaler {
|
func (ec *executionContext) _{{$interface.Name}}(ctx context.Context, sel ast.SelectionSet, obj {{$interface.Type | ref}}) graphql.Marshaler {
|
||||||
switch obj := (*obj).(type) {
|
switch obj := (obj).(type) {
|
||||||
case nil:
|
case nil:
|
||||||
return graphql.Null
|
return graphql.Null
|
||||||
{{- range $implementor := $interface.Implementors }}
|
{{- range $implementor := $interface.Implementors }}
|
||||||
{{- if $implementor.ValueReceiver }}
|
|
||||||
case {{$implementor.Type | ref}}:
|
case {{$implementor.Type | ref}}:
|
||||||
return ec._{{$implementor.Name}}(ctx, sel, &obj)
|
{{- if $implementor.CanBeNil }}
|
||||||
{{- end}}
|
if obj == nil {
|
||||||
case *{{$implementor.Type | ref}}:
|
return graphql.Null
|
||||||
return ec._{{$implementor.Name}}(ctx, sel, obj)
|
}
|
||||||
|
{{- end }}
|
||||||
|
return ec._{{$implementor.Name}}(ctx, sel, {{ if $implementor.TakeRef }}&{{ end }}obj)
|
||||||
{{- end }}
|
{{- end }}
|
||||||
default:
|
default:
|
||||||
panic(fmt.Errorf("unexpected type %T", obj))
|
panic(fmt.Errorf("unexpected type %T", obj))
|
||||||
|
|||||||
9
vendor/github.com/99designs/gqlgen/codegen/object.go
generated
vendored
9
vendor/github.com/99designs/gqlgen/codegen/object.go
generated
vendored
@@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/99designs/gqlgen/codegen/config"
|
"github.com/99designs/gqlgen/codegen/config"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/vektah/gqlparser/ast"
|
"github.com/vektah/gqlparser/v2/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GoFieldType int
|
type GoFieldType int
|
||||||
@@ -82,11 +82,9 @@ func (b *builder) buildObject(typ *ast.Definition) (*Object, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (o *Object) Reference() types.Type {
|
func (o *Object) Reference() types.Type {
|
||||||
switch o.Type.(type) {
|
if config.IsNilable(o.Type) {
|
||||||
case *types.Pointer, *types.Slice, *types.Map:
|
|
||||||
return o.Type
|
return o.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
return types.NewPointer(o.Type)
|
return types.NewPointer(o.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,8 +112,7 @@ func (o *Object) HasUnmarshal() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
for i := 0; i < o.Type.(*types.Named).NumMethods(); i++ {
|
for i := 0; i < o.Type.(*types.Named).NumMethods(); i++ {
|
||||||
switch o.Type.(*types.Named).Method(i).Name() {
|
if o.Type.(*types.Named).Method(i).Name() == "UnmarshalGQL" {
|
||||||
case "UnmarshalGQL":
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8
vendor/github.com/99designs/gqlgen/codegen/object.gotpl
generated
vendored
8
vendor/github.com/99designs/gqlgen/codegen/object.gotpl
generated
vendored
@@ -4,8 +4,8 @@ var {{ $object.Name|lcFirst}}Implementors = {{$object.Implementors}}
|
|||||||
|
|
||||||
{{- if .Stream }}
|
{{- if .Stream }}
|
||||||
func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.SelectionSet) func() graphql.Marshaler {
|
func (ec *executionContext) _{{$object.Name}}(ctx context.Context, sel ast.SelectionSet) func() graphql.Marshaler {
|
||||||
fields := graphql.CollectFields(ec.RequestContext, sel, {{$object.Name|lcFirst}}Implementors)
|
fields := graphql.CollectFields(ec.OperationContext, sel, {{$object.Name|lcFirst}}Implementors)
|
||||||
ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{
|
ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{
|
||||||
Object: {{$object.Name|quote}},
|
Object: {{$object.Name|quote}},
|
||||||
})
|
})
|
||||||
if len(fields) != 1 {
|
if len(fields) != 1 {
|
||||||
@@ -24,9 +24,9 @@ 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.RequestContext, sel, {{$object.Name|lcFirst}}Implementors)
|
fields := graphql.CollectFields(ec.OperationContext, sel, {{$object.Name|lcFirst}}Implementors)
|
||||||
{{if $object.Root}}
|
{{if $object.Root}}
|
||||||
ctx = graphql.WithResolverContext(ctx, &graphql.ResolverContext{
|
ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{
|
||||||
Object: {{$object.Name|quote}},
|
Object: {{$object.Name|quote}},
|
||||||
})
|
})
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
8
vendor/github.com/99designs/gqlgen/codegen/templates/import.go
generated
vendored
8
vendor/github.com/99designs/gqlgen/codegen/templates/import.go
generated
vendored
@@ -4,6 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"go/types"
|
"go/types"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/internal/code"
|
"github.com/99designs/gqlgen/internal/code"
|
||||||
)
|
)
|
||||||
@@ -17,10 +18,11 @@ type Import struct {
|
|||||||
type Imports struct {
|
type Imports struct {
|
||||||
imports []*Import
|
imports []*Import
|
||||||
destDir string
|
destDir string
|
||||||
|
packages *code.Packages
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *Import) String() string {
|
func (i *Import) String() string {
|
||||||
if i.Alias == i.Name {
|
if strings.HasSuffix(i.Path, i.Alias) {
|
||||||
return strconv.Quote(i.Path)
|
return strconv.Quote(i.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +50,7 @@ func (s *Imports) Reserve(path string, aliases ...string) (string, error) {
|
|||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
name := code.NameForPackage(path)
|
name := s.packages.NameForPackage(path)
|
||||||
var alias string
|
var alias string
|
||||||
if len(aliases) != 1 {
|
if len(aliases) != 1 {
|
||||||
alias = name
|
alias = name
|
||||||
@@ -93,7 +95,7 @@ func (s *Imports) Lookup(path string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
imp := &Import{
|
imp := &Import{
|
||||||
Name: code.NameForPackage(path),
|
Name: s.packages.NameForPackage(path),
|
||||||
Path: path,
|
Path: path,
|
||||||
}
|
}
|
||||||
s.imports = append(s.imports, imp)
|
s.imports = append(s.imports, imp)
|
||||||
|
|||||||
68
vendor/github.com/99designs/gqlgen/codegen/templates/templates.go
generated
vendored
68
vendor/github.com/99designs/gqlgen/codegen/templates/templates.go
generated
vendored
@@ -15,6 +15,8 @@ import (
|
|||||||
"text/template"
|
"text/template"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
|
"github.com/99designs/gqlgen/internal/code"
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/internal/imports"
|
"github.com/99designs/gqlgen/internal/imports"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
@@ -40,9 +42,16 @@ type Options struct {
|
|||||||
Filename string
|
Filename string
|
||||||
RegionTags bool
|
RegionTags bool
|
||||||
GeneratedHeader bool
|
GeneratedHeader bool
|
||||||
|
// PackageDoc is documentation written above the package line
|
||||||
|
PackageDoc string
|
||||||
|
// FileNotice is notice written below the package line
|
||||||
|
FileNotice string
|
||||||
// Data will be passed to the template execution.
|
// Data will be passed to the template execution.
|
||||||
Data interface{}
|
Data interface{}
|
||||||
Funcs template.FuncMap
|
Funcs template.FuncMap
|
||||||
|
|
||||||
|
// Packages cache, you can find me on config.Config
|
||||||
|
Packages *code.Packages
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render renders a gql plugin template from the given Options. Render is an
|
// Render renders a gql plugin template from the given Options. Render is an
|
||||||
@@ -53,7 +62,7 @@ func Render(cfg Options) error {
|
|||||||
if CurrentImports != nil {
|
if CurrentImports != nil {
|
||||||
panic(fmt.Errorf("recursive or concurrent call to RenderToFile detected"))
|
panic(fmt.Errorf("recursive or concurrent call to RenderToFile detected"))
|
||||||
}
|
}
|
||||||
CurrentImports = &Imports{destDir: filepath.Dir(cfg.Filename)}
|
CurrentImports = &Imports{packages: cfg.Packages, destDir: filepath.Dir(cfg.Filename)}
|
||||||
|
|
||||||
// load path relative to calling source file
|
// load path relative to calling source file
|
||||||
_, callerFile, _, _ := runtime.Caller(1)
|
_, callerFile, _, _ := runtime.Caller(1)
|
||||||
@@ -131,9 +140,16 @@ func Render(cfg Options) error {
|
|||||||
if cfg.GeneratedHeader {
|
if cfg.GeneratedHeader {
|
||||||
result.WriteString("// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.\n\n")
|
result.WriteString("// Code generated by github.com/99designs/gqlgen, DO NOT EDIT.\n\n")
|
||||||
}
|
}
|
||||||
|
if cfg.PackageDoc != "" {
|
||||||
|
result.WriteString(cfg.PackageDoc + "\n")
|
||||||
|
}
|
||||||
result.WriteString("package ")
|
result.WriteString("package ")
|
||||||
result.WriteString(cfg.PackageName)
|
result.WriteString(cfg.PackageName)
|
||||||
result.WriteString("\n\n")
|
result.WriteString("\n\n")
|
||||||
|
if cfg.FileNotice != "" {
|
||||||
|
result.WriteString(cfg.FileNotice)
|
||||||
|
result.WriteString("\n\n")
|
||||||
|
}
|
||||||
result.WriteString("import (\n")
|
result.WriteString("import (\n")
|
||||||
result.WriteString(CurrentImports.String())
|
result.WriteString(CurrentImports.String())
|
||||||
result.WriteString(")\n")
|
result.WriteString(")\n")
|
||||||
@@ -143,7 +159,13 @@ func Render(cfg Options) error {
|
|||||||
}
|
}
|
||||||
CurrentImports = nil
|
CurrentImports = nil
|
||||||
|
|
||||||
return write(cfg.Filename, result.Bytes())
|
err = write(cfg.Filename, result.Bytes(), cfg.Packages)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg.Packages.Evict(code.ImportPathForDir(filepath.Dir(cfg.Filename)))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func center(width int, pad string, s string) string {
|
func center(width int, pad string, s string) string {
|
||||||
@@ -157,8 +179,8 @@ func center(width int, pad string, s string) string {
|
|||||||
|
|
||||||
func Funcs() template.FuncMap {
|
func Funcs() template.FuncMap {
|
||||||
return template.FuncMap{
|
return template.FuncMap{
|
||||||
"ucFirst": ucFirst,
|
"ucFirst": UcFirst,
|
||||||
"lcFirst": lcFirst,
|
"lcFirst": LcFirst,
|
||||||
"quote": strconv.Quote,
|
"quote": strconv.Quote,
|
||||||
"rawQuote": rawQuote,
|
"rawQuote": rawQuote,
|
||||||
"dump": Dump,
|
"dump": Dump,
|
||||||
@@ -180,7 +202,7 @@ func Funcs() template.FuncMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ucFirst(s string) string {
|
func UcFirst(s string) string {
|
||||||
if s == "" {
|
if s == "" {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -189,7 +211,7 @@ func ucFirst(s string) string {
|
|||||||
return string(r)
|
return string(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func lcFirst(s string) string {
|
func LcFirst(s string) string {
|
||||||
if s == "" {
|
if s == "" {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -211,6 +233,7 @@ var pkgReplacer = strings.NewReplacer(
|
|||||||
"/", "ᚋ",
|
"/", "ᚋ",
|
||||||
".", "ᚗ",
|
".", "ᚗ",
|
||||||
"-", "ᚑ",
|
"-", "ᚑ",
|
||||||
|
"~", "א",
|
||||||
)
|
)
|
||||||
|
|
||||||
func TypeIdentifier(t types.Type) string {
|
func TypeIdentifier(t types.Type) string {
|
||||||
@@ -260,6 +283,9 @@ func Call(p *types.Func) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ToGo(name string) string {
|
func ToGo(name string) string {
|
||||||
|
if name == "_" {
|
||||||
|
return "_"
|
||||||
|
}
|
||||||
runes := make([]rune, 0, len(name))
|
runes := make([]rune, 0, len(name))
|
||||||
|
|
||||||
wordWalker(name, func(info *wordInfo) {
|
wordWalker(name, func(info *wordInfo) {
|
||||||
@@ -270,7 +296,7 @@ func ToGo(name string) string {
|
|||||||
if strings.ToUpper(word) == word || strings.ToLower(word) == word {
|
if strings.ToUpper(word) == word || strings.ToLower(word) == word {
|
||||||
// FOO or foo → Foo
|
// FOO or foo → Foo
|
||||||
// FOo → FOo
|
// FOo → FOo
|
||||||
word = ucFirst(strings.ToLower(word))
|
word = UcFirst(strings.ToLower(word))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
runes = append(runes, []rune(word)...)
|
runes = append(runes, []rune(word)...)
|
||||||
@@ -280,24 +306,28 @@ func ToGo(name string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ToGoPrivate(name string) string {
|
func ToGoPrivate(name string) string {
|
||||||
|
if name == "_" {
|
||||||
|
return "_"
|
||||||
|
}
|
||||||
runes := make([]rune, 0, len(name))
|
runes := make([]rune, 0, len(name))
|
||||||
|
|
||||||
first := true
|
first := true
|
||||||
wordWalker(name, func(info *wordInfo) {
|
wordWalker(name, func(info *wordInfo) {
|
||||||
word := info.Word
|
word := info.Word
|
||||||
if first {
|
switch {
|
||||||
|
case first:
|
||||||
if strings.ToUpper(word) == word || strings.ToLower(word) == word {
|
if strings.ToUpper(word) == word || strings.ToLower(word) == word {
|
||||||
// ID → id, CAMEL → camel
|
// ID → id, CAMEL → camel
|
||||||
word = strings.ToLower(info.Word)
|
word = strings.ToLower(info.Word)
|
||||||
} else {
|
} else {
|
||||||
// ITicket → iTicket
|
// ITicket → iTicket
|
||||||
word = lcFirst(info.Word)
|
word = LcFirst(info.Word)
|
||||||
}
|
}
|
||||||
first = false
|
first = false
|
||||||
} else if info.MatchCommonInitial {
|
case info.MatchCommonInitial:
|
||||||
word = strings.ToUpper(word)
|
word = strings.ToUpper(word)
|
||||||
} else if !info.HasCommonInitial {
|
case !info.HasCommonInitial:
|
||||||
word = ucFirst(strings.ToLower(word))
|
word = UcFirst(strings.ToLower(word))
|
||||||
}
|
}
|
||||||
runes = append(runes, []rune(word)...)
|
runes = append(runes, []rune(word)...)
|
||||||
})
|
})
|
||||||
@@ -314,14 +344,15 @@ type wordInfo struct {
|
|||||||
// This function is based on the following code.
|
// This function is based on the following code.
|
||||||
// https://github.com/golang/lint/blob/06c8688daad7faa9da5a0c2f163a3d14aac986ca/lint.go#L679
|
// https://github.com/golang/lint/blob/06c8688daad7faa9da5a0c2f163a3d14aac986ca/lint.go#L679
|
||||||
func wordWalker(str string, f func(*wordInfo)) {
|
func wordWalker(str string, f func(*wordInfo)) {
|
||||||
runes := []rune(str)
|
runes := []rune(strings.TrimFunc(str, isDelimiter))
|
||||||
w, i := 0, 0 // index of start of word, scan
|
w, i := 0, 0 // index of start of word, scan
|
||||||
hasCommonInitial := false
|
hasCommonInitial := false
|
||||||
for i+1 <= len(runes) {
|
for i+1 <= len(runes) {
|
||||||
eow := false // whether we hit the end of a word
|
eow := false // whether we hit the end of a word
|
||||||
if i+1 == len(runes) {
|
switch {
|
||||||
|
case i+1 == len(runes):
|
||||||
eow = true
|
eow = true
|
||||||
} else if isDelimiter(runes[i+1]) {
|
case isDelimiter(runes[i+1]):
|
||||||
// underscore; shift the remainder forward over any run of underscores
|
// underscore; shift the remainder forward over any run of underscores
|
||||||
eow = true
|
eow = true
|
||||||
n := 1
|
n := 1
|
||||||
@@ -336,7 +367,7 @@ func wordWalker(str string, f func(*wordInfo)) {
|
|||||||
|
|
||||||
copy(runes[i+1:], runes[i+n+1:])
|
copy(runes[i+1:], runes[i+n+1:])
|
||||||
runes = runes[:len(runes)-n]
|
runes = runes[:len(runes)-n]
|
||||||
} else if unicode.IsLower(runes[i]) && !unicode.IsLower(runes[i+1]) {
|
case unicode.IsLower(runes[i]) && !unicode.IsLower(runes[i+1]):
|
||||||
// lower->non-lower
|
// lower->non-lower
|
||||||
eow = true
|
eow = true
|
||||||
}
|
}
|
||||||
@@ -429,6 +460,7 @@ var commonInitialisms = map[string]bool{
|
|||||||
"IP": true,
|
"IP": true,
|
||||||
"JSON": true,
|
"JSON": true,
|
||||||
"LHS": true,
|
"LHS": true,
|
||||||
|
"PGP": true,
|
||||||
"QPS": true,
|
"QPS": true,
|
||||||
"RAM": true,
|
"RAM": true,
|
||||||
"RHS": true,
|
"RHS": true,
|
||||||
@@ -549,13 +581,13 @@ func render(filename string, tpldata interface{}) (*bytes.Buffer, error) {
|
|||||||
return buf, t.Execute(buf, tpldata)
|
return buf, t.Execute(buf, tpldata)
|
||||||
}
|
}
|
||||||
|
|
||||||
func write(filename string, b []byte) error {
|
func write(filename string, b []byte, packages *code.Packages) error {
|
||||||
err := os.MkdirAll(filepath.Dir(filename), 0755)
|
err := os.MkdirAll(filepath.Dir(filename), 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to create directory")
|
return errors.Wrap(err, "failed to create directory")
|
||||||
}
|
}
|
||||||
|
|
||||||
formatted, err := imports.Prune(filename, b)
|
formatted, err := imports.Prune(filename, b, packages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "gofmt failed on %s: %s\n", filepath.Base(filename), err.Error())
|
fmt.Fprintf(os.Stderr, "gofmt failed on %s: %s\n", filepath.Base(filename), err.Error())
|
||||||
formatted = b
|
formatted = b
|
||||||
|
|||||||
30
vendor/github.com/99designs/gqlgen/codegen/type.go
generated
vendored
30
vendor/github.com/99designs/gqlgen/codegen/type.go
generated
vendored
@@ -1,18 +1,32 @@
|
|||||||
package codegen
|
package codegen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/codegen/config"
|
"github.com/99designs/gqlgen/codegen/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (b *builder) buildTypes() (map[string]*config.TypeReference, error) {
|
func (b *builder) buildTypes() map[string]*config.TypeReference {
|
||||||
ret := map[string]*config.TypeReference{}
|
ret := map[string]*config.TypeReference{}
|
||||||
|
|
||||||
for _, ref := range b.Binder.References {
|
for _, ref := range b.Binder.References {
|
||||||
for ref != nil {
|
processType(ret, ref)
|
||||||
ret[ref.UniquenessKey()] = ref
|
}
|
||||||
|
return ret
|
||||||
ref = ref.Elem()
|
}
|
||||||
|
|
||||||
|
func processType(ret map[string]*config.TypeReference, ref *config.TypeReference) {
|
||||||
|
key := ref.UniquenessKey()
|
||||||
|
if existing, found := ret[key]; found {
|
||||||
|
// Simplistic check of content which is obviously different.
|
||||||
|
existingGQL := fmt.Sprintf("%v", existing.GQL)
|
||||||
|
newGQL := fmt.Sprintf("%v", ref.GQL)
|
||||||
|
if existingGQL != newGQL {
|
||||||
|
panic(fmt.Sprintf("non-unique key \"%s\", trying to replace %s with %s", key, existingGQL, newGQL))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret[key] = ref
|
||||||
|
|
||||||
|
if ref.IsSlice() {
|
||||||
|
processType(ret, ref.Elem())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return ret, nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
83
vendor/github.com/99designs/gqlgen/codegen/type.gotpl
generated
vendored
83
vendor/github.com/99designs/gqlgen/codegen/type.gotpl
generated
vendored
@@ -1,13 +1,10 @@
|
|||||||
{{- 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 $type.IsNilable }}
|
{{- if and $type.IsNilable (not $type.GQL.NonNull) }}
|
||||||
if v == nil { return nil, nil }
|
if v == nil { return nil, nil }
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- if $type.IsPtr }}
|
{{- if $type.IsSlice }}
|
||||||
res, err := ec.{{ $type.Elem.UnmarshalFunc }}(ctx, v)
|
|
||||||
return &res, err
|
|
||||||
{{- else if $type.IsSlice }}
|
|
||||||
var vSlice []interface{}
|
var vSlice []interface{}
|
||||||
if v != nil {
|
if v != nil {
|
||||||
if tmp1, ok := v.([]interface{}); ok {
|
if tmp1, ok := v.([]interface{}); ok {
|
||||||
@@ -19,9 +16,10 @@
|
|||||||
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))
|
||||||
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, err
|
return nil, graphql.WrapErrorWithInputPath(ctx, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
@@ -29,17 +27,38 @@
|
|||||||
{{- if $type.Unmarshaler }}
|
{{- if $type.Unmarshaler }}
|
||||||
{{- if $type.CastType }}
|
{{- if $type.CastType }}
|
||||||
tmp, err := {{ $type.Unmarshaler | call }}(v)
|
tmp, err := {{ $type.Unmarshaler | call }}(v)
|
||||||
return {{ $type.GO | ref }}(tmp), err
|
{{- if $type.IsNilable }}
|
||||||
|
res := {{ $type.Elem.GO | ref }}(tmp)
|
||||||
{{- else}}
|
{{- else}}
|
||||||
return {{ $type.Unmarshaler | call }}(v)
|
res := {{ $type.GO | ref }}(tmp)
|
||||||
|
{{- end }}
|
||||||
|
{{- else}}
|
||||||
|
res, err := {{ $type.Unmarshaler | call }}(v)
|
||||||
|
{{- end }}
|
||||||
|
{{- if and $type.IsTargetNilable (not $type.IsNilable) }}
|
||||||
|
return *res, graphql.WrapErrorWithInputPath(ctx, err)
|
||||||
|
{{- else if and (not $type.IsTargetNilable) $type.IsNilable }}
|
||||||
|
return &res, graphql.WrapErrorWithInputPath(ctx, err)
|
||||||
|
{{- else}}
|
||||||
|
return res, graphql.WrapErrorWithInputPath(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 }}
|
||||||
|
var res = new({{ $type.Elem.GO | ref }})
|
||||||
|
{{- else}}
|
||||||
var res {{ $type.GO | ref }}
|
var res {{ $type.GO | ref }}
|
||||||
return res, res.UnmarshalGQL(v)
|
{{- end }}
|
||||||
|
err := res.UnmarshalGQL(v)
|
||||||
|
return res, graphql.WrapErrorWithInputPath(ctx, err)
|
||||||
{{- else }}
|
{{- else }}
|
||||||
return ec.unmarshalInput{{ $type.GQL.Name }}(ctx, v)
|
res, err := ec.unmarshalInput{{ $type.GQL.Name }}(ctx, v)
|
||||||
|
{{- if $type.IsNilable }}
|
||||||
|
return &res, graphql.WrapErrorWithInputPath(ctx, err)
|
||||||
|
{{- else}}
|
||||||
|
return res, graphql.WrapErrorWithInputPath(ctx, err)
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
}
|
}
|
||||||
@@ -47,17 +66,6 @@
|
|||||||
|
|
||||||
{{ 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.IsNilable }}
|
|
||||||
if v == nil {
|
|
||||||
{{- if $type.GQL.NonNull }}
|
|
||||||
if !ec.HasError(graphql.GetResolverContext(ctx)) {
|
|
||||||
ec.Errorf(ctx, "must not be null")
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
return graphql.Null
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- if $type.IsSlice }}
|
{{- if $type.IsSlice }}
|
||||||
{{- if not $type.GQL.NonNull }}
|
{{- if not $type.GQL.NonNull }}
|
||||||
if v == nil {
|
if v == nil {
|
||||||
@@ -75,11 +83,11 @@
|
|||||||
for i := range v {
|
for i := range v {
|
||||||
{{- if not $type.IsScalar }}
|
{{- if not $type.IsScalar }}
|
||||||
i := i
|
i := i
|
||||||
rctx := &graphql.ResolverContext{
|
fc := &graphql.FieldContext{
|
||||||
Index: &i,
|
Index: &i,
|
||||||
Result: &v[i],
|
Result: &v[i],
|
||||||
}
|
}
|
||||||
ctx := graphql.WithResolverContext(ctx, rctx)
|
ctx := graphql.WithFieldContext(ctx, fc)
|
||||||
f := func(i int) {
|
f := func(i int) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@@ -104,22 +112,35 @@
|
|||||||
{{ if not $type.IsScalar }} wg.Wait() {{ end }}
|
{{ if not $type.IsScalar }} wg.Wait() {{ end }}
|
||||||
return ret
|
return ret
|
||||||
{{- else }}
|
{{- else }}
|
||||||
|
{{- if $type.IsNilable }}
|
||||||
|
if v == nil {
|
||||||
|
{{- if $type.GQL.NonNull }}
|
||||||
|
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
||||||
|
ec.Errorf(ctx, "must not be null")
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
return graphql.Null
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
{{- if $type.IsMarshaler }}
|
{{- if $type.IsMarshaler }}
|
||||||
return v
|
return v
|
||||||
{{- else if $type.Marshaler }}
|
{{- else if $type.Marshaler }}
|
||||||
{{- if $type.IsPtr }}
|
{{- $v := "v" }}
|
||||||
return ec.{{ $type.Elem.MarshalFunc }}(ctx, sel, *v)
|
{{- if and $type.IsTargetNilable (not $type.IsNilable) }}
|
||||||
{{- else if $type.GQL.NonNull }}
|
{{- $v = "&v" }}
|
||||||
res := {{ $type.Marshaler | call }}({{- if $type.CastType }}{{ $type.CastType | ref }}(v){{else}}v{{- end }})
|
{{- else if and (not $type.IsTargetNilable) $type.IsNilable }}
|
||||||
|
{{- $v = "*v" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $type.GQL.NonNull }}
|
||||||
|
res := {{ $type.Marshaler | call }}({{- if $type.CastType }}{{ $type.CastType | ref }}({{ $v }}){{else}}{{ $v }}{{- end }})
|
||||||
if res == graphql.Null {
|
if res == graphql.Null {
|
||||||
if !ec.HasError(graphql.GetResolverContext(ctx)) {
|
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
||||||
ec.Errorf(ctx, "must not be null")
|
ec.Errorf(ctx, "must not be null")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
{{- else }}
|
{{- else }}
|
||||||
return {{ $type.Marshaler | call }}({{- if $type.CastType }}{{ $type.CastType | ref }}(v){{else}}v{{- end }})
|
return {{ $type.Marshaler | call }}({{- if $type.CastType }}{{ $type.CastType | ref }}({{ $v }}){{else}}{{ $v }}{{- end }})
|
||||||
{{- 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)
|
||||||
|
|||||||
2
vendor/github.com/99designs/gqlgen/complexity/complexity.go
generated
vendored
2
vendor/github.com/99designs/gqlgen/complexity/complexity.go
generated
vendored
@@ -2,7 +2,7 @@ package complexity
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/99designs/gqlgen/graphql"
|
"github.com/99designs/gqlgen/graphql"
|
||||||
"github.com/vektah/gqlparser/ast"
|
"github.com/vektah/gqlparser/v2/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Calculate(es graphql.ExecutableSchema, op *ast.OperationDefinition, vars map[string]interface{}) int {
|
func Calculate(es graphql.ExecutableSchema, op *ast.OperationDefinition, vars map[string]interface{}) int {
|
||||||
|
|||||||
23
vendor/github.com/99designs/gqlgen/go.mod
generated
vendored
23
vendor/github.com/99designs/gqlgen/go.mod
generated
vendored
@@ -1,14 +1,19 @@
|
|||||||
module github.com/99designs/gqlgen
|
module github.com/99designs/gqlgen
|
||||||
|
|
||||||
|
go 1.12
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/agnivade/levenshtein v1.0.3 // indirect
|
||||||
github.com/go-chi/chi v3.3.2+incompatible
|
github.com/go-chi/chi v3.3.2+incompatible
|
||||||
github.com/gogo/protobuf v1.0.0 // indirect
|
github.com/gogo/protobuf v1.0.0 // indirect
|
||||||
github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f // indirect
|
github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f // indirect
|
||||||
github.com/gorilla/mux v1.6.1 // indirect
|
github.com/gorilla/mux v1.6.1 // indirect
|
||||||
github.com/gorilla/websocket v1.2.0
|
github.com/gorilla/websocket v1.4.2
|
||||||
github.com/hashicorp/golang-lru v0.5.0
|
github.com/hashicorp/golang-lru v0.5.0
|
||||||
github.com/kr/pretty v0.1.0 // indirect
|
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381
|
||||||
|
github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007
|
||||||
|
github.com/mattn/go-colorable v0.1.4
|
||||||
|
github.com/mattn/go-isatty v0.0.12
|
||||||
github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047
|
github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047
|
||||||
github.com/opentracing/basictracer-go v1.0.0 // indirect
|
github.com/opentracing/basictracer-go v1.0.0 // indirect
|
||||||
github.com/opentracing/opentracing-go v1.0.2
|
github.com/opentracing/opentracing-go v1.0.2
|
||||||
@@ -16,13 +21,13 @@ require (
|
|||||||
github.com/rs/cors v1.6.0
|
github.com/rs/cors v1.6.0
|
||||||
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371 // indirect
|
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371 // indirect
|
||||||
github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0 // indirect
|
github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0 // indirect
|
||||||
github.com/stretchr/testify v1.3.0
|
github.com/stretchr/testify v1.4.0
|
||||||
github.com/urfave/cli v1.20.0
|
github.com/urfave/cli/v2 v2.1.1
|
||||||
github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e
|
github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e
|
||||||
github.com/vektah/gqlparser v1.1.2
|
github.com/vektah/gqlparser v1.3.1
|
||||||
golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd
|
github.com/vektah/gqlparser/v2 v2.0.1
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
|
golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589
|
||||||
gopkg.in/yaml.v2 v2.2.2
|
gopkg.in/yaml.v2 v2.2.4
|
||||||
sourcegraph.com/sourcegraph/appdash v0.0.0-20180110180208-2cc67fd64755
|
sourcegraph.com/sourcegraph/appdash v0.0.0-20180110180208-2cc67fd64755
|
||||||
sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67 // indirect
|
sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
67
vendor/github.com/99designs/gqlgen/go.sum
generated
vendored
67
vendor/github.com/99designs/gqlgen/go.sum
generated
vendored
@@ -1,11 +1,20 @@
|
|||||||
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/agnivade/levenshtein v1.0.1 h1:3oJU7J3FGFmyhn8KHjmVaZCN5hxTr7GxgRue+sxIXdQ=
|
github.com/agnivade/levenshtein v1.0.1 h1:3oJU7J3FGFmyhn8KHjmVaZCN5hxTr7GxgRue+sxIXdQ=
|
||||||
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 h1:M5ZnqLOoZR8ygVq0FfkXsNOKzMCk0xRiow0R5+5VkQ0=
|
||||||
|
github.com/agnivade/levenshtein v1.0.3/go.mod h1:4SFRZbbXWLF4MU1T9Qg0pGgH3Pjs+t6ie5efyrwRJXs=
|
||||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
|
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
|
||||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||||
|
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/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
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=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
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/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c h1:TUuUh0Xgj97tLMNtWtNvI9mIV6isjEb9lBMNv+77IGM=
|
||||||
|
github.com/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
|
||||||
github.com/go-chi/chi v3.3.2+incompatible h1:uQNcQN3NsV1j4ANsPh42P4ew4t6rnRbJb8frvpp31qQ=
|
github.com/go-chi/chi v3.3.2+incompatible h1:uQNcQN3NsV1j4ANsPh42P4ew4t6rnRbJb8frvpp31qQ=
|
||||||
github.com/go-chi/chi v3.3.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
github.com/go-chi/chi v3.3.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||||
github.com/gogo/protobuf v1.0.0 h1:2jyBKDKU/8v3v2xVR2PtiWQviFUyiaGk2rpfyFT8rTM=
|
github.com/gogo/protobuf v1.0.0 h1:2jyBKDKU/8v3v2xVR2PtiWQviFUyiaGk2rpfyFT8rTM=
|
||||||
@@ -14,8 +23,8 @@ github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f h1:9oNbS1z4rVpbnkH
|
|||||||
github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||||
github.com/gorilla/mux v1.6.1 h1:KOwqsTYZdeuMacU7CxjMNYEKeBvLbxW+psodrbcEa3A=
|
github.com/gorilla/mux v1.6.1 h1:KOwqsTYZdeuMacU7CxjMNYEKeBvLbxW+psodrbcEa3A=
|
||||||
github.com/gorilla/mux v1.6.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
github.com/gorilla/mux v1.6.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||||
github.com/gorilla/websocket v1.2.0 h1:VJtLvh6VQym50czpZzx07z/kw9EgAxI3x1ZB8taTMQQ=
|
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||||
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
|
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
|
||||||
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/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
@@ -23,6 +32,15 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
|||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381 h1:bqDmpDG49ZRnB5PcgP0RXtQvnMSgIF14M7CBd2shtXs=
|
||||||
|
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||||
|
github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007 h1:reVOUXwnhsYv/8UqjvhrMOu5CNT9UapHFLbQ2JcXsmg=
|
||||||
|
github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
|
||||||
|
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||||
|
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||||
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
|
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||||
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047 h1:zCoDWFD5nrJJVjbXiDZcVhOBSzKn3o9LgRLLMRNuru8=
|
github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047 h1:zCoDWFD5nrJJVjbXiDZcVhOBSzKn3o9LgRLLMRNuru8=
|
||||||
github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/opentracing/basictracer-go v1.0.0 h1:YyUAhaEfjoWXclZVJ9sGoNct7j4TVk7lZWlQw5UXuoo=
|
github.com/opentracing/basictracer-go v1.0.0 h1:YyUAhaEfjoWXclZVJ9sGoNct7j4TVk7lZWlQw5UXuoo=
|
||||||
@@ -35,46 +53,61 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
|||||||
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/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/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||||
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
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/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||||
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371 h1:SWV2fHctRpRrp49VXJ6UZja7gU9QLHwRpIPBN89SKEo=
|
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371 h1:SWV2fHctRpRrp49VXJ6UZja7gU9QLHwRpIPBN89SKEo=
|
||||||
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
|
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/vfsgen v0.0.0-20180121065927-ffb13db8def0 h1:JJV9CsgM9EC9w2iVkwuz+sMx8yRFe89PJRUrv6hPCIA=
|
github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0 h1:JJV9CsgM9EC9w2iVkwuz+sMx8yRFe89PJRUrv6hPCIA=
|
||||||
github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
|
github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
|
||||||
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/testify v1.2.1 h1:52QO5WkIUcHGIR7EnGagH88x1bUzqGXTC5/1bDTUQ7U=
|
github.com/stretchr/testify v1.2.1 h1:52QO5WkIUcHGIR7EnGagH88x1bUzqGXTC5/1bDTUQ7U=
|
||||||
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/vektah/dataloaden v0.2.0 h1:lhynDrG7c8mNLahboCo0Wq82tMjmu5yOUv2ds/tBmss=
|
github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k=
|
||||||
github.com/vektah/dataloaden v0.2.0/go.mod h1:vxM6NuRlgiR0M6wbVTJeKp9vQIs81ZMfCYO+4yq/jbE=
|
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
|
||||||
github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e h1:+w0Zm/9gaWpEAyDlU1eKOuk5twTjAjuevXqcJJw8hrg=
|
github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e h1:+w0Zm/9gaWpEAyDlU1eKOuk5twTjAjuevXqcJJw8hrg=
|
||||||
github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U=
|
github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U=
|
||||||
github.com/vektah/gqlparser v1.1.2 h1:ZsyLGn7/7jDNI+y4SEhI4yAxRChlv15pUHMjijT+e68=
|
github.com/vektah/gqlparser v1.3.1 h1:8b0IcD3qZKWJQHSzynbDlrtP3IxVydZ2DZepCGofqfU=
|
||||||
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
|
github.com/vektah/gqlparser v1.3.1/go.mod h1:bkVf0FX+Stjg/MHnm8mEyubuaArhNEqfQhF+OTiAL74=
|
||||||
|
github.com/vektah/gqlparser/v2 v2.0.1 h1:xgl5abVnsd4hkN9rk65OJID9bfcLSMuTaTcZj777q1o=
|
||||||
|
github.com/vektah/gqlparser/v2 v2.0.1/go.mod h1:SyUiHgLATUR8BiYURfTirrTcGpcE+4XkV2se04Px1Ms=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/net v0.0.0-20180404174746-b3c676e531a6 h1:mge3qS/eMvcfyIAzTMOAy0XUzWG6Lk0N4M8zjuSmdco=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/net v0.0.0-20180404174746-b3c676e531a6/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
|
||||||
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
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/tools v0.0.0-20190125232054-d66bd3c5d5a6 h1:iZgcI2DDp6zW5v9Z/5+f0NuqoxNdmzg4hivjk2WLXpY=
|
golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6 h1:iZgcI2DDp6zW5v9Z/5+f0NuqoxNdmzg4hivjk2WLXpY=
|
||||||
golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/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-20190125232054-dbeab5af4b8d3204d444b78cafaba18a9a062a50/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190511041617-99f201b6807e h1:wTxRxdzKt8fn3IQa3+kVlPJMxK2hJj2Orm+M2Mzw9eg=
|
|
||||||
golang.org/x/tools v0.0.0-20190511041617-99f201b6807e/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd h1:oMEQDWVXVNpceQoVd1JN3CQ7LYJJzs5qWqZIUcxXHHw=
|
golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd h1:oMEQDWVXVNpceQoVd1JN3CQ7LYJJzs5qWqZIUcxXHHw=
|
||||||
golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
|
golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589 h1:rjUrONFu4kLchcZTfp3/96bR8bW8dIa8uz3cR5n0cgM=
|
||||||
|
golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
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.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
sourcegraph.com/sourcegraph/appdash v0.0.0-20180110180208-2cc67fd64755 h1:d2maSb13hr/ArmfK3rW+wNUKKfytCol7W1/vDHxMPiE=
|
sourcegraph.com/sourcegraph/appdash v0.0.0-20180110180208-2cc67fd64755 h1:d2maSb13hr/ArmfK3rW+wNUKKfytCol7W1/vDHxMPiE=
|
||||||
sourcegraph.com/sourcegraph/appdash v0.0.0-20180110180208-2cc67fd64755/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
|
sourcegraph.com/sourcegraph/appdash v0.0.0-20180110180208-2cc67fd64755/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
|
||||||
sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67 h1:e1sMhtVq9AfcEy8AXNb8eSg6gbzfdpYhoNqnPJa+GzI=
|
sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67 h1:e1sMhtVq9AfcEy8AXNb8eSg6gbzfdpYhoNqnPJa+GzI=
|
||||||
|
|||||||
29
vendor/github.com/99designs/gqlgen/graphql/cache.go
generated
vendored
Normal file
29
vendor/github.com/99designs/gqlgen/graphql/cache.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package graphql
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
// Cache is a shared store for APQ and query AST caching
|
||||||
|
type Cache interface {
|
||||||
|
// Get looks up a key's value from the cache.
|
||||||
|
Get(ctx context.Context, key string) (value interface{}, ok bool)
|
||||||
|
|
||||||
|
// Add adds a value to the cache.
|
||||||
|
Add(ctx context.Context, key string, value interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapCache is the simplest implementation of a cache, because it can not evict it should only be used in tests
|
||||||
|
type MapCache map[string]interface{}
|
||||||
|
|
||||||
|
// Get looks up a key's value from the cache.
|
||||||
|
func (m MapCache) Get(ctx context.Context, key string) (value interface{}, ok bool) {
|
||||||
|
v, ok := m[key]
|
||||||
|
return v, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add adds a value to the cache.
|
||||||
|
func (m MapCache) Add(ctx context.Context, key string, value interface{}) { m[key] = value }
|
||||||
|
|
||||||
|
type NoCache struct{}
|
||||||
|
|
||||||
|
func (n NoCache) Get(ctx context.Context, key string) (value interface{}, ok bool) { return nil, false }
|
||||||
|
func (n NoCache) Add(ctx context.Context, key string, value interface{}) {}
|
||||||
274
vendor/github.com/99designs/gqlgen/graphql/context.go
generated
vendored
274
vendor/github.com/99designs/gqlgen/graphql/context.go
generated
vendored
@@ -1,274 +0,0 @@
|
|||||||
package graphql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/vektah/gqlparser/ast"
|
|
||||||
"github.com/vektah/gqlparser/gqlerror"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Resolver func(ctx context.Context) (res interface{}, err error)
|
|
||||||
type FieldMiddleware func(ctx context.Context, next Resolver) (res interface{}, err error)
|
|
||||||
type RequestMiddleware func(ctx context.Context, next func(ctx context.Context) []byte) []byte
|
|
||||||
type ComplexityLimitFunc func(ctx context.Context) int
|
|
||||||
|
|
||||||
type RequestContext struct {
|
|
||||||
RawQuery string
|
|
||||||
Variables map[string]interface{}
|
|
||||||
Doc *ast.QueryDocument
|
|
||||||
|
|
||||||
ComplexityLimit int
|
|
||||||
OperationComplexity int
|
|
||||||
DisableIntrospection bool
|
|
||||||
|
|
||||||
// ErrorPresenter will be used to generate the error
|
|
||||||
// message from errors given to Error().
|
|
||||||
ErrorPresenter ErrorPresenterFunc
|
|
||||||
Recover RecoverFunc
|
|
||||||
ResolverMiddleware FieldMiddleware
|
|
||||||
DirectiveMiddleware FieldMiddleware
|
|
||||||
RequestMiddleware RequestMiddleware
|
|
||||||
Tracer Tracer
|
|
||||||
|
|
||||||
errorsMu sync.Mutex
|
|
||||||
Errors gqlerror.List
|
|
||||||
extensionsMu sync.Mutex
|
|
||||||
Extensions map[string]interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func DefaultResolverMiddleware(ctx context.Context, next Resolver) (res interface{}, err error) {
|
|
||||||
return next(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func DefaultDirectiveMiddleware(ctx context.Context, next Resolver) (res interface{}, err error) {
|
|
||||||
return next(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func DefaultRequestMiddleware(ctx context.Context, next func(ctx context.Context) []byte) []byte {
|
|
||||||
return next(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewRequestContext(doc *ast.QueryDocument, query string, variables map[string]interface{}) *RequestContext {
|
|
||||||
return &RequestContext{
|
|
||||||
Doc: doc,
|
|
||||||
RawQuery: query,
|
|
||||||
Variables: variables,
|
|
||||||
ResolverMiddleware: DefaultResolverMiddleware,
|
|
||||||
DirectiveMiddleware: DefaultDirectiveMiddleware,
|
|
||||||
RequestMiddleware: DefaultRequestMiddleware,
|
|
||||||
Recover: DefaultRecover,
|
|
||||||
ErrorPresenter: DefaultErrorPresenter,
|
|
||||||
Tracer: &NopTracer{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type key string
|
|
||||||
|
|
||||||
const (
|
|
||||||
request key = "request_context"
|
|
||||||
resolver key = "resolver_context"
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetRequestContext(ctx context.Context) *RequestContext {
|
|
||||||
if val, ok := ctx.Value(request).(*RequestContext); ok {
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func WithRequestContext(ctx context.Context, rc *RequestContext) context.Context {
|
|
||||||
return context.WithValue(ctx, request, rc)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResolverContext struct {
|
|
||||||
Parent *ResolverContext
|
|
||||||
// The name of the type this field belongs to
|
|
||||||
Object string
|
|
||||||
// These are the args after processing, they can be mutated in middleware to change what the resolver will get.
|
|
||||||
Args map[string]interface{}
|
|
||||||
// The raw field
|
|
||||||
Field CollectedField
|
|
||||||
// The index of array in path.
|
|
||||||
Index *int
|
|
||||||
// The result object of resolver
|
|
||||||
Result interface{}
|
|
||||||
// IsMethod indicates if the resolver is a method
|
|
||||||
IsMethod bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *ResolverContext) Path() []interface{} {
|
|
||||||
var path []interface{}
|
|
||||||
for it := r; it != nil; it = it.Parent {
|
|
||||||
if it.Index != nil {
|
|
||||||
path = append(path, *it.Index)
|
|
||||||
} else if it.Field.Field != nil {
|
|
||||||
path = append(path, it.Field.Alias)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// because we are walking up the chain, all the elements are backwards, do an inplace flip.
|
|
||||||
for i := len(path)/2 - 1; i >= 0; i-- {
|
|
||||||
opp := len(path) - 1 - i
|
|
||||||
path[i], path[opp] = path[opp], path[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetResolverContext(ctx context.Context) *ResolverContext {
|
|
||||||
if val, ok := ctx.Value(resolver).(*ResolverContext); ok {
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func WithResolverContext(ctx context.Context, rc *ResolverContext) context.Context {
|
|
||||||
rc.Parent = GetResolverContext(ctx)
|
|
||||||
return context.WithValue(ctx, resolver, rc)
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is just a convenient wrapper method for CollectFields
|
|
||||||
func CollectFieldsCtx(ctx context.Context, satisfies []string) []CollectedField {
|
|
||||||
resctx := GetResolverContext(ctx)
|
|
||||||
return CollectFields(GetRequestContext(ctx), resctx.Field.Selections, satisfies)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CollectAllFields returns a slice of all GraphQL field names that were selected for the current resolver context.
|
|
||||||
// The slice will contain the unique set of all field names requested regardless of fragment type conditions.
|
|
||||||
func CollectAllFields(ctx context.Context) []string {
|
|
||||||
resctx := GetResolverContext(ctx)
|
|
||||||
collected := CollectFields(GetRequestContext(ctx), resctx.Field.Selections, nil)
|
|
||||||
uniq := make([]string, 0, len(collected))
|
|
||||||
Next:
|
|
||||||
for _, f := range collected {
|
|
||||||
for _, name := range uniq {
|
|
||||||
if name == f.Name {
|
|
||||||
continue Next
|
|
||||||
}
|
|
||||||
}
|
|
||||||
uniq = append(uniq, f.Name)
|
|
||||||
}
|
|
||||||
return uniq
|
|
||||||
}
|
|
||||||
|
|
||||||
// Errorf sends an error string to the client, passing it through the formatter.
|
|
||||||
func (c *RequestContext) Errorf(ctx context.Context, format string, args ...interface{}) {
|
|
||||||
c.errorsMu.Lock()
|
|
||||||
defer c.errorsMu.Unlock()
|
|
||||||
|
|
||||||
c.Errors = append(c.Errors, c.ErrorPresenter(ctx, fmt.Errorf(format, args...)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error sends an error to the client, passing it through the formatter.
|
|
||||||
func (c *RequestContext) Error(ctx context.Context, err error) {
|
|
||||||
c.errorsMu.Lock()
|
|
||||||
defer c.errorsMu.Unlock()
|
|
||||||
|
|
||||||
c.Errors = append(c.Errors, c.ErrorPresenter(ctx, err))
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasError returns true if the current field has already errored
|
|
||||||
func (c *RequestContext) HasError(rctx *ResolverContext) bool {
|
|
||||||
c.errorsMu.Lock()
|
|
||||||
defer c.errorsMu.Unlock()
|
|
||||||
path := rctx.Path()
|
|
||||||
|
|
||||||
for _, err := range c.Errors {
|
|
||||||
if equalPath(err.Path, path) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetErrors returns a list of errors that occurred in the current field
|
|
||||||
func (c *RequestContext) GetErrors(rctx *ResolverContext) gqlerror.List {
|
|
||||||
c.errorsMu.Lock()
|
|
||||||
defer c.errorsMu.Unlock()
|
|
||||||
path := rctx.Path()
|
|
||||||
|
|
||||||
var errs gqlerror.List
|
|
||||||
for _, err := range c.Errors {
|
|
||||||
if equalPath(err.Path, path) {
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return errs
|
|
||||||
}
|
|
||||||
|
|
||||||
func equalPath(a []interface{}, b []interface{}) bool {
|
|
||||||
if len(a) != len(b) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := 0; i < len(a); i++ {
|
|
||||||
if a[i] != b[i] {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddError is a convenience method for adding an error to the current response
|
|
||||||
func AddError(ctx context.Context, err error) {
|
|
||||||
GetRequestContext(ctx).Error(ctx, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddErrorf is a convenience method for adding an error to the current response
|
|
||||||
func AddErrorf(ctx context.Context, format string, args ...interface{}) {
|
|
||||||
GetRequestContext(ctx).Errorf(ctx, format, args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterExtension registers an extension, returns error if extension has already been registered
|
|
||||||
func (c *RequestContext) RegisterExtension(key string, value interface{}) error {
|
|
||||||
c.extensionsMu.Lock()
|
|
||||||
defer c.extensionsMu.Unlock()
|
|
||||||
|
|
||||||
if c.Extensions == nil {
|
|
||||||
c.Extensions = make(map[string]interface{})
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := c.Extensions[key]; ok {
|
|
||||||
return fmt.Errorf("extension already registered for key %s", key)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Extensions[key] = value
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChainFieldMiddleware add chain by FieldMiddleware
|
|
||||||
func ChainFieldMiddleware(handleFunc ...FieldMiddleware) FieldMiddleware {
|
|
||||||
n := len(handleFunc)
|
|
||||||
|
|
||||||
if n > 1 {
|
|
||||||
lastI := n - 1
|
|
||||||
return func(ctx context.Context, next Resolver) (interface{}, error) {
|
|
||||||
var (
|
|
||||||
chainHandler Resolver
|
|
||||||
curI int
|
|
||||||
)
|
|
||||||
chainHandler = func(currentCtx context.Context) (interface{}, error) {
|
|
||||||
if curI == lastI {
|
|
||||||
return next(currentCtx)
|
|
||||||
}
|
|
||||||
curI++
|
|
||||||
res, err := handleFunc[curI](currentCtx, chainHandler)
|
|
||||||
curI--
|
|
||||||
return res, err
|
|
||||||
|
|
||||||
}
|
|
||||||
return handleFunc[0](ctx, chainHandler)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if n == 1 {
|
|
||||||
return handleFunc[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
return func(ctx context.Context, next Resolver) (interface{}, error) {
|
|
||||||
return next(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
92
vendor/github.com/99designs/gqlgen/graphql/context_field.go
generated
vendored
Normal file
92
vendor/github.com/99designs/gqlgen/graphql/context_field.go
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
package graphql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/vektah/gqlparser/v2/ast"
|
||||||
|
)
|
||||||
|
|
||||||
|
type key string
|
||||||
|
|
||||||
|
const resolverCtx key = "resolver_context"
|
||||||
|
|
||||||
|
// Deprecated: Use FieldContext instead
|
||||||
|
type ResolverContext = FieldContext
|
||||||
|
|
||||||
|
type FieldContext struct {
|
||||||
|
Parent *FieldContext
|
||||||
|
// The name of the type this field belongs to
|
||||||
|
Object string
|
||||||
|
// These are the args after processing, they can be mutated in middleware to change what the resolver will get.
|
||||||
|
Args map[string]interface{}
|
||||||
|
// The raw field
|
||||||
|
Field CollectedField
|
||||||
|
// The index of array in path.
|
||||||
|
Index *int
|
||||||
|
// The result object of resolver
|
||||||
|
Result interface{}
|
||||||
|
// IsMethod indicates if the resolver is a method
|
||||||
|
IsMethod bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type FieldStats struct {
|
||||||
|
// When field execution started
|
||||||
|
Started time.Time
|
||||||
|
|
||||||
|
// When argument marshaling finished
|
||||||
|
ArgumentsCompleted time.Time
|
||||||
|
|
||||||
|
// When the field completed running all middleware. Not available inside field middleware!
|
||||||
|
Completed time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *FieldContext) Path() ast.Path {
|
||||||
|
var path ast.Path
|
||||||
|
for it := r; it != nil; it = it.Parent {
|
||||||
|
if it.Index != nil {
|
||||||
|
path = append(path, ast.PathIndex(*it.Index))
|
||||||
|
} else if it.Field.Field != nil {
|
||||||
|
path = append(path, ast.PathName(it.Field.Alias))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// because we are walking up the chain, all the elements are backwards, do an inplace flip.
|
||||||
|
for i := len(path)/2 - 1; i >= 0; i-- {
|
||||||
|
opp := len(path) - 1 - i
|
||||||
|
path[i], path[opp] = path[opp], path[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use GetFieldContext instead
|
||||||
|
func GetResolverContext(ctx context.Context) *ResolverContext {
|
||||||
|
return GetFieldContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFieldContext(ctx context.Context) *FieldContext {
|
||||||
|
if val, ok := ctx.Value(resolverCtx).(*FieldContext); ok {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithFieldContext(ctx context.Context, rc *FieldContext) context.Context {
|
||||||
|
rc.Parent = GetFieldContext(ctx)
|
||||||
|
return context.WithValue(ctx, resolverCtx, rc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func equalPath(a ast.Path, b ast.Path) bool {
|
||||||
|
if len(a) != len(b) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(a); i++ {
|
||||||
|
if a[i] != b[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
85
vendor/github.com/99designs/gqlgen/graphql/context_field_input.go
generated
vendored
Normal file
85
vendor/github.com/99designs/gqlgen/graphql/context_field_input.go
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
107
vendor/github.com/99designs/gqlgen/graphql/context_operation.go
generated
vendored
Normal file
107
vendor/github.com/99designs/gqlgen/graphql/context_operation.go
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
package graphql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/vektah/gqlparser/v2/ast"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Deprecated: Please update all references to OperationContext instead
|
||||||
|
type RequestContext = OperationContext
|
||||||
|
|
||||||
|
type OperationContext struct {
|
||||||
|
RawQuery string
|
||||||
|
Variables map[string]interface{}
|
||||||
|
OperationName string
|
||||||
|
Doc *ast.QueryDocument
|
||||||
|
|
||||||
|
Operation *ast.OperationDefinition
|
||||||
|
DisableIntrospection bool
|
||||||
|
Recover RecoverFunc
|
||||||
|
ResolverMiddleware FieldMiddleware
|
||||||
|
|
||||||
|
Stats Stats
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *OperationContext) Validate(ctx context.Context) error {
|
||||||
|
if c.Doc == nil {
|
||||||
|
return errors.New("field 'Doc'is required")
|
||||||
|
}
|
||||||
|
if c.RawQuery == "" {
|
||||||
|
return errors.New("field 'RawQuery' is required")
|
||||||
|
}
|
||||||
|
if c.Variables == nil {
|
||||||
|
c.Variables = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
if c.ResolverMiddleware == nil {
|
||||||
|
return errors.New("field 'ResolverMiddleware' is required")
|
||||||
|
}
|
||||||
|
if c.Recover == nil {
|
||||||
|
c.Recover = DefaultRecover
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const operationCtx key = "operation_context"
|
||||||
|
|
||||||
|
// Deprecated: Please update all references to GetOperationContext instead
|
||||||
|
func GetRequestContext(ctx context.Context) *RequestContext {
|
||||||
|
return GetOperationContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetOperationContext(ctx context.Context) *OperationContext {
|
||||||
|
if val, ok := ctx.Value(operationCtx).(*OperationContext); ok && val != nil {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
panic("missing operation context")
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithOperationContext(ctx context.Context, rc *OperationContext) context.Context {
|
||||||
|
return context.WithValue(ctx, operationCtx, rc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasOperationContext checks if the given context is part of an ongoing operation
|
||||||
|
//
|
||||||
|
// Some errors can happen outside of an operation, eg json unmarshal errors.
|
||||||
|
func HasOperationContext(ctx context.Context) bool {
|
||||||
|
_, ok := ctx.Value(operationCtx).(*OperationContext)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is just a convenient wrapper method for CollectFields
|
||||||
|
func CollectFieldsCtx(ctx context.Context, satisfies []string) []CollectedField {
|
||||||
|
resctx := GetFieldContext(ctx)
|
||||||
|
return CollectFields(GetOperationContext(ctx), resctx.Field.Selections, satisfies)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CollectAllFields returns a slice of all GraphQL field names that were selected for the current resolver context.
|
||||||
|
// The slice will contain the unique set of all field names requested regardless of fragment type conditions.
|
||||||
|
func CollectAllFields(ctx context.Context) []string {
|
||||||
|
resctx := GetFieldContext(ctx)
|
||||||
|
collected := CollectFields(GetOperationContext(ctx), resctx.Field.Selections, nil)
|
||||||
|
uniq := make([]string, 0, len(collected))
|
||||||
|
Next:
|
||||||
|
for _, f := range collected {
|
||||||
|
for _, name := range uniq {
|
||||||
|
if name == f.Name {
|
||||||
|
continue Next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uniq = append(uniq, f.Name)
|
||||||
|
}
|
||||||
|
return uniq
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorf sends an error string to the client, passing it through the formatter.
|
||||||
|
// Deprecated: use graphql.AddErrorf(ctx, err) instead
|
||||||
|
func (c *OperationContext) Errorf(ctx context.Context, format string, args ...interface{}) {
|
||||||
|
AddErrorf(ctx, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error sends an error to the client, passing it through the formatter.
|
||||||
|
// Deprecated: use graphql.AddError(ctx, err) instead
|
||||||
|
func (c *OperationContext) Error(ctx context.Context, err error) {
|
||||||
|
AddError(ctx, err)
|
||||||
|
}
|
||||||
157
vendor/github.com/99designs/gqlgen/graphql/context_response.go
generated
vendored
Normal file
157
vendor/github.com/99designs/gqlgen/graphql/context_response.go
generated
vendored
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
package graphql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||||
|
)
|
||||||
|
|
||||||
|
type responseContext struct {
|
||||||
|
errorPresenter ErrorPresenterFunc
|
||||||
|
recover RecoverFunc
|
||||||
|
|
||||||
|
errors gqlerror.List
|
||||||
|
errorsMu sync.Mutex
|
||||||
|
|
||||||
|
extensions map[string]interface{}
|
||||||
|
extensionsMu sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
const resultCtx key = "result_context"
|
||||||
|
|
||||||
|
func getResponseContext(ctx context.Context) *responseContext {
|
||||||
|
val, ok := ctx.Value(resultCtx).(*responseContext)
|
||||||
|
if !ok {
|
||||||
|
panic("missing response context")
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithResponseContext(ctx context.Context, presenterFunc ErrorPresenterFunc, recoverFunc RecoverFunc) context.Context {
|
||||||
|
return context.WithValue(ctx, resultCtx, &responseContext{
|
||||||
|
errorPresenter: presenterFunc,
|
||||||
|
recover: recoverFunc,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddErrorf writes a formatted error to the client, first passing it through the error presenter.
|
||||||
|
func AddErrorf(ctx context.Context, format string, args ...interface{}) {
|
||||||
|
c := getResponseContext(ctx)
|
||||||
|
|
||||||
|
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.
|
||||||
|
func AddError(ctx context.Context, err error) {
|
||||||
|
c := getResponseContext(ctx)
|
||||||
|
|
||||||
|
c.errorsMu.Lock()
|
||||||
|
defer c.errorsMu.Unlock()
|
||||||
|
|
||||||
|
c.errors = append(c.errors, c.errorPresenter(ctx, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Recover(ctx context.Context, err interface{}) (userMessage error) {
|
||||||
|
c := getResponseContext(ctx)
|
||||||
|
return c.recover(ctx, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasFieldError returns true if the given field has already errored
|
||||||
|
func HasFieldError(ctx context.Context, rctx *FieldContext) bool {
|
||||||
|
c := getResponseContext(ctx)
|
||||||
|
|
||||||
|
c.errorsMu.Lock()
|
||||||
|
defer c.errorsMu.Unlock()
|
||||||
|
|
||||||
|
if len(c.errors) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
path := rctx.Path()
|
||||||
|
for _, err := range c.errors {
|
||||||
|
if equalPath(err.Path, path) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFieldErrors returns a list of errors that occurred in the given field
|
||||||
|
func GetFieldErrors(ctx context.Context, rctx *FieldContext) gqlerror.List {
|
||||||
|
c := getResponseContext(ctx)
|
||||||
|
|
||||||
|
c.errorsMu.Lock()
|
||||||
|
defer c.errorsMu.Unlock()
|
||||||
|
|
||||||
|
if len(c.errors) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
path := rctx.Path()
|
||||||
|
var errs gqlerror.List
|
||||||
|
for _, err := range c.errors {
|
||||||
|
if equalPath(err.Path, path) {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetErrors(ctx context.Context) gqlerror.List {
|
||||||
|
resCtx := getResponseContext(ctx)
|
||||||
|
resCtx.errorsMu.Lock()
|
||||||
|
defer resCtx.errorsMu.Unlock()
|
||||||
|
|
||||||
|
if len(resCtx.errors) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
errs := resCtx.errors
|
||||||
|
cpy := make(gqlerror.List, len(errs))
|
||||||
|
for i := range errs {
|
||||||
|
errCpy := *errs[i]
|
||||||
|
cpy[i] = &errCpy
|
||||||
|
}
|
||||||
|
return cpy
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterExtension allows you to add a new extension into the graphql response
|
||||||
|
func RegisterExtension(ctx context.Context, key string, value interface{}) {
|
||||||
|
c := getResponseContext(ctx)
|
||||||
|
c.extensionsMu.Lock()
|
||||||
|
defer c.extensionsMu.Unlock()
|
||||||
|
|
||||||
|
if c.extensions == nil {
|
||||||
|
c.extensions = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := c.extensions[key]; ok {
|
||||||
|
panic(fmt.Errorf("extension already registered for key %s", key))
|
||||||
|
}
|
||||||
|
|
||||||
|
c.extensions[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetExtensions returns any extensions registered in the current result context
|
||||||
|
func GetExtensions(ctx context.Context) map[string]interface{} {
|
||||||
|
ext := getResponseContext(ctx).extensions
|
||||||
|
if ext == nil {
|
||||||
|
return map[string]interface{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ext
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetExtension(ctx context.Context, name string) interface{} {
|
||||||
|
ext := getResponseContext(ctx).extensions
|
||||||
|
if ext == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return ext[name]
|
||||||
|
}
|
||||||
49
vendor/github.com/99designs/gqlgen/graphql/errcode/codes.go
generated
vendored
Normal file
49
vendor/github.com/99designs/gqlgen/graphql/errcode/codes.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package errcode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ValidationFailed = "GRAPHQL_VALIDATION_FAILED"
|
||||||
|
const ParseFailed = "GRAPHQL_PARSE_FAILED"
|
||||||
|
|
||||||
|
type ErrorKind int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// issues with graphql (validation, parsing). 422s in http, GQL_ERROR in websocket
|
||||||
|
KindProtocol ErrorKind = iota
|
||||||
|
// user errors, 200s in http, GQL_DATA in websocket
|
||||||
|
KindUser
|
||||||
|
)
|
||||||
|
|
||||||
|
var codeType = map[string]ErrorKind{
|
||||||
|
ValidationFailed: KindProtocol,
|
||||||
|
ParseFailed: KindProtocol,
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterErrorType should be called by extensions that want to customize the http status codes for errors they return
|
||||||
|
func RegisterErrorType(code string, kind ErrorKind) {
|
||||||
|
codeType[code] = kind
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the error code on a given graphql error extension
|
||||||
|
func Set(err *gqlerror.Error, value string) {
|
||||||
|
if err.Extensions == nil {
|
||||||
|
err.Extensions = map[string]interface{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
err.Extensions["code"] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the kind of the first non User error, defaults to User if no errors have a custom extension
|
||||||
|
func GetErrorKind(errs gqlerror.List) ErrorKind {
|
||||||
|
for _, err := range errs {
|
||||||
|
if code, ok := err.Extensions["code"].(string); ok {
|
||||||
|
if kind, ok := codeType[code]; ok && kind != KindUser {
|
||||||
|
return kind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return KindUser
|
||||||
|
}
|
||||||
8
vendor/github.com/99designs/gqlgen/graphql/error.go
generated
vendored
8
vendor/github.com/99designs/gqlgen/graphql/error.go
generated
vendored
@@ -3,10 +3,10 @@ package graphql
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/vektah/gqlparser/gqlerror"
|
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ErrorPresenterFunc func(context.Context, error) *gqlerror.Error
|
type ErrorPresenterFunc func(ctx context.Context, err error) *gqlerror.Error
|
||||||
|
|
||||||
type ExtendedError interface {
|
type ExtendedError interface {
|
||||||
Extensions() map[string]interface{}
|
Extensions() map[string]interface{}
|
||||||
@@ -15,7 +15,7 @@ type ExtendedError 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 {
|
if gqlerr, ok := err.(*gqlerror.Error); ok {
|
||||||
if gqlerr.Path == nil {
|
if gqlerr.Path == nil {
|
||||||
gqlerr.Path = GetResolverContext(ctx).Path()
|
gqlerr.Path = GetFieldContext(ctx).Path()
|
||||||
}
|
}
|
||||||
return gqlerr
|
return gqlerr
|
||||||
}
|
}
|
||||||
@@ -27,7 +27,7 @@ func DefaultErrorPresenter(ctx context.Context, err error) *gqlerror.Error {
|
|||||||
|
|
||||||
return &gqlerror.Error{
|
return &gqlerror.Error{
|
||||||
Message: err.Error(),
|
Message: err.Error(),
|
||||||
Path: GetResolverContext(ctx).Path(),
|
Path: GetFieldContext(ctx).Path(),
|
||||||
Extensions: extensions,
|
Extensions: extensions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
|
//go:generate go run github.com/matryer/moq -out executable_schema_mock.go . ExecutableSchema
|
||||||
|
|
||||||
package graphql
|
package graphql
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/vektah/gqlparser/ast"
|
"github.com/vektah/gqlparser/v2/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ExecutableSchema interface {
|
type ExecutableSchema interface {
|
||||||
Schema() *ast.Schema
|
Schema() *ast.Schema
|
||||||
|
|
||||||
Complexity(typeName, fieldName string, childComplexity int, args map[string]interface{}) (int, bool)
|
Complexity(typeName, fieldName string, childComplexity int, args map[string]interface{}) (int, bool)
|
||||||
Query(ctx context.Context, op *ast.OperationDefinition) *Response
|
Exec(ctx context.Context) ResponseHandler
|
||||||
Mutation(ctx context.Context, op *ast.OperationDefinition) *Response
|
|
||||||
Subscription(ctx context.Context, op *ast.OperationDefinition) func() *Response
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CollectFields returns the set of fields from an ast.SelectionSet where all collected fields satisfy at least one of the GraphQL types
|
// CollectFields returns the set of fields from an ast.SelectionSet where all collected fields satisfy at least one of the GraphQL types
|
||||||
// passed through satisfies. Providing an empty or nil slice for satisfies will return collect all fields regardless of fragment
|
// passed through satisfies. Providing an empty or nil slice for satisfies will return collect all fields regardless of fragment
|
||||||
// type conditions.
|
// type conditions.
|
||||||
func CollectFields(reqCtx *RequestContext, selSet ast.SelectionSet, satisfies []string) []CollectedField {
|
func CollectFields(reqCtx *OperationContext, selSet ast.SelectionSet, satisfies []string) []CollectedField {
|
||||||
return collectFields(reqCtx, selSet, satisfies, map[string]bool{})
|
return collectFields(reqCtx, selSet, satisfies, map[string]bool{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func collectFields(reqCtx *RequestContext, selSet ast.SelectionSet, satisfies []string, visited map[string]bool) []CollectedField {
|
func collectFields(reqCtx *OperationContext, selSet ast.SelectionSet, satisfies []string, visited map[string]bool) []CollectedField {
|
||||||
groupedFields := make([]CollectedField, 0, len(selSet))
|
groupedFields := make([]CollectedField, 0, len(selSet))
|
||||||
|
|
||||||
for _, sel := range selSet {
|
for _, sel := range selSet {
|
||||||
@@ -32,7 +32,7 @@ func collectFields(reqCtx *RequestContext, selSet ast.SelectionSet, satisfies []
|
|||||||
if !shouldIncludeNode(sel.Directives, reqCtx.Variables) {
|
if !shouldIncludeNode(sel.Directives, reqCtx.Variables) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
f := getOrCreateAndAppendField(&groupedFields, sel.Alias, func() CollectedField {
|
f := getOrCreateAndAppendField(&groupedFields, sel.Alias, sel.ObjectDefinition, func() CollectedField {
|
||||||
return CollectedField{Field: sel}
|
return CollectedField{Field: sel}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ func collectFields(reqCtx *RequestContext, 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, func() CollectedField { return childField })
|
f := getOrCreateAndAppendField(&groupedFields, childField.Name, childField.ObjectDefinition, func() CollectedField { return childField })
|
||||||
f.Selections = append(f.Selections, childField.Selections...)
|
f.Selections = append(f.Selections, childField.Selections...)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ func collectFields(reqCtx *RequestContext, 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, func() CollectedField { return childField })
|
f := getOrCreateAndAppendField(&groupedFields, childField.Name, childField.ObjectDefinition, func() CollectedField { return childField })
|
||||||
f.Selections = append(f.Selections, childField.Selections...)
|
f.Selections = append(f.Selections, childField.Selections...)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -96,9 +96,9 @@ func instanceOf(val string, satisfies []string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func getOrCreateAndAppendField(c *[]CollectedField, name string, creator func() CollectedField) *CollectedField {
|
func getOrCreateAndAppendField(c *[]CollectedField, name string, objectDefinition *ast.Definition, creator func() CollectedField) *CollectedField {
|
||||||
for i, cf := range *c {
|
for i, cf := range *c {
|
||||||
if cf.Alias == name {
|
if cf.Alias == name && (cf.ObjectDefinition == objectDefinition || (cf.ObjectDefinition != nil && objectDefinition != nil && cf.ObjectDefinition.Name == objectDefinition.Name)) {
|
||||||
return &(*c)[i]
|
return &(*c)[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
175
vendor/github.com/99designs/gqlgen/graphql/executable_schema_mock.go
generated
vendored
Normal file
175
vendor/github.com/99designs/gqlgen/graphql/executable_schema_mock.go
generated
vendored
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
// Code generated by moq; DO NOT EDIT.
|
||||||
|
// github.com/matryer/moq
|
||||||
|
|
||||||
|
package graphql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/vektah/gqlparser/v2/ast"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
lockExecutableSchemaMockComplexity sync.RWMutex
|
||||||
|
lockExecutableSchemaMockExec sync.RWMutex
|
||||||
|
lockExecutableSchemaMockSchema sync.RWMutex
|
||||||
|
)
|
||||||
|
|
||||||
|
// Ensure, that ExecutableSchemaMock does implement ExecutableSchema.
|
||||||
|
// If this is not the case, regenerate this file with moq.
|
||||||
|
var _ ExecutableSchema = &ExecutableSchemaMock{}
|
||||||
|
|
||||||
|
// ExecutableSchemaMock is a mock implementation of ExecutableSchema.
|
||||||
|
//
|
||||||
|
// func TestSomethingThatUsesExecutableSchema(t *testing.T) {
|
||||||
|
//
|
||||||
|
// // make and configure a mocked ExecutableSchema
|
||||||
|
// mockedExecutableSchema := &ExecutableSchemaMock{
|
||||||
|
// ComplexityFunc: func(typeName string, fieldName string, childComplexity int, args map[string]interface{}) (int, bool) {
|
||||||
|
// panic("mock out the Complexity method")
|
||||||
|
// },
|
||||||
|
// ExecFunc: func(ctx context.Context) ResponseHandler {
|
||||||
|
// panic("mock out the Exec method")
|
||||||
|
// },
|
||||||
|
// SchemaFunc: func() *ast.Schema {
|
||||||
|
// panic("mock out the Schema method")
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // use mockedExecutableSchema in code that requires ExecutableSchema
|
||||||
|
// // and then make assertions.
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
type ExecutableSchemaMock struct {
|
||||||
|
// ComplexityFunc mocks the Complexity method.
|
||||||
|
ComplexityFunc func(typeName string, fieldName string, childComplexity int, args map[string]interface{}) (int, bool)
|
||||||
|
|
||||||
|
// ExecFunc mocks the Exec method.
|
||||||
|
ExecFunc func(ctx context.Context) ResponseHandler
|
||||||
|
|
||||||
|
// SchemaFunc mocks the Schema method.
|
||||||
|
SchemaFunc func() *ast.Schema
|
||||||
|
|
||||||
|
// calls tracks calls to the methods.
|
||||||
|
calls struct {
|
||||||
|
// Complexity holds details about calls to the Complexity method.
|
||||||
|
Complexity []struct {
|
||||||
|
// TypeName is the typeName argument value.
|
||||||
|
TypeName string
|
||||||
|
// FieldName is the fieldName argument value.
|
||||||
|
FieldName string
|
||||||
|
// ChildComplexity is the childComplexity argument value.
|
||||||
|
ChildComplexity int
|
||||||
|
// Args is the args argument value.
|
||||||
|
Args map[string]interface{}
|
||||||
|
}
|
||||||
|
// Exec holds details about calls to the Exec method.
|
||||||
|
Exec []struct {
|
||||||
|
// Ctx is the ctx argument value.
|
||||||
|
Ctx context.Context
|
||||||
|
}
|
||||||
|
// Schema holds details about calls to the Schema method.
|
||||||
|
Schema []struct {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complexity calls ComplexityFunc.
|
||||||
|
func (mock *ExecutableSchemaMock) Complexity(typeName string, fieldName string, childComplexity int, args map[string]interface{}) (int, bool) {
|
||||||
|
if mock.ComplexityFunc == nil {
|
||||||
|
panic("ExecutableSchemaMock.ComplexityFunc: method is nil but ExecutableSchema.Complexity was just called")
|
||||||
|
}
|
||||||
|
callInfo := struct {
|
||||||
|
TypeName string
|
||||||
|
FieldName string
|
||||||
|
ChildComplexity int
|
||||||
|
Args map[string]interface{}
|
||||||
|
}{
|
||||||
|
TypeName: typeName,
|
||||||
|
FieldName: fieldName,
|
||||||
|
ChildComplexity: childComplexity,
|
||||||
|
Args: args,
|
||||||
|
}
|
||||||
|
lockExecutableSchemaMockComplexity.Lock()
|
||||||
|
mock.calls.Complexity = append(mock.calls.Complexity, callInfo)
|
||||||
|
lockExecutableSchemaMockComplexity.Unlock()
|
||||||
|
return mock.ComplexityFunc(typeName, fieldName, childComplexity, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ComplexityCalls gets all the calls that were made to Complexity.
|
||||||
|
// Check the length with:
|
||||||
|
// len(mockedExecutableSchema.ComplexityCalls())
|
||||||
|
func (mock *ExecutableSchemaMock) ComplexityCalls() []struct {
|
||||||
|
TypeName string
|
||||||
|
FieldName string
|
||||||
|
ChildComplexity int
|
||||||
|
Args map[string]interface{}
|
||||||
|
} {
|
||||||
|
var calls []struct {
|
||||||
|
TypeName string
|
||||||
|
FieldName string
|
||||||
|
ChildComplexity int
|
||||||
|
Args map[string]interface{}
|
||||||
|
}
|
||||||
|
lockExecutableSchemaMockComplexity.RLock()
|
||||||
|
calls = mock.calls.Complexity
|
||||||
|
lockExecutableSchemaMockComplexity.RUnlock()
|
||||||
|
return calls
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exec calls ExecFunc.
|
||||||
|
func (mock *ExecutableSchemaMock) Exec(ctx context.Context) ResponseHandler {
|
||||||
|
if mock.ExecFunc == nil {
|
||||||
|
panic("ExecutableSchemaMock.ExecFunc: method is nil but ExecutableSchema.Exec was just called")
|
||||||
|
}
|
||||||
|
callInfo := struct {
|
||||||
|
Ctx context.Context
|
||||||
|
}{
|
||||||
|
Ctx: ctx,
|
||||||
|
}
|
||||||
|
lockExecutableSchemaMockExec.Lock()
|
||||||
|
mock.calls.Exec = append(mock.calls.Exec, callInfo)
|
||||||
|
lockExecutableSchemaMockExec.Unlock()
|
||||||
|
return mock.ExecFunc(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExecCalls gets all the calls that were made to Exec.
|
||||||
|
// Check the length with:
|
||||||
|
// len(mockedExecutableSchema.ExecCalls())
|
||||||
|
func (mock *ExecutableSchemaMock) ExecCalls() []struct {
|
||||||
|
Ctx context.Context
|
||||||
|
} {
|
||||||
|
var calls []struct {
|
||||||
|
Ctx context.Context
|
||||||
|
}
|
||||||
|
lockExecutableSchemaMockExec.RLock()
|
||||||
|
calls = mock.calls.Exec
|
||||||
|
lockExecutableSchemaMockExec.RUnlock()
|
||||||
|
return calls
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schema calls SchemaFunc.
|
||||||
|
func (mock *ExecutableSchemaMock) Schema() *ast.Schema {
|
||||||
|
if mock.SchemaFunc == nil {
|
||||||
|
panic("ExecutableSchemaMock.SchemaFunc: method is nil but ExecutableSchema.Schema was just called")
|
||||||
|
}
|
||||||
|
callInfo := struct {
|
||||||
|
}{}
|
||||||
|
lockExecutableSchemaMockSchema.Lock()
|
||||||
|
mock.calls.Schema = append(mock.calls.Schema, callInfo)
|
||||||
|
lockExecutableSchemaMockSchema.Unlock()
|
||||||
|
return mock.SchemaFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SchemaCalls gets all the calls that were made to Schema.
|
||||||
|
// Check the length with:
|
||||||
|
// len(mockedExecutableSchema.SchemaCalls())
|
||||||
|
func (mock *ExecutableSchemaMock) SchemaCalls() []struct {
|
||||||
|
} {
|
||||||
|
var calls []struct {
|
||||||
|
}
|
||||||
|
lockExecutableSchemaMockSchema.RLock()
|
||||||
|
calls = mock.calls.Schema
|
||||||
|
lockExecutableSchemaMockSchema.RUnlock()
|
||||||
|
return calls
|
||||||
|
}
|
||||||
191
vendor/github.com/99designs/gqlgen/graphql/executor/executor.go
generated
vendored
Normal file
191
vendor/github.com/99designs/gqlgen/graphql/executor/executor.go
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
package executor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/99designs/gqlgen/graphql"
|
||||||
|
"github.com/99designs/gqlgen/graphql/errcode"
|
||||||
|
"github.com/vektah/gqlparser/v2/ast"
|
||||||
|
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||||
|
"github.com/vektah/gqlparser/v2/parser"
|
||||||
|
"github.com/vektah/gqlparser/v2/validator"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Executor executes graphql queries against a schema.
|
||||||
|
type Executor struct {
|
||||||
|
es graphql.ExecutableSchema
|
||||||
|
extensions []graphql.HandlerExtension
|
||||||
|
ext extensions
|
||||||
|
|
||||||
|
errorPresenter graphql.ErrorPresenterFunc
|
||||||
|
recoverFunc graphql.RecoverFunc
|
||||||
|
queryCache graphql.Cache
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ graphql.GraphExecutor = &Executor{}
|
||||||
|
|
||||||
|
// New creates a new Executor with the given schema, and a default error and
|
||||||
|
// recovery callbacks, and no query cache or extensions.
|
||||||
|
func New(es graphql.ExecutableSchema) *Executor {
|
||||||
|
e := &Executor{
|
||||||
|
es: es,
|
||||||
|
errorPresenter: graphql.DefaultErrorPresenter,
|
||||||
|
recoverFunc: graphql.DefaultRecover,
|
||||||
|
queryCache: graphql.NoCache{},
|
||||||
|
ext: processExtensions(nil),
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Executor) CreateOperationContext(ctx context.Context, params *graphql.RawParams) (*graphql.OperationContext, gqlerror.List) {
|
||||||
|
rc := &graphql.OperationContext{
|
||||||
|
DisableIntrospection: true,
|
||||||
|
Recover: e.recoverFunc,
|
||||||
|
ResolverMiddleware: e.ext.fieldMiddleware,
|
||||||
|
Stats: graphql.Stats{
|
||||||
|
Read: params.ReadTime,
|
||||||
|
OperationStart: graphql.GetStartTime(ctx),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
ctx = graphql.WithOperationContext(ctx, rc)
|
||||||
|
|
||||||
|
for _, p := range e.ext.operationParameterMutators {
|
||||||
|
if err := p.MutateOperationParameters(ctx, params); err != nil {
|
||||||
|
return rc, gqlerror.List{err}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rc.RawQuery = params.Query
|
||||||
|
rc.OperationName = params.OperationName
|
||||||
|
|
||||||
|
var listErr gqlerror.List
|
||||||
|
rc.Doc, listErr = e.parseQuery(ctx, &rc.Stats, params.Query)
|
||||||
|
if len(listErr) != 0 {
|
||||||
|
return rc, listErr
|
||||||
|
}
|
||||||
|
|
||||||
|
rc.Operation = rc.Doc.Operations.ForName(params.OperationName)
|
||||||
|
if rc.Operation == nil {
|
||||||
|
return rc, gqlerror.List{gqlerror.Errorf("operation %s not found", params.OperationName)}
|
||||||
|
}
|
||||||
|
|
||||||
|
var err *gqlerror.Error
|
||||||
|
rc.Variables, err = validator.VariableValues(e.es.Schema(), rc.Operation, params.Variables)
|
||||||
|
if err != nil {
|
||||||
|
errcode.Set(err, errcode.ValidationFailed)
|
||||||
|
return rc, gqlerror.List{err}
|
||||||
|
}
|
||||||
|
rc.Stats.Validation.End = graphql.Now()
|
||||||
|
|
||||||
|
for _, p := range e.ext.operationContextMutators {
|
||||||
|
if err := p.MutateOperationContext(ctx, rc); err != nil {
|
||||||
|
return rc, gqlerror.List{err}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Executor) DispatchOperation(ctx context.Context, rc *graphql.OperationContext) (graphql.ResponseHandler, context.Context) {
|
||||||
|
ctx = graphql.WithOperationContext(ctx, rc)
|
||||||
|
|
||||||
|
var innerCtx context.Context
|
||||||
|
res := e.ext.operationMiddleware(ctx, func(ctx context.Context) graphql.ResponseHandler {
|
||||||
|
innerCtx = ctx
|
||||||
|
|
||||||
|
tmpResponseContext := graphql.WithResponseContext(ctx, e.errorPresenter, e.recoverFunc)
|
||||||
|
responses := e.es.Exec(tmpResponseContext)
|
||||||
|
if errs := graphql.GetErrors(tmpResponseContext); errs != nil {
|
||||||
|
return graphql.OneShot(&graphql.Response{Errors: errs})
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(ctx context.Context) *graphql.Response {
|
||||||
|
ctx = graphql.WithResponseContext(ctx, e.errorPresenter, e.recoverFunc)
|
||||||
|
resp := e.ext.responseMiddleware(ctx, func(ctx context.Context) *graphql.Response {
|
||||||
|
resp := responses(ctx)
|
||||||
|
if resp == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
resp.Errors = append(resp.Errors, graphql.GetErrors(ctx)...)
|
||||||
|
resp.Extensions = graphql.GetExtensions(ctx)
|
||||||
|
return resp
|
||||||
|
})
|
||||||
|
if resp == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return res, innerCtx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Executor) DispatchError(ctx context.Context, list gqlerror.List) *graphql.Response {
|
||||||
|
ctx = graphql.WithResponseContext(ctx, e.errorPresenter, e.recoverFunc)
|
||||||
|
for _, gErr := range list {
|
||||||
|
graphql.AddError(ctx, gErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := e.ext.responseMiddleware(ctx, func(ctx context.Context) *graphql.Response {
|
||||||
|
resp := &graphql.Response{
|
||||||
|
Errors: list,
|
||||||
|
}
|
||||||
|
resp.Extensions = graphql.GetExtensions(ctx)
|
||||||
|
return resp
|
||||||
|
})
|
||||||
|
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Executor) PresentRecoveredError(ctx context.Context, err interface{}) *gqlerror.Error {
|
||||||
|
return e.errorPresenter(ctx, e.recoverFunc(ctx, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Executor) SetQueryCache(cache graphql.Cache) {
|
||||||
|
e.queryCache = cache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Executor) SetErrorPresenter(f graphql.ErrorPresenterFunc) {
|
||||||
|
e.errorPresenter = f
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Executor) SetRecoverFunc(f graphql.RecoverFunc) {
|
||||||
|
e.recoverFunc = f
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseQuery decodes the incoming query and validates it, pulling from cache if present.
|
||||||
|
//
|
||||||
|
// NOTE: This should NOT look at variables, they will change per request. It should only parse and validate
|
||||||
|
// the raw query string.
|
||||||
|
func (e *Executor) parseQuery(ctx context.Context, stats *graphql.Stats, query string) (*ast.QueryDocument, gqlerror.List) {
|
||||||
|
stats.Parsing.Start = graphql.Now()
|
||||||
|
|
||||||
|
if doc, ok := e.queryCache.Get(ctx, query); ok {
|
||||||
|
now := graphql.Now()
|
||||||
|
|
||||||
|
stats.Parsing.End = now
|
||||||
|
stats.Validation.Start = now
|
||||||
|
return doc.(*ast.QueryDocument), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
doc, err := parser.ParseQuery(&ast.Source{Input: query})
|
||||||
|
if err != nil {
|
||||||
|
errcode.Set(err, errcode.ParseFailed)
|
||||||
|
return nil, gqlerror.List{err}
|
||||||
|
}
|
||||||
|
stats.Parsing.End = graphql.Now()
|
||||||
|
|
||||||
|
stats.Validation.Start = graphql.Now()
|
||||||
|
listErr := validator.Validate(e.es.Schema(), doc)
|
||||||
|
if len(listErr) != 0 {
|
||||||
|
for _, e := range listErr {
|
||||||
|
errcode.Set(e, errcode.ValidationFailed)
|
||||||
|
}
|
||||||
|
return nil, listErr
|
||||||
|
}
|
||||||
|
|
||||||
|
e.queryCache.Add(ctx, query, doc)
|
||||||
|
|
||||||
|
return doc, nil
|
||||||
|
}
|
||||||
159
vendor/github.com/99designs/gqlgen/graphql/executor/extensions.go
generated
vendored
Normal file
159
vendor/github.com/99designs/gqlgen/graphql/executor/extensions.go
generated
vendored
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
package executor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/99designs/gqlgen/graphql"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Use adds the given extension to this Executor.
|
||||||
|
func (e *Executor) Use(extension graphql.HandlerExtension) {
|
||||||
|
if err := extension.Validate(e.es); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch extension.(type) {
|
||||||
|
case graphql.OperationParameterMutator,
|
||||||
|
graphql.OperationContextMutator,
|
||||||
|
graphql.OperationInterceptor,
|
||||||
|
graphql.FieldInterceptor,
|
||||||
|
graphql.ResponseInterceptor:
|
||||||
|
e.extensions = append(e.extensions, extension)
|
||||||
|
e.ext = processExtensions(e.extensions)
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("cannot Use %T as a gqlgen handler extension because it does not implement any extension hooks", extension))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AroundFields is a convenience method for creating an extension that only implements field middleware
|
||||||
|
func (e *Executor) AroundFields(f graphql.FieldMiddleware) {
|
||||||
|
e.Use(aroundFieldFunc(f))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AroundOperations is a convenience method for creating an extension that only implements operation middleware
|
||||||
|
func (e *Executor) AroundOperations(f graphql.OperationMiddleware) {
|
||||||
|
e.Use(aroundOpFunc(f))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AroundResponses is a convenience method for creating an extension that only implements response middleware
|
||||||
|
func (e *Executor) AroundResponses(f graphql.ResponseMiddleware) {
|
||||||
|
e.Use(aroundRespFunc(f))
|
||||||
|
}
|
||||||
|
|
||||||
|
type extensions struct {
|
||||||
|
operationMiddleware graphql.OperationMiddleware
|
||||||
|
responseMiddleware graphql.ResponseMiddleware
|
||||||
|
fieldMiddleware graphql.FieldMiddleware
|
||||||
|
operationParameterMutators []graphql.OperationParameterMutator
|
||||||
|
operationContextMutators []graphql.OperationContextMutator
|
||||||
|
}
|
||||||
|
|
||||||
|
func processExtensions(exts []graphql.HandlerExtension) extensions {
|
||||||
|
e := extensions{
|
||||||
|
operationMiddleware: func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler {
|
||||||
|
return next(ctx)
|
||||||
|
},
|
||||||
|
responseMiddleware: func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
|
||||||
|
return next(ctx)
|
||||||
|
},
|
||||||
|
fieldMiddleware: func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
|
||||||
|
return next(ctx)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// this loop goes backwards so the first extension is the outer most middleware and runs first.
|
||||||
|
for i := len(exts) - 1; i >= 0; i-- {
|
||||||
|
p := exts[i]
|
||||||
|
if p, ok := p.(graphql.OperationInterceptor); ok {
|
||||||
|
previous := e.operationMiddleware
|
||||||
|
e.operationMiddleware = func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler {
|
||||||
|
return p.InterceptOperation(ctx, func(ctx context.Context) graphql.ResponseHandler {
|
||||||
|
return previous(ctx, next)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if p, ok := p.(graphql.ResponseInterceptor); ok {
|
||||||
|
previous := e.responseMiddleware
|
||||||
|
e.responseMiddleware = func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
|
||||||
|
return p.InterceptResponse(ctx, func(ctx context.Context) *graphql.Response {
|
||||||
|
return previous(ctx, next)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if p, ok := p.(graphql.FieldInterceptor); ok {
|
||||||
|
previous := e.fieldMiddleware
|
||||||
|
e.fieldMiddleware = func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
|
||||||
|
return p.InterceptField(ctx, func(ctx context.Context) (res interface{}, err error) {
|
||||||
|
return previous(ctx, next)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range exts {
|
||||||
|
if p, ok := p.(graphql.OperationParameterMutator); ok {
|
||||||
|
e.operationParameterMutators = append(e.operationParameterMutators, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
if p, ok := p.(graphql.OperationContextMutator); ok {
|
||||||
|
e.operationContextMutators = append(e.operationContextMutators, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
type aroundOpFunc func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler
|
||||||
|
|
||||||
|
func (r aroundOpFunc) ExtensionName() string {
|
||||||
|
return "InlineOperationFunc"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r aroundOpFunc) Validate(schema graphql.ExecutableSchema) error {
|
||||||
|
if r == nil {
|
||||||
|
return fmt.Errorf("OperationFunc can not be nil")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r aroundOpFunc) InterceptOperation(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler {
|
||||||
|
return r(ctx, next)
|
||||||
|
}
|
||||||
|
|
||||||
|
type aroundRespFunc func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response
|
||||||
|
|
||||||
|
func (r aroundRespFunc) ExtensionName() string {
|
||||||
|
return "InlineResponseFunc"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r aroundRespFunc) Validate(schema graphql.ExecutableSchema) error {
|
||||||
|
if r == nil {
|
||||||
|
return fmt.Errorf("ResponseFunc can not be nil")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r aroundRespFunc) InterceptResponse(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
|
||||||
|
return r(ctx, next)
|
||||||
|
}
|
||||||
|
|
||||||
|
type aroundFieldFunc func(ctx context.Context, next graphql.Resolver) (res interface{}, err error)
|
||||||
|
|
||||||
|
func (f aroundFieldFunc) ExtensionName() string {
|
||||||
|
return "InlineFieldFunc"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f aroundFieldFunc) Validate(schema graphql.ExecutableSchema) error {
|
||||||
|
if f == nil {
|
||||||
|
return fmt.Errorf("FieldFunc can not be nil")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f aroundFieldFunc) InterceptField(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
|
||||||
|
return f(ctx, next)
|
||||||
|
}
|
||||||
123
vendor/github.com/99designs/gqlgen/graphql/handler.go
generated
vendored
Normal file
123
vendor/github.com/99designs/gqlgen/graphql/handler.go
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
package graphql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
OperationMiddleware func(ctx context.Context, next OperationHandler) ResponseHandler
|
||||||
|
OperationHandler func(ctx context.Context) ResponseHandler
|
||||||
|
|
||||||
|
ResponseHandler func(ctx context.Context) *Response
|
||||||
|
ResponseMiddleware func(ctx context.Context, next ResponseHandler) *Response
|
||||||
|
|
||||||
|
Resolver func(ctx context.Context) (res interface{}, err error)
|
||||||
|
FieldMiddleware func(ctx context.Context, next Resolver) (res interface{}, err error)
|
||||||
|
|
||||||
|
RawParams struct {
|
||||||
|
Query string `json:"query"`
|
||||||
|
OperationName string `json:"operationName"`
|
||||||
|
Variables map[string]interface{} `json:"variables"`
|
||||||
|
Extensions map[string]interface{} `json:"extensions"`
|
||||||
|
|
||||||
|
ReadTime TraceTiming `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
GraphExecutor interface {
|
||||||
|
CreateOperationContext(ctx context.Context, params *RawParams) (*OperationContext, gqlerror.List)
|
||||||
|
DispatchOperation(ctx context.Context, rc *OperationContext) (ResponseHandler, context.Context)
|
||||||
|
DispatchError(ctx context.Context, list gqlerror.List) *Response
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandlerExtension adds functionality to the http handler. See the list of possible hook points below
|
||||||
|
// Its important to understand the lifecycle of a graphql request and the terminology we use in gqlgen
|
||||||
|
// before working with these
|
||||||
|
//
|
||||||
|
// +--- REQUEST POST /graphql --------------------------------------------+
|
||||||
|
// | +- OPERATION query OpName { viewer { name } } -----------------------+ |
|
||||||
|
// | | RESPONSE { "data": { "viewer": { "name": "bob" } } } | |
|
||||||
|
// | +- OPERATION subscription OpName2 { chat { message } } --------------+ |
|
||||||
|
// | | RESPONSE { "data": { "chat": { "message": "hello" } } } | |
|
||||||
|
// | | RESPONSE { "data": { "chat": { "message": "byee" } } } | |
|
||||||
|
// | +--------------------------------------------------------------------+ |
|
||||||
|
// +------------------------------------------------------------------------+
|
||||||
|
HandlerExtension interface {
|
||||||
|
// ExtensionName should be a CamelCase string version of the extension which may be shown in stats and logging.
|
||||||
|
ExtensionName() string
|
||||||
|
// Validate is called when adding an extension to the server, it allows validation against the servers schema.
|
||||||
|
Validate(schema ExecutableSchema) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// OperationParameterMutator is called before creating a request context. allows manipulating the raw query
|
||||||
|
// on the way in.
|
||||||
|
OperationParameterMutator interface {
|
||||||
|
MutateOperationParameters(ctx context.Context, request *RawParams) *gqlerror.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// OperationContextMutator is called after creating the request context, but before executing the root resolver.
|
||||||
|
OperationContextMutator interface {
|
||||||
|
MutateOperationContext(ctx context.Context, rc *OperationContext) *gqlerror.Error
|
||||||
|
}
|
||||||
|
|
||||||
|
// OperationInterceptor is called for each incoming query, for basic requests the writer will be invoked once,
|
||||||
|
// for subscriptions it will be invoked multiple times.
|
||||||
|
OperationInterceptor interface {
|
||||||
|
InterceptOperation(ctx context.Context, next OperationHandler) ResponseHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResponseInterceptor is called around each graphql operation response. This can be called many times for a single
|
||||||
|
// operation the case of subscriptions.
|
||||||
|
ResponseInterceptor interface {
|
||||||
|
InterceptResponse(ctx context.Context, next ResponseHandler) *Response
|
||||||
|
}
|
||||||
|
|
||||||
|
// FieldInterceptor called around each field
|
||||||
|
FieldInterceptor interface {
|
||||||
|
InterceptField(ctx context.Context, next Resolver) (res interface{}, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transport provides support for different wire level encodings of graphql requests, eg Form, Get, Post, Websocket
|
||||||
|
Transport interface {
|
||||||
|
Supports(r *http.Request) bool
|
||||||
|
Do(w http.ResponseWriter, r *http.Request, exec GraphExecutor)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type Status int
|
||||||
|
|
||||||
|
func (p *RawParams) AddUpload(upload Upload, key, path string) *gqlerror.Error {
|
||||||
|
if !strings.HasPrefix(path, "variables.") {
|
||||||
|
return gqlerror.Errorf("invalid operations paths for key %s", key)
|
||||||
|
}
|
||||||
|
|
||||||
|
var ptr interface{} = p.Variables
|
||||||
|
parts := strings.Split(path, ".")
|
||||||
|
|
||||||
|
// skip the first part (variables) because we started there
|
||||||
|
for i, p := range parts[1:] {
|
||||||
|
last := i == len(parts)-2
|
||||||
|
if ptr == nil {
|
||||||
|
return gqlerror.Errorf("path is missing \"variables.\" prefix, key: %s, path: %s", key, path)
|
||||||
|
}
|
||||||
|
if index, parseNbrErr := strconv.Atoi(p); parseNbrErr == nil {
|
||||||
|
if last {
|
||||||
|
ptr.([]interface{})[index] = upload
|
||||||
|
} else {
|
||||||
|
ptr = ptr.([]interface{})[index]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if last {
|
||||||
|
ptr.(map[string]interface{})[p] = upload
|
||||||
|
} else {
|
||||||
|
ptr = ptr.(map[string]interface{})[p]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
112
vendor/github.com/99designs/gqlgen/graphql/handler/extension/apq.go
generated
vendored
Normal file
112
vendor/github.com/99designs/gqlgen/graphql/handler/extension/apq.go
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
package extension
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/99designs/gqlgen/graphql/errcode"
|
||||||
|
|
||||||
|
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||||
|
|
||||||
|
"github.com/99designs/gqlgen/graphql"
|
||||||
|
"github.com/mitchellh/mapstructure"
|
||||||
|
)
|
||||||
|
|
||||||
|
const errPersistedQueryNotFound = "PersistedQueryNotFound"
|
||||||
|
const errPersistedQueryNotFoundCode = "PERSISTED_QUERY_NOT_FOUND"
|
||||||
|
|
||||||
|
// AutomaticPersistedQuery saves client upload by optimistically sending only the hashes of queries, if the server
|
||||||
|
// does not yet know what the query is for the hash it will respond telling the client to send the query along with the
|
||||||
|
// hash in the next request.
|
||||||
|
// see https://github.com/apollographql/apollo-link-persisted-queries
|
||||||
|
type AutomaticPersistedQuery struct {
|
||||||
|
Cache graphql.Cache
|
||||||
|
}
|
||||||
|
|
||||||
|
type ApqStats struct {
|
||||||
|
// The hash of the incoming query
|
||||||
|
Hash string
|
||||||
|
|
||||||
|
// SentQuery is true if the incoming request sent the full query
|
||||||
|
SentQuery bool
|
||||||
|
}
|
||||||
|
|
||||||
|
const apqExtension = "APQ"
|
||||||
|
|
||||||
|
var _ interface {
|
||||||
|
graphql.OperationParameterMutator
|
||||||
|
graphql.HandlerExtension
|
||||||
|
} = AutomaticPersistedQuery{}
|
||||||
|
|
||||||
|
func (a AutomaticPersistedQuery) ExtensionName() string {
|
||||||
|
return "AutomaticPersistedQuery"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a AutomaticPersistedQuery) Validate(schema graphql.ExecutableSchema) error {
|
||||||
|
if a.Cache == nil {
|
||||||
|
return fmt.Errorf("AutomaticPersistedQuery.Cache can not be nil")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a AutomaticPersistedQuery) MutateOperationParameters(ctx context.Context, rawParams *graphql.RawParams) *gqlerror.Error {
|
||||||
|
if rawParams.Extensions["persistedQuery"] == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var extension struct {
|
||||||
|
Sha256 string `mapstructure:"sha256Hash"`
|
||||||
|
Version int64 `mapstructure:"version"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := mapstructure.Decode(rawParams.Extensions["persistedQuery"], &extension); err != nil {
|
||||||
|
return gqlerror.Errorf("invalid APQ extension data")
|
||||||
|
}
|
||||||
|
|
||||||
|
if extension.Version != 1 {
|
||||||
|
return gqlerror.Errorf("unsupported APQ version")
|
||||||
|
}
|
||||||
|
|
||||||
|
fullQuery := false
|
||||||
|
if rawParams.Query == "" {
|
||||||
|
// client sent optimistic query hash without query string, get it from the cache
|
||||||
|
query, ok := a.Cache.Get(ctx, extension.Sha256)
|
||||||
|
if !ok {
|
||||||
|
err := gqlerror.Errorf(errPersistedQueryNotFound)
|
||||||
|
errcode.Set(err, errPersistedQueryNotFoundCode)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rawParams.Query = query.(string)
|
||||||
|
} else {
|
||||||
|
// client sent optimistic query hash with query string, verify and store it
|
||||||
|
if computeQueryHash(rawParams.Query) != extension.Sha256 {
|
||||||
|
return gqlerror.Errorf("provided APQ hash does not match query")
|
||||||
|
}
|
||||||
|
a.Cache.Add(ctx, extension.Sha256, rawParams.Query)
|
||||||
|
fullQuery = true
|
||||||
|
}
|
||||||
|
|
||||||
|
graphql.GetOperationContext(ctx).Stats.SetExtension(apqExtension, &ApqStats{
|
||||||
|
Hash: extension.Sha256,
|
||||||
|
SentQuery: fullQuery,
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetApqStats(ctx context.Context) *ApqStats {
|
||||||
|
rc := graphql.GetOperationContext(ctx)
|
||||||
|
if rc == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
s, _ := rc.Stats.GetExtension(apqExtension).(*ApqStats)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func computeQueryHash(query string) string {
|
||||||
|
b := sha256.Sum256([]byte(query))
|
||||||
|
return hex.EncodeToString(b[:])
|
||||||
|
}
|
||||||
88
vendor/github.com/99designs/gqlgen/graphql/handler/extension/complexity.go
generated
vendored
Normal file
88
vendor/github.com/99designs/gqlgen/graphql/handler/extension/complexity.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
package extension
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/99designs/gqlgen/complexity"
|
||||||
|
"github.com/99designs/gqlgen/graphql"
|
||||||
|
"github.com/99designs/gqlgen/graphql/errcode"
|
||||||
|
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||||
|
)
|
||||||
|
|
||||||
|
const errComplexityLimit = "COMPLEXITY_LIMIT_EXCEEDED"
|
||||||
|
|
||||||
|
// ComplexityLimit allows you to define a limit on query complexity
|
||||||
|
//
|
||||||
|
// If a query is submitted that exceeds the limit, a 422 status code will be returned.
|
||||||
|
type ComplexityLimit struct {
|
||||||
|
Func func(ctx context.Context, rc *graphql.OperationContext) int
|
||||||
|
|
||||||
|
es graphql.ExecutableSchema
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ interface {
|
||||||
|
graphql.OperationContextMutator
|
||||||
|
graphql.HandlerExtension
|
||||||
|
} = &ComplexityLimit{}
|
||||||
|
|
||||||
|
const complexityExtension = "ComplexityLimit"
|
||||||
|
|
||||||
|
type ComplexityStats struct {
|
||||||
|
// The calculated complexity for this request
|
||||||
|
Complexity int
|
||||||
|
|
||||||
|
// The complexity limit for this request returned by the extension func
|
||||||
|
ComplexityLimit int
|
||||||
|
}
|
||||||
|
|
||||||
|
// FixedComplexityLimit sets a complexity limit that does not change
|
||||||
|
func FixedComplexityLimit(limit int) *ComplexityLimit {
|
||||||
|
return &ComplexityLimit{
|
||||||
|
Func: func(ctx context.Context, rc *graphql.OperationContext) int {
|
||||||
|
return limit
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ComplexityLimit) ExtensionName() string {
|
||||||
|
return complexityExtension
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ComplexityLimit) Validate(schema graphql.ExecutableSchema) error {
|
||||||
|
if c.Func == nil {
|
||||||
|
return fmt.Errorf("ComplexityLimit func can not be nil")
|
||||||
|
}
|
||||||
|
c.es = schema
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ComplexityLimit) MutateOperationContext(ctx context.Context, rc *graphql.OperationContext) *gqlerror.Error {
|
||||||
|
op := rc.Doc.Operations.ForName(rc.OperationName)
|
||||||
|
complexity := complexity.Calculate(c.es, op, rc.Variables)
|
||||||
|
|
||||||
|
limit := c.Func(ctx, rc)
|
||||||
|
|
||||||
|
rc.Stats.SetExtension(complexityExtension, &ComplexityStats{
|
||||||
|
Complexity: complexity,
|
||||||
|
ComplexityLimit: limit,
|
||||||
|
})
|
||||||
|
|
||||||
|
if complexity > limit {
|
||||||
|
err := gqlerror.Errorf("operation has complexity %d, which exceeds the limit of %d", complexity, limit)
|
||||||
|
errcode.Set(err, errComplexityLimit)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetComplexityStats(ctx context.Context) *ComplexityStats {
|
||||||
|
rc := graphql.GetOperationContext(ctx)
|
||||||
|
if rc == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
s, _ := rc.Stats.GetExtension(complexityExtension).(*ComplexityStats)
|
||||||
|
return s
|
||||||
|
}
|
||||||
29
vendor/github.com/99designs/gqlgen/graphql/handler/extension/introspection.go
generated
vendored
Normal file
29
vendor/github.com/99designs/gqlgen/graphql/handler/extension/introspection.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package extension
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/99designs/gqlgen/graphql"
|
||||||
|
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EnableIntrospection enables clients to reflect all of the types available on the graph.
|
||||||
|
type Introspection struct{}
|
||||||
|
|
||||||
|
var _ interface {
|
||||||
|
graphql.OperationContextMutator
|
||||||
|
graphql.HandlerExtension
|
||||||
|
} = Introspection{}
|
||||||
|
|
||||||
|
func (c Introspection) ExtensionName() string {
|
||||||
|
return "Introspection"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Introspection) Validate(schema graphql.ExecutableSchema) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Introspection) MutateOperationContext(ctx context.Context, rc *graphql.OperationContext) *gqlerror.Error {
|
||||||
|
rc.DisableIntrospection = false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
32
vendor/github.com/99designs/gqlgen/graphql/handler/lru/lru.go
generated
vendored
Normal file
32
vendor/github.com/99designs/gqlgen/graphql/handler/lru/lru.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package lru
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/99designs/gqlgen/graphql"
|
||||||
|
lru "github.com/hashicorp/golang-lru"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LRU struct {
|
||||||
|
lru *lru.Cache
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ graphql.Cache = &LRU{}
|
||||||
|
|
||||||
|
func New(size int) *LRU {
|
||||||
|
cache, err := lru.New(size)
|
||||||
|
if err != nil {
|
||||||
|
// An error is only returned for non-positive cache size
|
||||||
|
// and we already checked for that.
|
||||||
|
panic("unexpected error creating cache: " + err.Error())
|
||||||
|
}
|
||||||
|
return &LRU{cache}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l LRU) Get(ctx context.Context, key string) (value interface{}, ok bool) {
|
||||||
|
return l.lru.Get(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l LRU) Add(ctx context.Context, key string, value interface{}) {
|
||||||
|
l.lru.Add(key, value)
|
||||||
|
}
|
||||||
180
vendor/github.com/99designs/gqlgen/graphql/handler/server.go
generated
vendored
Normal file
180
vendor/github.com/99designs/gqlgen/graphql/handler/server.go
generated
vendored
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/99designs/gqlgen/graphql"
|
||||||
|
"github.com/99designs/gqlgen/graphql/executor"
|
||||||
|
"github.com/99designs/gqlgen/graphql/handler/extension"
|
||||||
|
"github.com/99designs/gqlgen/graphql/handler/lru"
|
||||||
|
"github.com/99designs/gqlgen/graphql/handler/transport"
|
||||||
|
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
Server struct {
|
||||||
|
transports []graphql.Transport
|
||||||
|
exec *executor.Executor
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func New(es graphql.ExecutableSchema) *Server {
|
||||||
|
return &Server{
|
||||||
|
exec: executor.New(es),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDefaultServer(es graphql.ExecutableSchema) *Server {
|
||||||
|
srv := New(es)
|
||||||
|
|
||||||
|
srv.AddTransport(transport.Websocket{
|
||||||
|
KeepAlivePingInterval: 10 * time.Second,
|
||||||
|
})
|
||||||
|
srv.AddTransport(transport.Options{})
|
||||||
|
srv.AddTransport(transport.GET{})
|
||||||
|
srv.AddTransport(transport.POST{})
|
||||||
|
srv.AddTransport(transport.MultipartForm{})
|
||||||
|
|
||||||
|
srv.SetQueryCache(lru.New(1000))
|
||||||
|
|
||||||
|
srv.Use(extension.Introspection{})
|
||||||
|
srv.Use(extension.AutomaticPersistedQuery{
|
||||||
|
Cache: lru.New(100),
|
||||||
|
})
|
||||||
|
|
||||||
|
return srv
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) AddTransport(transport graphql.Transport) {
|
||||||
|
s.transports = append(s.transports, transport)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) SetErrorPresenter(f graphql.ErrorPresenterFunc) {
|
||||||
|
s.exec.SetErrorPresenter(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) SetRecoverFunc(f graphql.RecoverFunc) {
|
||||||
|
s.exec.SetRecoverFunc(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) SetQueryCache(cache graphql.Cache) {
|
||||||
|
s.exec.SetQueryCache(cache)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Use(extension graphql.HandlerExtension) {
|
||||||
|
s.exec.Use(extension)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AroundFields is a convenience method for creating an extension that only implements field middleware
|
||||||
|
func (s *Server) AroundFields(f graphql.FieldMiddleware) {
|
||||||
|
s.exec.AroundFields(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AroundOperations is a convenience method for creating an extension that only implements operation middleware
|
||||||
|
func (s *Server) AroundOperations(f graphql.OperationMiddleware) {
|
||||||
|
s.exec.AroundOperations(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AroundResponses is a convenience method for creating an extension that only implements response middleware
|
||||||
|
func (s *Server) AroundResponses(f graphql.ResponseMiddleware) {
|
||||||
|
s.exec.AroundResponses(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) getTransport(r *http.Request) graphql.Transport {
|
||||||
|
for _, t := range s.transports {
|
||||||
|
if t.Supports(r) {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
err := s.exec.PresentRecoveredError(r.Context(), err)
|
||||||
|
resp := &graphql.Response{Errors: []*gqlerror.Error{err}}
|
||||||
|
b, _ := json.Marshal(resp)
|
||||||
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||||
|
w.Write(b)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
r = r.WithContext(graphql.StartOperationTrace(r.Context()))
|
||||||
|
|
||||||
|
transport := s.getTransport(r)
|
||||||
|
if transport == nil {
|
||||||
|
sendErrorf(w, http.StatusBadRequest, "transport not supported")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
transport.Do(w, r, s.exec)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendError(w http.ResponseWriter, code int, errors ...*gqlerror.Error) {
|
||||||
|
w.WriteHeader(code)
|
||||||
|
b, err := json.Marshal(&graphql.Response{Errors: errors})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
w.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendErrorf(w http.ResponseWriter, code int, format string, args ...interface{}) {
|
||||||
|
sendError(w, code, &gqlerror.Error{Message: fmt.Sprintf(format, args...)})
|
||||||
|
}
|
||||||
|
|
||||||
|
type OperationFunc func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler
|
||||||
|
|
||||||
|
func (r OperationFunc) ExtensionName() string {
|
||||||
|
return "InlineOperationFunc"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r OperationFunc) Validate(schema graphql.ExecutableSchema) error {
|
||||||
|
if r == nil {
|
||||||
|
return fmt.Errorf("OperationFunc can not be nil")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r OperationFunc) InterceptOperation(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler {
|
||||||
|
return r(ctx, next)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResponseFunc func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response
|
||||||
|
|
||||||
|
func (r ResponseFunc) ExtensionName() string {
|
||||||
|
return "InlineResponseFunc"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r ResponseFunc) Validate(schema graphql.ExecutableSchema) error {
|
||||||
|
if r == nil {
|
||||||
|
return fmt.Errorf("ResponseFunc can not be nil")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r ResponseFunc) InterceptResponse(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
|
||||||
|
return r(ctx, next)
|
||||||
|
}
|
||||||
|
|
||||||
|
type FieldFunc func(ctx context.Context, next graphql.Resolver) (res interface{}, err error)
|
||||||
|
|
||||||
|
func (f FieldFunc) ExtensionName() string {
|
||||||
|
return "InlineFieldFunc"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f FieldFunc) Validate(schema graphql.ExecutableSchema) error {
|
||||||
|
if f == nil {
|
||||||
|
return fmt.Errorf("FieldFunc can not be nil")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f FieldFunc) InterceptField(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
|
||||||
|
return f(ctx, next)
|
||||||
|
}
|
||||||
26
vendor/github.com/99designs/gqlgen/graphql/handler/transport/error.go
generated
vendored
Normal file
26
vendor/github.com/99designs/gqlgen/graphql/handler/transport/error.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package transport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/99designs/gqlgen/graphql"
|
||||||
|
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SendError sends a best effort error to a raw response writer. It assumes the client can understand the standard
|
||||||
|
// json error response
|
||||||
|
func SendError(w http.ResponseWriter, code int, errors ...*gqlerror.Error) {
|
||||||
|
w.WriteHeader(code)
|
||||||
|
b, err := json.Marshal(&graphql.Response{Errors: errors})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
w.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendErrorf wraps SendError to add formatted messages
|
||||||
|
func SendErrorf(w http.ResponseWriter, code int, format string, args ...interface{}) {
|
||||||
|
SendError(w, code, &gqlerror.Error{Message: fmt.Sprintf(format, args...)})
|
||||||
|
}
|
||||||
208
vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_form.go
generated
vendored
Normal file
208
vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_form.go
generated
vendored
Normal file
@@ -0,0 +1,208 @@
|
|||||||
|
package transport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"mime"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/99designs/gqlgen/graphql"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MultipartForm the Multipart request spec https://github.com/jaydenseric/graphql-multipart-request-spec
|
||||||
|
type MultipartForm struct {
|
||||||
|
// MaxUploadSize sets the maximum number of bytes used to parse a request body
|
||||||
|
// as multipart/form-data.
|
||||||
|
MaxUploadSize int64
|
||||||
|
|
||||||
|
// MaxMemory defines the maximum number of bytes used to parse a request body
|
||||||
|
// as multipart/form-data in memory, with the remainder stored on disk in
|
||||||
|
// temporary files.
|
||||||
|
MaxMemory int64
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ graphql.Transport = MultipartForm{}
|
||||||
|
|
||||||
|
func (f MultipartForm) Supports(r *http.Request) bool {
|
||||||
|
if r.Header.Get("Upgrade") != "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.Method == "POST" && mediaType == "multipart/form-data"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f MultipartForm) maxUploadSize() int64 {
|
||||||
|
if f.MaxUploadSize == 0 {
|
||||||
|
return 32 << 20
|
||||||
|
}
|
||||||
|
return f.MaxUploadSize
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f MultipartForm) maxMemory() int64 {
|
||||||
|
if f.MaxMemory == 0 {
|
||||||
|
return 32 << 20
|
||||||
|
}
|
||||||
|
return f.MaxMemory
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f MultipartForm) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
start := graphql.Now()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
if r.ContentLength > f.maxUploadSize() {
|
||||||
|
writeJsonError(w, "failed to parse multipart form, request body too large")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r.Body = http.MaxBytesReader(w, r.Body, f.maxUploadSize())
|
||||||
|
if err = r.ParseMultipartForm(f.maxMemory()); err != nil {
|
||||||
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||||
|
if strings.Contains(err.Error(), "request body too large") {
|
||||||
|
writeJsonError(w, "failed to parse multipart form, request body too large")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeJsonError(w, "failed to parse multipart form")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer r.Body.Close()
|
||||||
|
|
||||||
|
var params graphql.RawParams
|
||||||
|
|
||||||
|
if err = jsonDecode(strings.NewReader(r.Form.Get("operations")), ¶ms); err != nil {
|
||||||
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||||
|
writeJsonError(w, "operations form field could not be decoded")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var uploadsMap = map[string][]string{}
|
||||||
|
if err = json.Unmarshal([]byte(r.Form.Get("map")), &uploadsMap); err != nil {
|
||||||
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||||
|
writeJsonError(w, "map form field could not be decoded")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var upload graphql.Upload
|
||||||
|
for key, paths := range uploadsMap {
|
||||||
|
if len(paths) == 0 {
|
||||||
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||||
|
writeJsonErrorf(w, "invalid empty operations paths list for key %s", key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file, header, err := r.FormFile(key)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||||
|
writeJsonErrorf(w, "failed to get key %s from form", key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
if len(paths) == 1 {
|
||||||
|
upload = graphql.Upload{
|
||||||
|
File: file,
|
||||||
|
Size: header.Size,
|
||||||
|
Filename: header.Filename,
|
||||||
|
ContentType: header.Header.Get("Content-Type"),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := params.AddUpload(upload, key, paths[0]); err != nil {
|
||||||
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||||
|
writeJsonGraphqlError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if r.ContentLength < f.maxMemory() {
|
||||||
|
fileBytes, err := ioutil.ReadAll(file)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||||
|
writeJsonErrorf(w, "failed to read file for key %s", key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, path := range paths {
|
||||||
|
upload = graphql.Upload{
|
||||||
|
File: &bytesReader{s: &fileBytes, i: 0, prevRune: -1},
|
||||||
|
Size: header.Size,
|
||||||
|
Filename: header.Filename,
|
||||||
|
ContentType: header.Header.Get("Content-Type"),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := params.AddUpload(upload, key, path); err != nil {
|
||||||
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||||
|
writeJsonGraphqlError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tmpFile, err := ioutil.TempFile(os.TempDir(), "gqlgen-")
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||||
|
writeJsonErrorf(w, "failed to create temp file for key %s", key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tmpName := tmpFile.Name()
|
||||||
|
defer func() {
|
||||||
|
_ = os.Remove(tmpName)
|
||||||
|
}()
|
||||||
|
_, err = io.Copy(tmpFile, file)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||||
|
if err := tmpFile.Close(); err != nil {
|
||||||
|
writeJsonErrorf(w, "failed to copy to temp file and close temp file for key %s", key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeJsonErrorf(w, "failed to copy to temp file for key %s", key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := tmpFile.Close(); err != nil {
|
||||||
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||||
|
writeJsonErrorf(w, "failed to close temp file for key %s", key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, path := range paths {
|
||||||
|
pathTmpFile, err := os.Open(tmpName)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||||
|
writeJsonErrorf(w, "failed to open temp file for key %s", key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer pathTmpFile.Close()
|
||||||
|
upload = graphql.Upload{
|
||||||
|
File: pathTmpFile,
|
||||||
|
Size: header.Size,
|
||||||
|
Filename: header.Filename,
|
||||||
|
ContentType: header.Header.Get("Content-Type"),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := params.AddUpload(upload, key, path); err != nil {
|
||||||
|
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||||
|
writeJsonGraphqlError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
params.ReadTime = graphql.TraceTiming{
|
||||||
|
Start: start,
|
||||||
|
End: graphql.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
rc, gerr := exec.CreateOperationContext(r.Context(), ¶ms)
|
||||||
|
if gerr != nil {
|
||||||
|
resp := exec.DispatchError(graphql.WithOperationContext(r.Context(), rc), gerr)
|
||||||
|
w.WriteHeader(statusFor(gerr))
|
||||||
|
writeJson(w, resp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
responses, ctx := exec.DispatchOperation(r.Context(), rc)
|
||||||
|
writeJson(w, responses(ctx))
|
||||||
|
}
|
||||||
87
vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_get.go
generated
vendored
Normal file
87
vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_get.go
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
package transport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/99designs/gqlgen/graphql"
|
||||||
|
"github.com/99designs/gqlgen/graphql/errcode"
|
||||||
|
"github.com/vektah/gqlparser/v2/ast"
|
||||||
|
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GET implements the GET side of the default HTTP transport
|
||||||
|
// defined in https://github.com/APIs-guru/graphql-over-http#get
|
||||||
|
type GET struct{}
|
||||||
|
|
||||||
|
var _ graphql.Transport = GET{}
|
||||||
|
|
||||||
|
func (h GET) Supports(r *http.Request) bool {
|
||||||
|
if r.Header.Get("Upgrade") != "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.Method == "GET"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h GET) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
raw := &graphql.RawParams{
|
||||||
|
Query: r.URL.Query().Get("query"),
|
||||||
|
OperationName: r.URL.Query().Get("operationName"),
|
||||||
|
}
|
||||||
|
raw.ReadTime.Start = graphql.Now()
|
||||||
|
|
||||||
|
if variables := r.URL.Query().Get("variables"); variables != "" {
|
||||||
|
if err := jsonDecode(strings.NewReader(variables), &raw.Variables); err != nil {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
writeJsonError(w, "variables could not be decoded")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if extensions := r.URL.Query().Get("extensions"); extensions != "" {
|
||||||
|
if err := jsonDecode(strings.NewReader(extensions), &raw.Extensions); err != nil {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
writeJsonError(w, "extensions could not be decoded")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
raw.ReadTime.End = graphql.Now()
|
||||||
|
|
||||||
|
rc, err := exec.CreateOperationContext(r.Context(), raw)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(statusFor(err))
|
||||||
|
resp := exec.DispatchError(graphql.WithOperationContext(r.Context(), rc), err)
|
||||||
|
writeJson(w, resp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
op := rc.Doc.Operations.ForName(rc.OperationName)
|
||||||
|
if op.Operation != ast.Query {
|
||||||
|
w.WriteHeader(http.StatusNotAcceptable)
|
||||||
|
writeJsonError(w, "GET requests only allow query operations")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
responses, ctx := exec.DispatchOperation(r.Context(), rc)
|
||||||
|
writeJson(w, responses(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
func jsonDecode(r io.Reader, val interface{}) error {
|
||||||
|
dec := json.NewDecoder(r)
|
||||||
|
dec.UseNumber()
|
||||||
|
return dec.Decode(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
func statusFor(errs gqlerror.List) int {
|
||||||
|
switch errcode.GetErrorKind(errs) {
|
||||||
|
case errcode.KindProtocol:
|
||||||
|
return http.StatusUnprocessableEntity
|
||||||
|
default:
|
||||||
|
return http.StatusOK
|
||||||
|
}
|
||||||
|
}
|
||||||
54
vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_post.go
generated
vendored
Normal file
54
vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_post.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package transport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"mime"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/99designs/gqlgen/graphql"
|
||||||
|
)
|
||||||
|
|
||||||
|
// POST implements the POST side of the default HTTP transport
|
||||||
|
// defined in https://github.com/APIs-guru/graphql-over-http#post
|
||||||
|
type POST struct{}
|
||||||
|
|
||||||
|
var _ graphql.Transport = POST{}
|
||||||
|
|
||||||
|
func (h POST) Supports(r *http.Request) bool {
|
||||||
|
if r.Header.Get("Upgrade") != "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.Method == "POST" && mediaType == "application/json"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h POST) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
var params *graphql.RawParams
|
||||||
|
start := graphql.Now()
|
||||||
|
if err := jsonDecode(r.Body, ¶ms); err != nil {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
writeJsonErrorf(w, "json body could not be decoded: "+err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
params.ReadTime = graphql.TraceTiming{
|
||||||
|
Start: start,
|
||||||
|
End: graphql.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
rc, err := exec.CreateOperationContext(r.Context(), params)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(statusFor(err))
|
||||||
|
resp := exec.DispatchError(graphql.WithOperationContext(r.Context(), rc), err)
|
||||||
|
writeJson(w, resp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx := graphql.WithOperationContext(r.Context(), rc)
|
||||||
|
responses, ctx := exec.DispatchOperation(ctx, rc)
|
||||||
|
writeJson(w, responses(ctx))
|
||||||
|
}
|
||||||
26
vendor/github.com/99designs/gqlgen/graphql/handler/transport/options.go
generated
vendored
Normal file
26
vendor/github.com/99designs/gqlgen/graphql/handler/transport/options.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package transport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/99designs/gqlgen/graphql"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Options responds to http OPTIONS and HEAD requests
|
||||||
|
type Options struct{}
|
||||||
|
|
||||||
|
var _ graphql.Transport = Options{}
|
||||||
|
|
||||||
|
func (o Options) Supports(r *http.Request) bool {
|
||||||
|
return r.Method == "HEAD" || r.Method == "OPTIONS"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o Options) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) {
|
||||||
|
switch r.Method {
|
||||||
|
case http.MethodOptions:
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Header().Set("Allow", "OPTIONS, GET, POST")
|
||||||
|
case http.MethodHead:
|
||||||
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||||
|
}
|
||||||
|
}
|
||||||
25
vendor/github.com/99designs/gqlgen/graphql/handler/transport/reader.go
generated
vendored
Normal file
25
vendor/github.com/99designs/gqlgen/graphql/handler/transport/reader.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package transport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type bytesReader struct {
|
||||||
|
s *[]byte
|
||||||
|
i int64 // current reading index
|
||||||
|
prevRune int // index of previous rune; or < 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *bytesReader) Read(b []byte) (n int, err error) {
|
||||||
|
if r.s == nil {
|
||||||
|
return 0, errors.New("byte slice pointer is nil")
|
||||||
|
}
|
||||||
|
if r.i >= int64(len(*r.s)) {
|
||||||
|
return 0, io.EOF
|
||||||
|
}
|
||||||
|
r.prevRune = -1
|
||||||
|
n = copy(b, (*r.s)[r.i:])
|
||||||
|
r.i += int64(n)
|
||||||
|
return
|
||||||
|
}
|
||||||
30
vendor/github.com/99designs/gqlgen/graphql/handler/transport/util.go
generated
vendored
Normal file
30
vendor/github.com/99designs/gqlgen/graphql/handler/transport/util.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package transport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/99designs/gqlgen/graphql"
|
||||||
|
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||||
|
)
|
||||||
|
|
||||||
|
func writeJson(w io.Writer, response *graphql.Response) {
|
||||||
|
b, err := json.Marshal(response)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
w.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeJsonError(w io.Writer, msg string) {
|
||||||
|
writeJson(w, &graphql.Response{Errors: gqlerror.List{{Message: msg}}})
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeJsonErrorf(w io.Writer, format string, args ...interface{}) {
|
||||||
|
writeJson(w, &graphql.Response{Errors: gqlerror.List{{Message: fmt.Sprintf(format, args...)}}})
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeJsonGraphqlError(w io.Writer, err ...*gqlerror.Error) {
|
||||||
|
writeJson(w, &graphql.Response{Errors: err})
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package handler
|
package transport
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -11,12 +11,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/graphql"
|
"github.com/99designs/gqlgen/graphql"
|
||||||
|
"github.com/99designs/gqlgen/graphql/errcode"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/hashicorp/golang-lru"
|
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||||
"github.com/vektah/gqlparser"
|
|
||||||
"github.com/vektah/gqlparser/ast"
|
|
||||||
"github.com/vektah/gqlparser/gqlerror"
|
|
||||||
"github.com/vektah/gqlparser/validator"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -32,42 +29,53 @@ const (
|
|||||||
connectionKeepAliveMsg = "ka" // Server -> Client
|
connectionKeepAliveMsg = "ka" // Server -> Client
|
||||||
)
|
)
|
||||||
|
|
||||||
type operationMessage struct {
|
type (
|
||||||
|
Websocket struct {
|
||||||
|
Upgrader websocket.Upgrader
|
||||||
|
InitFunc WebsocketInitFunc
|
||||||
|
KeepAlivePingInterval time.Duration
|
||||||
|
}
|
||||||
|
wsConnection struct {
|
||||||
|
Websocket
|
||||||
|
ctx context.Context
|
||||||
|
conn *websocket.Conn
|
||||||
|
active map[string]context.CancelFunc
|
||||||
|
mu sync.Mutex
|
||||||
|
keepAliveTicker *time.Ticker
|
||||||
|
exec graphql.GraphExecutor
|
||||||
|
|
||||||
|
initPayload InitPayload
|
||||||
|
}
|
||||||
|
operationMessage struct {
|
||||||
Payload json.RawMessage `json:"payload,omitempty"`
|
Payload json.RawMessage `json:"payload,omitempty"`
|
||||||
ID string `json:"id,omitempty"`
|
ID string `json:"id,omitempty"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
}
|
||||||
|
WebsocketInitFunc func(ctx context.Context, initPayload InitPayload) (context.Context, error)
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ graphql.Transport = Websocket{}
|
||||||
|
|
||||||
|
func (t Websocket) Supports(r *http.Request) bool {
|
||||||
|
return r.Header.Get("Upgrade") != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
type wsConnection struct {
|
func (t Websocket) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) {
|
||||||
ctx context.Context
|
ws, err := t.Upgrader.Upgrade(w, r, http.Header{
|
||||||
conn *websocket.Conn
|
|
||||||
exec graphql.ExecutableSchema
|
|
||||||
active map[string]context.CancelFunc
|
|
||||||
mu sync.Mutex
|
|
||||||
cfg *Config
|
|
||||||
cache *lru.Cache
|
|
||||||
keepAliveTicker *time.Ticker
|
|
||||||
|
|
||||||
initPayload InitPayload
|
|
||||||
}
|
|
||||||
|
|
||||||
func connectWs(exec graphql.ExecutableSchema, w http.ResponseWriter, r *http.Request, cfg *Config, cache *lru.Cache) {
|
|
||||||
ws, err := cfg.upgrader.Upgrade(w, r, http.Header{
|
|
||||||
"Sec-Websocket-Protocol": []string{"graphql-ws"},
|
"Sec-Websocket-Protocol": []string{"graphql-ws"},
|
||||||
})
|
})
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
conn := wsConnection{
|
conn := wsConnection{
|
||||||
active: map[string]context.CancelFunc{},
|
active: map[string]context.CancelFunc{},
|
||||||
exec: exec,
|
|
||||||
conn: ws,
|
conn: ws,
|
||||||
ctx: r.Context(),
|
ctx: r.Context(),
|
||||||
cfg: cfg,
|
exec: exec,
|
||||||
cache: cache,
|
Websocket: t,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !conn.init() {
|
if !conn.init() {
|
||||||
@@ -94,7 +102,18 @@ func (c *wsConnection) init() bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.InitFunc != nil {
|
||||||
|
ctx, err := c.InitFunc(c.ctx, c.initPayload)
|
||||||
|
if err != nil {
|
||||||
|
c.sendConnectionError(err.Error())
|
||||||
|
c.close(websocket.CloseNormalClosure, "terminated")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
c.ctx = ctx
|
||||||
|
}
|
||||||
|
|
||||||
c.write(&operationMessage{Type: connectionAckMsg})
|
c.write(&operationMessage{Type: connectionAckMsg})
|
||||||
|
c.write(&operationMessage{Type: connectionKeepAliveMsg})
|
||||||
case connectionTerminateMsg:
|
case connectionTerminateMsg:
|
||||||
c.close(websocket.CloseNormalClosure, "terminated")
|
c.close(websocket.CloseNormalClosure, "terminated")
|
||||||
return false
|
return false
|
||||||
@@ -117,18 +136,22 @@ func (c *wsConnection) run() {
|
|||||||
// We create a cancellation that will shutdown the keep-alive when we leave
|
// We create a cancellation that will shutdown the keep-alive when we leave
|
||||||
// this function.
|
// this function.
|
||||||
ctx, cancel := context.WithCancel(c.ctx)
|
ctx, cancel := context.WithCancel(c.ctx)
|
||||||
defer cancel()
|
defer func() {
|
||||||
|
cancel()
|
||||||
|
c.close(websocket.CloseAbnormalClosure, "unexpected closure")
|
||||||
|
}()
|
||||||
|
|
||||||
// Create a timer that will fire every interval to keep the connection alive.
|
// Create a timer that will fire every interval to keep the connection alive.
|
||||||
if c.cfg.connectionKeepAlivePingInterval != 0 {
|
if c.KeepAlivePingInterval != 0 {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
c.keepAliveTicker = time.NewTicker(c.cfg.connectionKeepAlivePingInterval)
|
c.keepAliveTicker = time.NewTicker(c.KeepAlivePingInterval)
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
|
|
||||||
go c.keepAlive(ctx)
|
go c.keepAlive(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
start := graphql.Now()
|
||||||
message := c.readOp()
|
message := c.readOp()
|
||||||
if message == nil {
|
if message == nil {
|
||||||
return
|
return
|
||||||
@@ -136,19 +159,14 @@ func (c *wsConnection) run() {
|
|||||||
|
|
||||||
switch message.Type {
|
switch message.Type {
|
||||||
case startMsg:
|
case startMsg:
|
||||||
if !c.subscribe(message) {
|
c.subscribe(start, message)
|
||||||
return
|
|
||||||
}
|
|
||||||
case stopMsg:
|
case stopMsg:
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
closer := c.active[message.ID]
|
closer := c.active[message.ID]
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
if closer == nil {
|
if closer != nil {
|
||||||
c.sendError(message.ID, gqlerror.Errorf("%s is not running, cannot stop", message.ID))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
closer()
|
closer()
|
||||||
|
}
|
||||||
case connectionTerminateMsg:
|
case connectionTerminateMsg:
|
||||||
c.close(websocket.CloseNormalClosure, "terminated")
|
c.close(websocket.CloseNormalClosure, "terminated")
|
||||||
return
|
return
|
||||||
@@ -172,108 +190,90 @@ func (c *wsConnection) keepAlive(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *wsConnection) subscribe(message *operationMessage) bool {
|
func (c *wsConnection) subscribe(start time.Time, message *operationMessage) {
|
||||||
var reqParams params
|
ctx := graphql.StartOperationTrace(c.ctx)
|
||||||
if err := jsonDecode(bytes.NewReader(message.Payload), &reqParams); err != nil {
|
var params *graphql.RawParams
|
||||||
c.sendConnectionError("invalid json")
|
if err := jsonDecode(bytes.NewReader(message.Payload), ¶ms); err != nil {
|
||||||
return false
|
c.sendError(message.ID, &gqlerror.Error{Message: "invalid json"})
|
||||||
|
c.complete(message.ID)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
params.ReadTime = graphql.TraceTiming{
|
||||||
doc *ast.QueryDocument
|
Start: start,
|
||||||
cacheHit bool
|
End: graphql.Now(),
|
||||||
)
|
|
||||||
if c.cache != nil {
|
|
||||||
val, ok := c.cache.Get(reqParams.Query)
|
|
||||||
if ok {
|
|
||||||
doc = val.(*ast.QueryDocument)
|
|
||||||
cacheHit = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !cacheHit {
|
|
||||||
var qErr gqlerror.List
|
|
||||||
doc, qErr = gqlparser.LoadQuery(c.exec.Schema(), reqParams.Query)
|
|
||||||
if qErr != nil {
|
|
||||||
c.sendError(message.ID, qErr...)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if c.cache != nil {
|
|
||||||
c.cache.Add(reqParams.Query, doc)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
op := doc.Operations.ForName(reqParams.OperationName)
|
rc, err := c.exec.CreateOperationContext(ctx, params)
|
||||||
if op == nil {
|
|
||||||
c.sendError(message.ID, gqlerror.Errorf("operation %s not found", reqParams.OperationName))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
vars, err := validator.VariableValues(c.exec.Schema(), op, reqParams.Variables)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.sendError(message.ID, err)
|
resp := c.exec.DispatchError(graphql.WithOperationContext(ctx, rc), err)
|
||||||
return true
|
switch errcode.GetErrorKind(err) {
|
||||||
|
case errcode.KindProtocol:
|
||||||
|
c.sendError(message.ID, resp.Errors...)
|
||||||
|
default:
|
||||||
|
c.sendResponse(message.ID, &graphql.Response{Errors: err})
|
||||||
}
|
}
|
||||||
reqCtx := c.cfg.newRequestContext(c.exec, doc, op, reqParams.Query, vars)
|
|
||||||
ctx := graphql.WithRequestContext(c.ctx, reqCtx)
|
c.complete(message.ID)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = graphql.WithOperationContext(ctx, rc)
|
||||||
|
|
||||||
if c.initPayload != nil {
|
if c.initPayload != nil {
|
||||||
ctx = withInitPayload(ctx, c.initPayload)
|
ctx = withInitPayload(ctx, c.initPayload)
|
||||||
}
|
}
|
||||||
|
|
||||||
if op.Operation != ast.Subscription {
|
|
||||||
var result *graphql.Response
|
|
||||||
if op.Operation == ast.Query {
|
|
||||||
result = c.exec.Query(ctx, op)
|
|
||||||
} else {
|
|
||||||
result = c.exec.Mutation(ctx, op)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.sendData(message.ID, result)
|
|
||||||
c.write(&operationMessage{ID: message.ID, Type: completeMsg})
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
c.active[message.ID] = cancel
|
c.active[message.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 := reqCtx.Recover(ctx, r)
|
userErr := rc.Recover(ctx, r)
|
||||||
c.sendError(message.ID, &gqlerror.Error{Message: userErr.Error()})
|
c.sendError(message.ID, &gqlerror.Error{Message: userErr.Error()})
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
next := c.exec.Subscription(ctx, op)
|
responses, ctx := c.exec.DispatchOperation(ctx, rc)
|
||||||
for result := next(); result != nil; result = next() {
|
for {
|
||||||
c.sendData(message.ID, result)
|
response := responses(ctx)
|
||||||
|
if response == nil {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
c.write(&operationMessage{ID: message.ID, Type: completeMsg})
|
c.sendResponse(message.ID, response)
|
||||||
|
}
|
||||||
|
c.complete(message.ID)
|
||||||
|
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
delete(c.active, message.ID)
|
delete(c.active, message.ID)
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
cancel()
|
cancel()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *wsConnection) sendData(id string, response *graphql.Response) {
|
func (c *wsConnection) sendResponse(id string, response *graphql.Response) {
|
||||||
b, err := json.Marshal(response)
|
b, err := json.Marshal(response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.sendError(id, gqlerror.Errorf("unable to encode json response: %s", err.Error()))
|
panic(err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
c.write(&operationMessage{
|
||||||
|
Payload: b,
|
||||||
|
ID: id,
|
||||||
|
Type: dataMsg,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
c.write(&operationMessage{Type: dataMsg, ID: id, Payload: b})
|
func (c *wsConnection) complete(id string) {
|
||||||
|
c.write(&operationMessage{ID: id, Type: completeMsg})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *wsConnection) sendError(id string, errors ...*gqlerror.Error) {
|
func (c *wsConnection) sendError(id string, errors ...*gqlerror.Error) {
|
||||||
var errs []error
|
errs := make([]error, len(errors))
|
||||||
for _, err := range errors {
|
for i, err := range errors {
|
||||||
errs = append(errs, err)
|
errs[i] = err
|
||||||
}
|
}
|
||||||
b, err := json.Marshal(errs)
|
b, err := json.Marshal(errs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -293,8 +293,10 @@ func (c *wsConnection) sendConnectionError(format string, args ...interface{}) {
|
|||||||
|
|
||||||
func (c *wsConnection) readOp() *operationMessage {
|
func (c *wsConnection) readOp() *operationMessage {
|
||||||
_, r, err := c.conn.NextReader()
|
_, r, err := c.conn.NextReader()
|
||||||
if err != nil {
|
if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) {
|
||||||
c.sendConnectionError("invalid json")
|
return nil
|
||||||
|
} else if err != nil {
|
||||||
|
c.sendConnectionError("invalid json: %T %s", err, err.Error())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
message := operationMessage{}
|
message := operationMessage{}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package handler
|
package transport
|
||||||
|
|
||||||
import "context"
|
import "context"
|
||||||
|
|
||||||
@@ -14,12 +14,12 @@ type InitPayload map[string]interface{}
|
|||||||
|
|
||||||
// GetString safely gets a string value from the payload. It returns an empty string if the
|
// GetString safely gets a string value from the payload. It returns an empty string if the
|
||||||
// payload is nil or the value isn't set.
|
// payload is nil or the value isn't set.
|
||||||
func (payload InitPayload) GetString(key string) string {
|
func (p InitPayload) GetString(key string) string {
|
||||||
if payload == nil {
|
if p == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if value, ok := payload[key]; ok {
|
if value, ok := p[key]; ok {
|
||||||
res, _ := value.(string)
|
res, _ := value.(string)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
@@ -29,12 +29,12 @@ func (payload InitPayload) GetString(key string) string {
|
|||||||
|
|
||||||
// Authorization is a short hand for getting the Authorization header from the
|
// Authorization is a short hand for getting the Authorization header from the
|
||||||
// payload.
|
// payload.
|
||||||
func (payload InitPayload) Authorization() string {
|
func (p InitPayload) Authorization() string {
|
||||||
if value := payload.GetString("Authorization"); value != "" {
|
if value := p.GetString("Authorization"); value != "" {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
if value := payload.GetString("authorization"); value != "" {
|
if value := p.GetString("authorization"); value != "" {
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
2
vendor/github.com/99designs/gqlgen/graphql/id.go
generated
vendored
2
vendor/github.com/99designs/gqlgen/graphql/id.go
generated
vendored
@@ -20,6 +20,8 @@ func UnmarshalID(v interface{}) (string, error) {
|
|||||||
return string(v), nil
|
return string(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:
|
||||||
|
|||||||
2
vendor/github.com/99designs/gqlgen/graphql/introspection/introspection.go
generated
vendored
2
vendor/github.com/99designs/gqlgen/graphql/introspection/introspection.go
generated
vendored
@@ -1,7 +1,7 @@
|
|||||||
// introspection implements the spec defined in https://github.com/facebook/graphql/blob/master/spec/Section%204%20--%20Introspection.md#schema-introspection
|
// introspection implements the spec defined in https://github.com/facebook/graphql/blob/master/spec/Section%204%20--%20Introspection.md#schema-introspection
|
||||||
package introspection
|
package introspection
|
||||||
|
|
||||||
import "github.com/vektah/gqlparser/ast"
|
import "github.com/vektah/gqlparser/v2/ast"
|
||||||
|
|
||||||
type (
|
type (
|
||||||
Directive struct {
|
Directive struct {
|
||||||
|
|||||||
20
vendor/github.com/99designs/gqlgen/graphql/introspection/schema.go
generated
vendored
20
vendor/github.com/99designs/gqlgen/graphql/introspection/schema.go
generated
vendored
@@ -3,7 +3,7 @@ package introspection
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/vektah/gqlparser/ast"
|
"github.com/vektah/gqlparser/v2/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Schema struct {
|
type Schema struct {
|
||||||
@@ -11,7 +11,7 @@ type Schema struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Schema) Types() []Type {
|
func (s *Schema) Types() []Type {
|
||||||
var types []Type
|
types := make([]Type, 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
|
||||||
@@ -34,7 +34,7 @@ func (s *Schema) SubscriptionType() *Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Schema) Directives() []Directive {
|
func (s *Schema) Directives() []Directive {
|
||||||
var res []Directive
|
res := make([]Directive, 0, len(s.schema.Directives))
|
||||||
|
|
||||||
for _, d := range s.schema.Directives {
|
for _, d := range s.schema.Directives {
|
||||||
res = append(res, s.directiveFromDef(d))
|
res = append(res, s.directiveFromDef(d))
|
||||||
@@ -44,19 +44,19 @@ func (s *Schema) Directives() []Directive {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Schema) directiveFromDef(d *ast.DirectiveDefinition) Directive {
|
func (s *Schema) directiveFromDef(d *ast.DirectiveDefinition) Directive {
|
||||||
var locs []string
|
locs := make([]string, len(d.Locations))
|
||||||
for _, loc := range d.Locations {
|
for i, loc := range d.Locations {
|
||||||
locs = append(locs, string(loc))
|
locs[i] = string(loc)
|
||||||
}
|
}
|
||||||
|
|
||||||
var args []InputValue
|
args := make([]InputValue, len(d.Arguments))
|
||||||
for _, arg := range d.Arguments {
|
for i, arg := range d.Arguments {
|
||||||
args = append(args, 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),
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Directive{
|
return Directive{
|
||||||
|
|||||||
6
vendor/github.com/99designs/gqlgen/graphql/introspection/type.go
generated
vendored
6
vendor/github.com/99designs/gqlgen/graphql/introspection/type.go
generated
vendored
@@ -3,7 +3,7 @@ package introspection
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/vektah/gqlparser/ast"
|
"github.com/vektah/gqlparser/v2/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Type struct {
|
type Type struct {
|
||||||
@@ -152,6 +152,10 @@ func (t *Type) EnumValues(includeDeprecated bool) []EnumValue {
|
|||||||
|
|
||||||
res := []EnumValue{}
|
res := []EnumValue{}
|
||||||
for _, val := range t.def.EnumValues {
|
for _, val := range t.def.EnumValues {
|
||||||
|
if !includeDeprecated && val.Directives.ForName("deprecated") != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
res = append(res, EnumValue{
|
res = append(res, EnumValue{
|
||||||
Name: val.Name,
|
Name: val.Name,
|
||||||
Description: val.Description,
|
Description: val.Description,
|
||||||
|
|||||||
6
vendor/github.com/99designs/gqlgen/graphql/oneshot.go
generated
vendored
6
vendor/github.com/99designs/gqlgen/graphql/oneshot.go
generated
vendored
@@ -1,9 +1,11 @@
|
|||||||
package graphql
|
package graphql
|
||||||
|
|
||||||
func OneShot(resp *Response) func() *Response {
|
import "context"
|
||||||
|
|
||||||
|
func OneShot(resp *Response) ResponseHandler {
|
||||||
var oneshot bool
|
var oneshot bool
|
||||||
|
|
||||||
return func() *Response {
|
return func(context context.Context) *Response {
|
||||||
if oneshot {
|
if oneshot {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package handler
|
package playground
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"html/template"
|
"html/template"
|
||||||
@@ -33,6 +33,7 @@ var page = template.Must(template.New("graphiql").Parse(`<!DOCTYPE html>
|
|||||||
GraphQLPlayground.init(root, {
|
GraphQLPlayground.init(root, {
|
||||||
endpoint: location.protocol + '//' + location.host + '{{.endpoint}}',
|
endpoint: location.protocol + '//' + location.host + '{{.endpoint}}',
|
||||||
subscriptionsEndpoint: wsProto + '//' + location.host + '{{.endpoint }}',
|
subscriptionsEndpoint: wsProto + '//' + location.host + '{{.endpoint }}',
|
||||||
|
shareEnabled: true,
|
||||||
settings: {
|
settings: {
|
||||||
'request.credentials': 'same-origin'
|
'request.credentials': 'same-origin'
|
||||||
}
|
}
|
||||||
@@ -43,7 +44,7 @@ var page = template.Must(template.New("graphiql").Parse(`<!DOCTYPE html>
|
|||||||
</html>
|
</html>
|
||||||
`))
|
`))
|
||||||
|
|
||||||
func Playground(title string, endpoint string) http.HandlerFunc {
|
func Handler(title string, endpoint string) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Add("Content-Type", "text/html")
|
w.Header().Add("Content-Type", "text/html")
|
||||||
err := page.Execute(w, map[string]string{
|
err := page.Execute(w, map[string]string{
|
||||||
2
vendor/github.com/99designs/gqlgen/graphql/response.go
generated
vendored
2
vendor/github.com/99designs/gqlgen/graphql/response.go
generated
vendored
@@ -5,7 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/vektah/gqlparser/gqlerror"
|
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Errors are intentionally serialized first based on the advice in
|
// Errors are intentionally serialized first based on the advice in
|
||||||
|
|||||||
60
vendor/github.com/99designs/gqlgen/graphql/stats.go
generated
vendored
Normal file
60
vendor/github.com/99designs/gqlgen/graphql/stats.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package graphql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Stats struct {
|
||||||
|
OperationStart time.Time
|
||||||
|
Read TraceTiming
|
||||||
|
Parsing TraceTiming
|
||||||
|
Validation TraceTiming
|
||||||
|
|
||||||
|
// Stats collected by handler extensions. Dont use directly, the extension should provide a type safe way to
|
||||||
|
// access this.
|
||||||
|
extension map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type TraceTiming struct {
|
||||||
|
Start time.Time
|
||||||
|
End time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
var ctxTraceStart key = "trace_start"
|
||||||
|
|
||||||
|
// StartOperationTrace captures the current time and stores it in context. This will eventually be added to request
|
||||||
|
// context but we want to grab it as soon as possible. For transports that can only handle a single graphql query
|
||||||
|
// per http requests you dont need to call this at all, the server will do it for you. For transports that handle
|
||||||
|
// multiple (eg batching, subscriptions) this should be called before decoding each request.
|
||||||
|
func StartOperationTrace(ctx context.Context) context.Context {
|
||||||
|
return context.WithValue(ctx, ctxTraceStart, Now())
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetStartTime should only be called by the handler package, it will be set into request context
|
||||||
|
// as Stats.Start
|
||||||
|
func GetStartTime(ctx context.Context) time.Time {
|
||||||
|
t, ok := ctx.Value(ctxTraceStart).(time.Time)
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf("missing start time: %T", ctx.Value(ctxTraceStart)))
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Stats) SetExtension(name string, data interface{}) {
|
||||||
|
if c.extension == nil {
|
||||||
|
c.extension = map[string]interface{}{}
|
||||||
|
}
|
||||||
|
c.extension[name] = data
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Stats) GetExtension(name string) interface{} {
|
||||||
|
if c.extension == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return c.extension[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now is time.Now, except in tests. Then it can be whatever you want it to be.
|
||||||
|
var Now = time.Now
|
||||||
58
vendor/github.com/99designs/gqlgen/graphql/tracer.go
generated
vendored
58
vendor/github.com/99designs/gqlgen/graphql/tracer.go
generated
vendored
@@ -1,58 +0,0 @@
|
|||||||
package graphql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ Tracer = (*NopTracer)(nil)
|
|
||||||
|
|
||||||
type Tracer interface {
|
|
||||||
StartOperationParsing(ctx context.Context) context.Context
|
|
||||||
EndOperationParsing(ctx context.Context)
|
|
||||||
StartOperationValidation(ctx context.Context) context.Context
|
|
||||||
EndOperationValidation(ctx context.Context)
|
|
||||||
StartOperationExecution(ctx context.Context) context.Context
|
|
||||||
StartFieldExecution(ctx context.Context, field CollectedField) context.Context
|
|
||||||
StartFieldResolverExecution(ctx context.Context, rc *ResolverContext) context.Context
|
|
||||||
StartFieldChildExecution(ctx context.Context) context.Context
|
|
||||||
EndFieldExecution(ctx context.Context)
|
|
||||||
EndOperationExecution(ctx context.Context)
|
|
||||||
}
|
|
||||||
|
|
||||||
type NopTracer struct{}
|
|
||||||
|
|
||||||
func (NopTracer) StartOperationParsing(ctx context.Context) context.Context {
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (NopTracer) EndOperationParsing(ctx context.Context) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (NopTracer) StartOperationValidation(ctx context.Context) context.Context {
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (NopTracer) EndOperationValidation(ctx context.Context) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (NopTracer) StartOperationExecution(ctx context.Context) context.Context {
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (NopTracer) StartFieldExecution(ctx context.Context, field CollectedField) context.Context {
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (NopTracer) StartFieldResolverExecution(ctx context.Context, rc *ResolverContext) context.Context {
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (NopTracer) StartFieldChildExecution(ctx context.Context) context.Context {
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (NopTracer) EndFieldExecution(ctx context.Context) {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (NopTracer) EndOperationExecution(ctx context.Context) {
|
|
||||||
}
|
|
||||||
1
vendor/github.com/99designs/gqlgen/graphql/upload.go
generated
vendored
1
vendor/github.com/99designs/gqlgen/graphql/upload.go
generated
vendored
@@ -9,6 +9,7 @@ type Upload struct {
|
|||||||
File io.Reader
|
File io.Reader
|
||||||
Filename string
|
Filename string
|
||||||
Size int64
|
Size int64
|
||||||
|
ContentType string
|
||||||
}
|
}
|
||||||
|
|
||||||
func MarshalUpload(f Upload) Marshaler {
|
func MarshalUpload(f Upload) Marshaler {
|
||||||
|
|||||||
2
vendor/github.com/99designs/gqlgen/graphql/version.go
generated
vendored
2
vendor/github.com/99designs/gqlgen/graphql/version.go
generated
vendored
@@ -1,3 +1,3 @@
|
|||||||
package graphql
|
package graphql
|
||||||
|
|
||||||
const Version = "v0.9.0"
|
const Version = "v0.12.2"
|
||||||
|
|||||||
709
vendor/github.com/99designs/gqlgen/handler/graphql.go
generated
vendored
709
vendor/github.com/99designs/gqlgen/handler/graphql.go
generated
vendored
@@ -1,709 +0,0 @@
|
|||||||
package handler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"mime"
|
|
||||||
"net/http"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/complexity"
|
|
||||||
"github.com/99designs/gqlgen/graphql"
|
|
||||||
"github.com/gorilla/websocket"
|
|
||||||
lru "github.com/hashicorp/golang-lru"
|
|
||||||
"github.com/vektah/gqlparser/ast"
|
|
||||||
"github.com/vektah/gqlparser/gqlerror"
|
|
||||||
"github.com/vektah/gqlparser/parser"
|
|
||||||
"github.com/vektah/gqlparser/validator"
|
|
||||||
)
|
|
||||||
|
|
||||||
type params struct {
|
|
||||||
Query string `json:"query"`
|
|
||||||
OperationName string `json:"operationName"`
|
|
||||||
Variables map[string]interface{} `json:"variables"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
cacheSize int
|
|
||||||
upgrader websocket.Upgrader
|
|
||||||
recover graphql.RecoverFunc
|
|
||||||
errorPresenter graphql.ErrorPresenterFunc
|
|
||||||
resolverHook graphql.FieldMiddleware
|
|
||||||
requestHook graphql.RequestMiddleware
|
|
||||||
tracer graphql.Tracer
|
|
||||||
complexityLimit int
|
|
||||||
complexityLimitFunc graphql.ComplexityLimitFunc
|
|
||||||
disableIntrospection bool
|
|
||||||
connectionKeepAlivePingInterval time.Duration
|
|
||||||
uploadMaxMemory int64
|
|
||||||
uploadMaxSize int64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) newRequestContext(es graphql.ExecutableSchema, doc *ast.QueryDocument, op *ast.OperationDefinition, query string, variables map[string]interface{}) *graphql.RequestContext {
|
|
||||||
reqCtx := graphql.NewRequestContext(doc, query, variables)
|
|
||||||
reqCtx.DisableIntrospection = c.disableIntrospection
|
|
||||||
|
|
||||||
if hook := c.recover; hook != nil {
|
|
||||||
reqCtx.Recover = hook
|
|
||||||
}
|
|
||||||
|
|
||||||
if hook := c.errorPresenter; hook != nil {
|
|
||||||
reqCtx.ErrorPresenter = hook
|
|
||||||
}
|
|
||||||
|
|
||||||
if hook := c.resolverHook; hook != nil {
|
|
||||||
reqCtx.ResolverMiddleware = hook
|
|
||||||
}
|
|
||||||
|
|
||||||
if hook := c.requestHook; hook != nil {
|
|
||||||
reqCtx.RequestMiddleware = hook
|
|
||||||
}
|
|
||||||
|
|
||||||
if hook := c.tracer; hook != nil {
|
|
||||||
reqCtx.Tracer = hook
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.complexityLimit > 0 || c.complexityLimitFunc != nil {
|
|
||||||
reqCtx.ComplexityLimit = c.complexityLimit
|
|
||||||
operationComplexity := complexity.Calculate(es, op, variables)
|
|
||||||
reqCtx.OperationComplexity = operationComplexity
|
|
||||||
}
|
|
||||||
|
|
||||||
return reqCtx
|
|
||||||
}
|
|
||||||
|
|
||||||
type Option func(cfg *Config)
|
|
||||||
|
|
||||||
func WebsocketUpgrader(upgrader websocket.Upgrader) Option {
|
|
||||||
return func(cfg *Config) {
|
|
||||||
cfg.upgrader = upgrader
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func RecoverFunc(recover graphql.RecoverFunc) Option {
|
|
||||||
return func(cfg *Config) {
|
|
||||||
cfg.recover = recover
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrorPresenter transforms errors found while resolving into errors that will be returned to the user. It provides
|
|
||||||
// a good place to add any extra fields, like error.type, that might be desired by your frontend. Check the default
|
|
||||||
// implementation in graphql.DefaultErrorPresenter for an example.
|
|
||||||
func ErrorPresenter(f graphql.ErrorPresenterFunc) Option {
|
|
||||||
return func(cfg *Config) {
|
|
||||||
cfg.errorPresenter = f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// IntrospectionEnabled = false will forbid clients from calling introspection endpoints. Can be useful in prod when you dont
|
|
||||||
// want clients introspecting the full schema.
|
|
||||||
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.
|
|
||||||
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.
|
|
||||||
func ComplexityLimitFunc(complexityLimitFunc graphql.ComplexityLimitFunc) 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.
|
|
||||||
func ResolverMiddleware(middleware graphql.FieldMiddleware) Option {
|
|
||||||
return func(cfg *Config) {
|
|
||||||
if cfg.resolverHook == nil {
|
|
||||||
cfg.resolverHook = middleware
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
lastResolve := cfg.resolverHook
|
|
||||||
cfg.resolverHook = func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
|
|
||||||
return lastResolve(ctx, func(ctx context.Context) (res interface{}, err error) {
|
|
||||||
return middleware(ctx, next)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RequestMiddleware allows you to define a function that will be called around the root request,
|
|
||||||
// after the query has been parsed. This is useful for logging
|
|
||||||
func RequestMiddleware(middleware graphql.RequestMiddleware) Option {
|
|
||||||
return func(cfg *Config) {
|
|
||||||
if cfg.requestHook == nil {
|
|
||||||
cfg.requestHook = middleware
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
lastResolve := cfg.requestHook
|
|
||||||
cfg.requestHook = func(ctx context.Context, next func(ctx context.Context) []byte) []byte {
|
|
||||||
return lastResolve(ctx, func(ctx context.Context) []byte {
|
|
||||||
return middleware(ctx, next)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tracer allows you to add a request/resolver tracer that will be called around the root request,
|
|
||||||
// calling resolver. This is useful for tracing
|
|
||||||
func Tracer(tracer graphql.Tracer) Option {
|
|
||||||
return func(cfg *Config) {
|
|
||||||
if cfg.tracer == nil {
|
|
||||||
cfg.tracer = tracer
|
|
||||||
|
|
||||||
} else {
|
|
||||||
lastResolve := cfg.tracer
|
|
||||||
cfg.tracer = &tracerWrapper{
|
|
||||||
tracer1: lastResolve,
|
|
||||||
tracer2: tracer,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
opt := RequestMiddleware(func(ctx context.Context, next func(ctx context.Context) []byte) []byte {
|
|
||||||
ctx = tracer.StartOperationExecution(ctx)
|
|
||||||
resp := next(ctx)
|
|
||||||
tracer.EndOperationExecution(ctx)
|
|
||||||
|
|
||||||
return resp
|
|
||||||
})
|
|
||||||
opt(cfg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type tracerWrapper struct {
|
|
||||||
tracer1 graphql.Tracer
|
|
||||||
tracer2 graphql.Tracer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tw *tracerWrapper) StartOperationParsing(ctx context.Context) context.Context {
|
|
||||||
ctx = tw.tracer1.StartOperationParsing(ctx)
|
|
||||||
ctx = tw.tracer2.StartOperationParsing(ctx)
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tw *tracerWrapper) EndOperationParsing(ctx context.Context) {
|
|
||||||
tw.tracer2.EndOperationParsing(ctx)
|
|
||||||
tw.tracer1.EndOperationParsing(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tw *tracerWrapper) StartOperationValidation(ctx context.Context) context.Context {
|
|
||||||
ctx = tw.tracer1.StartOperationValidation(ctx)
|
|
||||||
ctx = tw.tracer2.StartOperationValidation(ctx)
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tw *tracerWrapper) EndOperationValidation(ctx context.Context) {
|
|
||||||
tw.tracer2.EndOperationValidation(ctx)
|
|
||||||
tw.tracer1.EndOperationValidation(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tw *tracerWrapper) StartOperationExecution(ctx context.Context) context.Context {
|
|
||||||
ctx = tw.tracer1.StartOperationExecution(ctx)
|
|
||||||
ctx = tw.tracer2.StartOperationExecution(ctx)
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tw *tracerWrapper) StartFieldExecution(ctx context.Context, field graphql.CollectedField) context.Context {
|
|
||||||
ctx = tw.tracer1.StartFieldExecution(ctx, field)
|
|
||||||
ctx = tw.tracer2.StartFieldExecution(ctx, field)
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tw *tracerWrapper) StartFieldResolverExecution(ctx context.Context, rc *graphql.ResolverContext) context.Context {
|
|
||||||
ctx = tw.tracer1.StartFieldResolverExecution(ctx, rc)
|
|
||||||
ctx = tw.tracer2.StartFieldResolverExecution(ctx, rc)
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tw *tracerWrapper) StartFieldChildExecution(ctx context.Context) context.Context {
|
|
||||||
ctx = tw.tracer1.StartFieldChildExecution(ctx)
|
|
||||||
ctx = tw.tracer2.StartFieldChildExecution(ctx)
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tw *tracerWrapper) EndFieldExecution(ctx context.Context) {
|
|
||||||
tw.tracer2.EndFieldExecution(ctx)
|
|
||||||
tw.tracer1.EndFieldExecution(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tw *tracerWrapper) EndOperationExecution(ctx context.Context) {
|
|
||||||
tw.tracer2.EndOperationExecution(ctx)
|
|
||||||
tw.tracer1.EndOperationExecution(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CacheSize sets the maximum size of the query cache.
|
|
||||||
// If size is less than or equal to 0, the cache is disabled.
|
|
||||||
func CacheSize(size int) Option {
|
|
||||||
return func(cfg *Config) {
|
|
||||||
cfg.cacheSize = size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// UploadMaxSize sets the maximum number of bytes used to parse a request body
|
|
||||||
// as multipart/form-data.
|
|
||||||
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.
|
|
||||||
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.
|
|
||||||
func WebsocketKeepAliveDuration(duration time.Duration) Option {
|
|
||||||
return func(cfg *Config) {
|
|
||||||
cfg.connectionKeepAlivePingInterval = duration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const DefaultCacheSize = 1000
|
|
||||||
const DefaultConnectionKeepAlivePingInterval = 25 * time.Second
|
|
||||||
|
|
||||||
// DefaultUploadMaxMemory is 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.
|
|
||||||
const DefaultUploadMaxMemory = 32 << 20
|
|
||||||
|
|
||||||
// DefaultUploadMaxSize is maximum number of bytes used to parse a request body
|
|
||||||
// as multipart/form-data.
|
|
||||||
const DefaultUploadMaxSize = 32 << 20
|
|
||||||
|
|
||||||
func GraphQL(exec graphql.ExecutableSchema, options ...Option) http.HandlerFunc {
|
|
||||||
cfg := &Config{
|
|
||||||
cacheSize: DefaultCacheSize,
|
|
||||||
uploadMaxMemory: DefaultUploadMaxMemory,
|
|
||||||
uploadMaxSize: DefaultUploadMaxSize,
|
|
||||||
connectionKeepAlivePingInterval: DefaultConnectionKeepAlivePingInterval,
|
|
||||||
upgrader: websocket.Upgrader{
|
|
||||||
ReadBufferSize: 1024,
|
|
||||||
WriteBufferSize: 1024,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, option := range options {
|
|
||||||
option(cfg)
|
|
||||||
}
|
|
||||||
|
|
||||||
var cache *lru.Cache
|
|
||||||
if cfg.cacheSize > 0 {
|
|
||||||
var err error
|
|
||||||
cache, err = lru.New(cfg.cacheSize)
|
|
||||||
if err != nil {
|
|
||||||
// An error is only returned for non-positive cache size
|
|
||||||
// and we already checked for that.
|
|
||||||
panic("unexpected error creating cache: " + err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if cfg.tracer == nil {
|
|
||||||
cfg.tracer = &graphql.NopTracer{}
|
|
||||||
}
|
|
||||||
|
|
||||||
handler := &graphqlHandler{
|
|
||||||
cfg: cfg,
|
|
||||||
cache: cache,
|
|
||||||
exec: exec,
|
|
||||||
}
|
|
||||||
|
|
||||||
return handler.ServeHTTP
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ http.Handler = (*graphqlHandler)(nil)
|
|
||||||
|
|
||||||
type graphqlHandler struct {
|
|
||||||
cfg *Config
|
|
||||||
cache *lru.Cache
|
|
||||||
exec graphql.ExecutableSchema
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gh *graphqlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if r.Method == http.MethodOptions {
|
|
||||||
w.Header().Set("Allow", "OPTIONS, GET, POST")
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.Contains(r.Header.Get("Upgrade"), "websocket") {
|
|
||||||
connectWs(gh.exec, w, r, gh.cfg, gh.cache)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
var reqParams params
|
|
||||||
switch r.Method {
|
|
||||||
case http.MethodGet:
|
|
||||||
reqParams.Query = r.URL.Query().Get("query")
|
|
||||||
reqParams.OperationName = r.URL.Query().Get("operationName")
|
|
||||||
|
|
||||||
if variables := r.URL.Query().Get("variables"); variables != "" {
|
|
||||||
if err := jsonDecode(strings.NewReader(variables), &reqParams.Variables); err != nil {
|
|
||||||
sendErrorf(w, http.StatusBadRequest, "variables could not be decoded")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case http.MethodPost:
|
|
||||||
mediaType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
|
||||||
if err != nil {
|
|
||||||
sendErrorf(w, http.StatusBadRequest, "error parsing request Content-Type")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
switch mediaType {
|
|
||||||
case "application/json":
|
|
||||||
if err := jsonDecode(r.Body, &reqParams); err != nil {
|
|
||||||
sendErrorf(w, http.StatusBadRequest, "json body could not be decoded: "+err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
case "multipart/form-data":
|
|
||||||
var closers []io.Closer
|
|
||||||
var tmpFiles []string
|
|
||||||
defer func() {
|
|
||||||
for i := len(closers) - 1; 0 <= i; i-- {
|
|
||||||
_ = closers[i].Close()
|
|
||||||
}
|
|
||||||
for _, tmpFile := range tmpFiles {
|
|
||||||
_ = os.Remove(tmpFile)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if err := processMultipart(w, r, &reqParams, &closers, &tmpFiles, gh.cfg.uploadMaxSize, gh.cfg.uploadMaxMemory); err != nil {
|
|
||||||
sendErrorf(w, http.StatusBadRequest, "multipart body could not be decoded: "+err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
sendErrorf(w, http.StatusBadRequest, "unsupported Content-Type: "+mediaType)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := r.Context()
|
|
||||||
|
|
||||||
var doc *ast.QueryDocument
|
|
||||||
var cacheHit bool
|
|
||||||
if gh.cache != nil {
|
|
||||||
val, ok := gh.cache.Get(reqParams.Query)
|
|
||||||
if ok {
|
|
||||||
doc = val.(*ast.QueryDocument)
|
|
||||||
cacheHit = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, doc, gqlErr := gh.parseOperation(ctx, &parseOperationArgs{
|
|
||||||
Query: reqParams.Query,
|
|
||||||
CachedDoc: doc,
|
|
||||||
})
|
|
||||||
if gqlErr != nil {
|
|
||||||
sendError(w, http.StatusUnprocessableEntity, gqlErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, op, vars, listErr := gh.validateOperation(ctx, &validateOperationArgs{
|
|
||||||
Doc: doc,
|
|
||||||
OperationName: reqParams.OperationName,
|
|
||||||
CacheHit: cacheHit,
|
|
||||||
R: r,
|
|
||||||
Variables: reqParams.Variables,
|
|
||||||
})
|
|
||||||
if len(listErr) != 0 {
|
|
||||||
sendError(w, http.StatusUnprocessableEntity, listErr...)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if gh.cache != nil && !cacheHit {
|
|
||||||
gh.cache.Add(reqParams.Query, doc)
|
|
||||||
}
|
|
||||||
|
|
||||||
reqCtx := gh.cfg.newRequestContext(gh.exec, doc, op, reqParams.Query, vars)
|
|
||||||
ctx = graphql.WithRequestContext(ctx, reqCtx)
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if err := recover(); err != nil {
|
|
||||||
userErr := reqCtx.Recover(ctx, err)
|
|
||||||
sendErrorf(w, http.StatusUnprocessableEntity, userErr.Error())
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if gh.cfg.complexityLimitFunc != nil {
|
|
||||||
reqCtx.ComplexityLimit = gh.cfg.complexityLimitFunc(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
if reqCtx.ComplexityLimit > 0 && reqCtx.OperationComplexity > reqCtx.ComplexityLimit {
|
|
||||||
sendErrorf(w, http.StatusUnprocessableEntity, "operation has complexity %d, which exceeds the limit of %d", reqCtx.OperationComplexity, reqCtx.ComplexityLimit)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
switch op.Operation {
|
|
||||||
case ast.Query:
|
|
||||||
b, err := json.Marshal(gh.exec.Query(ctx, op))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
w.Write(b)
|
|
||||||
case ast.Mutation:
|
|
||||||
b, err := json.Marshal(gh.exec.Mutation(ctx, op))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
w.Write(b)
|
|
||||||
default:
|
|
||||||
sendErrorf(w, http.StatusBadRequest, "unsupported operation type")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type parseOperationArgs struct {
|
|
||||||
Query string
|
|
||||||
CachedDoc *ast.QueryDocument
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gh *graphqlHandler) parseOperation(ctx context.Context, args *parseOperationArgs) (context.Context, *ast.QueryDocument, *gqlerror.Error) {
|
|
||||||
ctx = gh.cfg.tracer.StartOperationParsing(ctx)
|
|
||||||
defer func() { gh.cfg.tracer.EndOperationParsing(ctx) }()
|
|
||||||
|
|
||||||
if args.CachedDoc != nil {
|
|
||||||
return ctx, args.CachedDoc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
doc, gqlErr := parser.ParseQuery(&ast.Source{Input: args.Query})
|
|
||||||
if gqlErr != nil {
|
|
||||||
return ctx, nil, gqlErr
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx, doc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type validateOperationArgs struct {
|
|
||||||
Doc *ast.QueryDocument
|
|
||||||
OperationName string
|
|
||||||
CacheHit bool
|
|
||||||
R *http.Request
|
|
||||||
Variables map[string]interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gh *graphqlHandler) validateOperation(ctx context.Context, args *validateOperationArgs) (context.Context, *ast.OperationDefinition, map[string]interface{}, gqlerror.List) {
|
|
||||||
ctx = gh.cfg.tracer.StartOperationValidation(ctx)
|
|
||||||
defer func() { gh.cfg.tracer.EndOperationValidation(ctx) }()
|
|
||||||
|
|
||||||
if !args.CacheHit {
|
|
||||||
listErr := validator.Validate(gh.exec.Schema(), args.Doc)
|
|
||||||
if len(listErr) != 0 {
|
|
||||||
return ctx, nil, nil, listErr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
op := args.Doc.Operations.ForName(args.OperationName)
|
|
||||||
if op == nil {
|
|
||||||
return ctx, nil, nil, gqlerror.List{gqlerror.Errorf("operation %s not found", args.OperationName)}
|
|
||||||
}
|
|
||||||
|
|
||||||
if op.Operation != ast.Query && args.R.Method == http.MethodGet {
|
|
||||||
return ctx, nil, nil, gqlerror.List{gqlerror.Errorf("GET requests only allow query operations")}
|
|
||||||
}
|
|
||||||
|
|
||||||
vars, err := validator.VariableValues(gh.exec.Schema(), op, args.Variables)
|
|
||||||
if err != nil {
|
|
||||||
return ctx, nil, nil, gqlerror.List{err}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx, op, vars, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func jsonDecode(r io.Reader, val interface{}) error {
|
|
||||||
dec := json.NewDecoder(r)
|
|
||||||
dec.UseNumber()
|
|
||||||
return dec.Decode(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendError(w http.ResponseWriter, code int, errors ...*gqlerror.Error) {
|
|
||||||
w.WriteHeader(code)
|
|
||||||
b, err := json.Marshal(&graphql.Response{Errors: errors})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
w.Write(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func sendErrorf(w http.ResponseWriter, code int, format string, args ...interface{}) {
|
|
||||||
sendError(w, code, &gqlerror.Error{Message: fmt.Sprintf(format, args...)})
|
|
||||||
}
|
|
||||||
|
|
||||||
type bytesReader struct {
|
|
||||||
s *[]byte
|
|
||||||
i int64 // current reading index
|
|
||||||
prevRune int // index of previous rune; or < 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *bytesReader) Read(b []byte) (n int, err error) {
|
|
||||||
if r.s == nil {
|
|
||||||
return 0, errors.New("byte slice pointer is nil")
|
|
||||||
}
|
|
||||||
if r.i >= int64(len(*r.s)) {
|
|
||||||
return 0, io.EOF
|
|
||||||
}
|
|
||||||
r.prevRune = -1
|
|
||||||
n = copy(b, (*r.s)[r.i:])
|
|
||||||
r.i += int64(n)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func processMultipart(w http.ResponseWriter, r *http.Request, request *params, closers *[]io.Closer, tmpFiles *[]string, uploadMaxSize, uploadMaxMemory int64) error {
|
|
||||||
var err error
|
|
||||||
if r.ContentLength > uploadMaxSize {
|
|
||||||
return errors.New("failed to parse multipart form, request body too large")
|
|
||||||
}
|
|
||||||
r.Body = http.MaxBytesReader(w, r.Body, uploadMaxSize)
|
|
||||||
if err = r.ParseMultipartForm(uploadMaxMemory); err != nil {
|
|
||||||
if strings.Contains(err.Error(), "request body too large") {
|
|
||||||
return errors.New("failed to parse multipart form, request body too large")
|
|
||||||
}
|
|
||||||
return errors.New("failed to parse multipart form")
|
|
||||||
}
|
|
||||||
*closers = append(*closers, r.Body)
|
|
||||||
|
|
||||||
if err = jsonDecode(strings.NewReader(r.Form.Get("operations")), &request); err != nil {
|
|
||||||
return errors.New("operations form field could not be decoded")
|
|
||||||
}
|
|
||||||
|
|
||||||
var uploadsMap = map[string][]string{}
|
|
||||||
if err = json.Unmarshal([]byte(r.Form.Get("map")), &uploadsMap); err != nil {
|
|
||||||
return errors.New("map form field could not be decoded")
|
|
||||||
}
|
|
||||||
|
|
||||||
var upload graphql.Upload
|
|
||||||
for key, paths := range uploadsMap {
|
|
||||||
if len(paths) == 0 {
|
|
||||||
return fmt.Errorf("invalid empty operations paths list for key %s", key)
|
|
||||||
}
|
|
||||||
file, header, err := r.FormFile(key)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to get key %s from form", key)
|
|
||||||
}
|
|
||||||
*closers = append(*closers, file)
|
|
||||||
|
|
||||||
if len(paths) == 1 {
|
|
||||||
upload = graphql.Upload{
|
|
||||||
File: file,
|
|
||||||
Size: header.Size,
|
|
||||||
Filename: header.Filename,
|
|
||||||
}
|
|
||||||
err = addUploadToOperations(request, upload, key, paths[0])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if r.ContentLength < uploadMaxMemory {
|
|
||||||
fileBytes, err := ioutil.ReadAll(file)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to read file for key %s", key)
|
|
||||||
}
|
|
||||||
for _, path := range paths {
|
|
||||||
upload = graphql.Upload{
|
|
||||||
File: &bytesReader{s: &fileBytes, i: 0, prevRune: -1},
|
|
||||||
Size: header.Size,
|
|
||||||
Filename: header.Filename,
|
|
||||||
}
|
|
||||||
err = addUploadToOperations(request, upload, key, path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tmpFile, err := ioutil.TempFile(os.TempDir(), "gqlgen-")
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to create temp file for key %s", key)
|
|
||||||
}
|
|
||||||
tmpName := tmpFile.Name()
|
|
||||||
*tmpFiles = append(*tmpFiles, tmpName)
|
|
||||||
_, err = io.Copy(tmpFile, file)
|
|
||||||
if err != nil {
|
|
||||||
if err := tmpFile.Close(); err != nil {
|
|
||||||
return fmt.Errorf("failed to copy to temp file and close temp file for key %s", key)
|
|
||||||
}
|
|
||||||
return fmt.Errorf("failed to copy to temp file for key %s", key)
|
|
||||||
}
|
|
||||||
if err := tmpFile.Close(); err != nil {
|
|
||||||
return fmt.Errorf("failed to close temp file for key %s", key)
|
|
||||||
}
|
|
||||||
for _, path := range paths {
|
|
||||||
pathTmpFile, err := os.Open(tmpName)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to open temp file for key %s", key)
|
|
||||||
}
|
|
||||||
*closers = append(*closers, pathTmpFile)
|
|
||||||
upload = graphql.Upload{
|
|
||||||
File: pathTmpFile,
|
|
||||||
Size: header.Size,
|
|
||||||
Filename: header.Filename,
|
|
||||||
}
|
|
||||||
err = addUploadToOperations(request, upload, key, path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func addUploadToOperations(request *params, upload graphql.Upload, key, path string) error {
|
|
||||||
if !strings.HasPrefix(path, "variables.") {
|
|
||||||
return fmt.Errorf("invalid operations paths for key %s", key)
|
|
||||||
}
|
|
||||||
|
|
||||||
var ptr interface{} = request.Variables
|
|
||||||
parts := strings.Split(path, ".")
|
|
||||||
|
|
||||||
// skip the first part (variables) because we started there
|
|
||||||
for i, p := range parts[1:] {
|
|
||||||
last := i == len(parts)-2
|
|
||||||
if ptr == nil {
|
|
||||||
return fmt.Errorf("path is missing \"variables.\" prefix, key: %s, path: %s", key, path)
|
|
||||||
}
|
|
||||||
if index, parseNbrErr := strconv.Atoi(p); parseNbrErr == nil {
|
|
||||||
if last {
|
|
||||||
ptr.([]interface{})[index] = upload
|
|
||||||
} else {
|
|
||||||
ptr = ptr.([]interface{})[index]
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if last {
|
|
||||||
ptr.(map[string]interface{})[p] = upload
|
|
||||||
} else {
|
|
||||||
ptr = ptr.(map[string]interface{})[p]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
247
vendor/github.com/99designs/gqlgen/handler/handler.go
generated
vendored
Normal file
247
vendor/github.com/99designs/gqlgen/handler/handler.go
generated
vendored
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
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
|
||||||
57
vendor/github.com/99designs/gqlgen/handler/mock.go
generated
vendored
57
vendor/github.com/99designs/gqlgen/handler/mock.go
generated
vendored
@@ -1,57 +0,0 @@
|
|||||||
package handler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/graphql"
|
|
||||||
"github.com/vektah/gqlparser"
|
|
||||||
"github.com/vektah/gqlparser/ast"
|
|
||||||
)
|
|
||||||
|
|
||||||
type executableSchemaMock struct {
|
|
||||||
MutationFunc func(ctx context.Context, op *ast.OperationDefinition) *graphql.Response
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ graphql.ExecutableSchema = &executableSchemaMock{}
|
|
||||||
|
|
||||||
func (e *executableSchemaMock) Schema() *ast.Schema {
|
|
||||||
return gqlparser.MustLoadSchema(&ast.Source{Input: `
|
|
||||||
schema { query: Query, mutation: Mutation }
|
|
||||||
type Query {
|
|
||||||
empty: String!
|
|
||||||
}
|
|
||||||
scalar Upload
|
|
||||||
type File {
|
|
||||||
id: Int!
|
|
||||||
}
|
|
||||||
input UploadFile {
|
|
||||||
id: Int!
|
|
||||||
file: Upload!
|
|
||||||
}
|
|
||||||
type Mutation {
|
|
||||||
singleUpload(file: Upload!): File!
|
|
||||||
singleUploadWithPayload(req: UploadFile!): File!
|
|
||||||
multipleUpload(files: [Upload!]!): [File!]!
|
|
||||||
multipleUploadWithPayload(req: [UploadFile!]!): [File!]!
|
|
||||||
}
|
|
||||||
`})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *executableSchemaMock) Complexity(typeName, field string, childComplexity int, args map[string]interface{}) (int, bool) {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *executableSchemaMock) Query(ctx context.Context, op *ast.OperationDefinition) *graphql.Response {
|
|
||||||
return graphql.ErrorResponse(ctx, "queries are not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *executableSchemaMock) Mutation(ctx context.Context, op *ast.OperationDefinition) *graphql.Response {
|
|
||||||
return e.MutationFunc(ctx, op)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *executableSchemaMock) Subscription(ctx context.Context, op *ast.OperationDefinition) func() *graphql.Response {
|
|
||||||
return func() *graphql.Response {
|
|
||||||
<-ctx.Done()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
51
vendor/github.com/99designs/gqlgen/handler/stub.go
generated
vendored
51
vendor/github.com/99designs/gqlgen/handler/stub.go
generated
vendored
@@ -1,51 +0,0 @@
|
|||||||
package handler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/99designs/gqlgen/graphql"
|
|
||||||
"github.com/vektah/gqlparser"
|
|
||||||
"github.com/vektah/gqlparser/ast"
|
|
||||||
)
|
|
||||||
|
|
||||||
type executableSchemaStub struct {
|
|
||||||
NextResp chan struct{}
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ graphql.ExecutableSchema = &executableSchemaStub{}
|
|
||||||
|
|
||||||
func (e *executableSchemaStub) Schema() *ast.Schema {
|
|
||||||
return gqlparser.MustLoadSchema(&ast.Source{Input: `
|
|
||||||
schema { query: Query }
|
|
||||||
type Query {
|
|
||||||
me: User!
|
|
||||||
user(id: Int): User!
|
|
||||||
}
|
|
||||||
type User { name: String! }
|
|
||||||
`})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *executableSchemaStub) Complexity(typeName, field string, childComplexity int, args map[string]interface{}) (int, bool) {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *executableSchemaStub) Query(ctx context.Context, op *ast.OperationDefinition) *graphql.Response {
|
|
||||||
return &graphql.Response{Data: []byte(`{"name":"test"}`)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *executableSchemaStub) Mutation(ctx context.Context, op *ast.OperationDefinition) *graphql.Response {
|
|
||||||
return graphql.ErrorResponse(ctx, "mutations are not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *executableSchemaStub) Subscription(ctx context.Context, op *ast.OperationDefinition) func() *graphql.Response {
|
|
||||||
return func() *graphql.Response {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return nil
|
|
||||||
case <-e.NextResp:
|
|
||||||
return &graphql.Response{
|
|
||||||
Data: []byte(`{"name":"test"}`),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
61
vendor/github.com/99designs/gqlgen/internal/code/imports.go
generated
vendored
61
vendor/github.com/99designs/gqlgen/internal/code/imports.go
generated
vendored
@@ -1,7 +1,6 @@
|
|||||||
package code
|
package code
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"go/build"
|
"go/build"
|
||||||
"go/parser"
|
"go/parser"
|
||||||
"go/token"
|
"go/token"
|
||||||
@@ -9,13 +8,8 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"golang.org/x/tools/go/packages"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var nameForPackageCache = sync.Map{}
|
|
||||||
|
|
||||||
var gopaths []string
|
var gopaths []string
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -51,33 +45,50 @@ func NameForDir(dir string) string {
|
|||||||
return SanitizePackageName(filepath.Base(dir))
|
return SanitizePackageName(filepath.Base(dir))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImportPathForDir takes a path and returns a golang import path for the package
|
// goModuleRoot returns the root of the current go module if there is a go.mod file in the directory tree
|
||||||
func ImportPathForDir(dir string) (res string) {
|
// If not, it returns false
|
||||||
|
func goModuleRoot(dir string) (string, bool) {
|
||||||
dir, err := filepath.Abs(dir)
|
dir, err := filepath.Abs(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
dir = filepath.ToSlash(dir)
|
dir = filepath.ToSlash(dir)
|
||||||
|
|
||||||
modDir := dir
|
modDir := dir
|
||||||
assumedPart := ""
|
assumedPart := ""
|
||||||
for {
|
for {
|
||||||
f, err := ioutil.ReadFile(filepath.Join(modDir, "/", "go.mod"))
|
f, err := ioutil.ReadFile(filepath.Join(modDir, "go.mod"))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// found it, stop searching
|
// found it, stop searching
|
||||||
return string(modregex.FindSubmatch(f)[1]) + assumedPart
|
return string(modregex.FindSubmatch(f)[1]) + assumedPart, true
|
||||||
}
|
}
|
||||||
|
|
||||||
assumedPart = "/" + filepath.Base(modDir) + assumedPart
|
assumedPart = "/" + filepath.Base(modDir) + assumedPart
|
||||||
modDir, err = filepath.Abs(filepath.Join(modDir, ".."))
|
parentDir, err := filepath.Abs(filepath.Join(modDir, ".."))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if parentDir == modDir {
|
||||||
// Walked all the way to the root and didnt find anything :'(
|
// Walked all the way to the root and didnt find anything :'(
|
||||||
if modDir == "/" {
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
modDir = parentDir
|
||||||
|
}
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImportPathForDir takes a path and returns a golang import path for the package
|
||||||
|
func ImportPathForDir(dir string) (res string) {
|
||||||
|
dir, err := filepath.Abs(dir)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
dir = filepath.ToSlash(dir)
|
||||||
|
|
||||||
|
modDir, ok := goModuleRoot(dir)
|
||||||
|
if ok {
|
||||||
|
return modDir
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, gopath := range gopaths {
|
for _, gopath := range gopaths {
|
||||||
@@ -89,26 +100,4 @@ func ImportPathForDir(dir string) (res string) {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
var modregex = regexp.MustCompile("module (.*)\n")
|
var modregex = regexp.MustCompile(`module ([^\s]*)`)
|
||||||
|
|
||||||
// NameForPackage returns the package name for a given import path. This can be really slow.
|
|
||||||
func NameForPackage(importPath string) string {
|
|
||||||
if importPath == "" {
|
|
||||||
panic(errors.New("import path can not be empty"))
|
|
||||||
}
|
|
||||||
if v, ok := nameForPackageCache.Load(importPath); ok {
|
|
||||||
return v.(string)
|
|
||||||
}
|
|
||||||
importPath = QualifyPackagePath(importPath)
|
|
||||||
p, _ := packages.Load(&packages.Config{
|
|
||||||
Mode: packages.NeedName,
|
|
||||||
}, importPath)
|
|
||||||
|
|
||||||
if len(p) != 1 || p[0].Name == "" {
|
|
||||||
return SanitizePackageName(filepath.Base(importPath))
|
|
||||||
}
|
|
||||||
|
|
||||||
nameForPackageCache.Store(importPath, p[0].Name)
|
|
||||||
|
|
||||||
return p[0].Name
|
|
||||||
}
|
|
||||||
|
|||||||
173
vendor/github.com/99designs/gqlgen/internal/code/packages.go
generated
vendored
Normal file
173
vendor/github.com/99designs/gqlgen/internal/code/packages.go
generated
vendored
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
package code
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"golang.org/x/tools/go/packages"
|
||||||
|
)
|
||||||
|
|
||||||
|
var mode = packages.NeedName |
|
||||||
|
packages.NeedFiles |
|
||||||
|
packages.NeedImports |
|
||||||
|
packages.NeedTypes |
|
||||||
|
packages.NeedSyntax |
|
||||||
|
packages.NeedTypesInfo
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
type Packages struct {
|
||||||
|
packages map[string]*packages.Package
|
||||||
|
importToName map[string]string
|
||||||
|
loadErrors []error
|
||||||
|
|
||||||
|
numLoadCalls int // stupid test steam. ignore.
|
||||||
|
numNameCalls int // stupid test steam. ignore.
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadAll will call packages.Load and return the package data for the given packages,
|
||||||
|
// but if the package already have been loaded it will return cached values instead.
|
||||||
|
func (p *Packages) LoadAll(importPaths ...string) []*packages.Package {
|
||||||
|
if p.packages == nil {
|
||||||
|
p.packages = map[string]*packages.Package{}
|
||||||
|
}
|
||||||
|
|
||||||
|
missing := make([]string, 0, len(importPaths))
|
||||||
|
for _, path := range importPaths {
|
||||||
|
if _, ok := p.packages[path]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
missing = append(missing, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(missing) > 0 {
|
||||||
|
p.numLoadCalls++
|
||||||
|
pkgs, err := packages.Load(&packages.Config{Mode: mode}, missing...)
|
||||||
|
if err != nil {
|
||||||
|
p.loadErrors = append(p.loadErrors, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pkg := range pkgs {
|
||||||
|
p.addToCache(pkg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res := make([]*packages.Package, 0, len(importPaths))
|
||||||
|
for _, path := range importPaths {
|
||||||
|
res = append(res, p.packages[NormalizeVendor(path)])
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Packages) addToCache(pkg *packages.Package) {
|
||||||
|
imp := NormalizeVendor(pkg.PkgPath)
|
||||||
|
p.packages[imp] = pkg
|
||||||
|
for _, imp := range pkg.Imports {
|
||||||
|
if _, found := p.packages[NormalizeVendor(imp.PkgPath)]; !found {
|
||||||
|
p.addToCache(imp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load works the same as LoadAll, except a single package at a time.
|
||||||
|
func (p *Packages) Load(importPath string) *packages.Package {
|
||||||
|
pkgs := p.LoadAll(importPath)
|
||||||
|
if len(pkgs) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return pkgs[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadWithTypes tries a standard load, which may not have enough type info (TypesInfo== nil) available if the imported package is a
|
||||||
|
// second order dependency. Fortunately this doesnt happen very often, so we can just issue a load when we detect it.
|
||||||
|
func (p *Packages) LoadWithTypes(importPath string) *packages.Package {
|
||||||
|
pkg := p.Load(importPath)
|
||||||
|
if pkg == nil || pkg.TypesInfo == nil {
|
||||||
|
p.numLoadCalls++
|
||||||
|
pkgs, err := packages.Load(&packages.Config{Mode: mode}, importPath)
|
||||||
|
if err != nil {
|
||||||
|
p.loadErrors = append(p.loadErrors, err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
p.addToCache(pkgs[0])
|
||||||
|
pkg = pkgs[0]
|
||||||
|
}
|
||||||
|
return pkg
|
||||||
|
}
|
||||||
|
|
||||||
|
// NameForPackage looks up the package name from the package stanza in the go files at the given import path.
|
||||||
|
func (p *Packages) NameForPackage(importPath string) string {
|
||||||
|
if importPath == "" {
|
||||||
|
panic(errors.New("import path can not be empty"))
|
||||||
|
}
|
||||||
|
if p.importToName == nil {
|
||||||
|
p.importToName = map[string]string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
importPath = NormalizeVendor(importPath)
|
||||||
|
|
||||||
|
// if its in the name cache use it
|
||||||
|
if name := p.importToName[importPath]; name != "" {
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise we might have already loaded the full package data for it cached
|
||||||
|
pkg := p.packages[importPath]
|
||||||
|
|
||||||
|
if pkg == nil {
|
||||||
|
// otherwise do a name only lookup for it but dont put it in the package cache.
|
||||||
|
p.numNameCalls++
|
||||||
|
pkgs, err := packages.Load(&packages.Config{Mode: packages.NeedName}, importPath)
|
||||||
|
if err != nil {
|
||||||
|
p.loadErrors = append(p.loadErrors, err)
|
||||||
|
} else {
|
||||||
|
pkg = pkgs[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if pkg == nil || pkg.Name == "" {
|
||||||
|
return SanitizePackageName(filepath.Base(importPath))
|
||||||
|
}
|
||||||
|
|
||||||
|
p.importToName[importPath] = pkg.Name
|
||||||
|
|
||||||
|
return pkg.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evict removes a given package import path from the cache, along with any packages that depend on it. Further calls
|
||||||
|
// to Load will fetch it from disk.
|
||||||
|
func (p *Packages) Evict(importPath string) {
|
||||||
|
delete(p.packages, importPath)
|
||||||
|
|
||||||
|
for _, pkg := range p.packages {
|
||||||
|
for _, imported := range pkg.Imports {
|
||||||
|
if imported.PkgPath == importPath {
|
||||||
|
p.Evict(pkg.PkgPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errors returns any errors that were returned by Load, either from the call itself or any of the loaded packages.
|
||||||
|
func (p *Packages) Errors() PkgErrors {
|
||||||
|
var res []error //nolint:prealloc
|
||||||
|
res = append(res, p.loadErrors...)
|
||||||
|
for _, pkg := range p.packages {
|
||||||
|
for _, err := range pkg.Errors {
|
||||||
|
res = append(res, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
type PkgErrors []error
|
||||||
|
|
||||||
|
func (p PkgErrors) Error() string {
|
||||||
|
var b bytes.Buffer
|
||||||
|
b.WriteString("packages.Load: ")
|
||||||
|
for _, e := range p {
|
||||||
|
b.WriteString(e.Error() + "\n")
|
||||||
|
}
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
5
vendor/github.com/99designs/gqlgen/internal/code/util.go
generated
vendored
5
vendor/github.com/99designs/gqlgen/internal/code/util.go
generated
vendored
@@ -41,6 +41,11 @@ func NormalizeVendor(pkg string) string {
|
|||||||
func QualifyPackagePath(importPath string) string {
|
func QualifyPackagePath(importPath string) string {
|
||||||
wd, _ := os.Getwd()
|
wd, _ := os.Getwd()
|
||||||
|
|
||||||
|
// in go module mode, the import path doesn't need fixing
|
||||||
|
if _, ok := goModuleRoot(wd); ok {
|
||||||
|
return importPath
|
||||||
|
}
|
||||||
|
|
||||||
pkg, err := build.Import(importPath, wd, 0)
|
pkg, err := build.Import(importPath, wd, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return importPath
|
return importPath
|
||||||
|
|||||||
13
vendor/github.com/99designs/gqlgen/internal/imports/prune.go
generated
vendored
13
vendor/github.com/99designs/gqlgen/internal/imports/prune.go
generated
vendored
@@ -24,7 +24,7 @@ func (fn visitFn) Visit(node ast.Node) ast.Visitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Prune removes any unused imports
|
// Prune removes any unused imports
|
||||||
func Prune(filename string, src []byte) ([]byte, error) {
|
func Prune(filename string, src []byte, packages *code.Packages) ([]byte, error) {
|
||||||
fset := token.NewFileSet()
|
fset := token.NewFileSet()
|
||||||
|
|
||||||
file, err := parser.ParseFile(fset, filename, src, parser.ParseComments|parser.AllErrors)
|
file, err := parser.ParseFile(fset, filename, src, parser.ParseComments|parser.AllErrors)
|
||||||
@@ -32,10 +32,7 @@ func Prune(filename string, src []byte) ([]byte, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
unused, err := getUnusedImports(file, filename)
|
unused := getUnusedImports(file, packages)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for ipath, name := range unused {
|
for ipath, name := range unused {
|
||||||
astutil.DeleteNamedImport(fset, file, name, ipath)
|
astutil.DeleteNamedImport(fset, file, name, ipath)
|
||||||
}
|
}
|
||||||
@@ -49,7 +46,7 @@ func Prune(filename string, src []byte) ([]byte, error) {
|
|||||||
return imports.Process(filename, buf.Bytes(), &imports.Options{FormatOnly: true, Comments: true, TabIndent: true, TabWidth: 8})
|
return imports.Process(filename, buf.Bytes(), &imports.Options{FormatOnly: true, Comments: true, TabIndent: true, TabWidth: 8})
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUnusedImports(file ast.Node, filename string) (map[string]string, error) {
|
func getUnusedImports(file ast.Node, packages *code.Packages) map[string]string {
|
||||||
imported := map[string]*ast.ImportSpec{}
|
imported := map[string]*ast.ImportSpec{}
|
||||||
used := map[string]bool{}
|
used := map[string]bool{}
|
||||||
|
|
||||||
@@ -68,7 +65,7 @@ func getUnusedImports(file ast.Node, filename string) (map[string]string, error)
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
local := code.NameForPackage(ipath)
|
local := packages.NameForPackage(ipath)
|
||||||
|
|
||||||
imported[local] = v
|
imported[local] = v
|
||||||
case *ast.SelectorExpr:
|
case *ast.SelectorExpr:
|
||||||
@@ -99,5 +96,5 @@ func getUnusedImports(file ast.Node, filename string) (map[string]string, error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return unusedImport, nil
|
return unusedImport
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user