mirror of
https://github.com/MichaelMure/git-bug.git
synced 2024-12-14 17:51:44 +03:00
webui: add a primitive graphql handler
This commit is contained in:
parent
25fb88d749
commit
a2a50f3de0
26
Gopkg.lock
generated
26
Gopkg.lock
generated
@ -19,6 +19,30 @@
|
|||||||
revision = "e3702bed27f0d39777b0b37b664b6280e8ef8fbf"
|
revision = "e3702bed27f0d39777b0b37b664b6280e8ef8fbf"
|
||||||
version = "v1.6.2"
|
version = "v1.6.2"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/graphql-go/graphql"
|
||||||
|
packages = [
|
||||||
|
".",
|
||||||
|
"gqlerrors",
|
||||||
|
"language/ast",
|
||||||
|
"language/kinds",
|
||||||
|
"language/lexer",
|
||||||
|
"language/location",
|
||||||
|
"language/parser",
|
||||||
|
"language/printer",
|
||||||
|
"language/source",
|
||||||
|
"language/typeInfo",
|
||||||
|
"language/visitor"
|
||||||
|
]
|
||||||
|
revision = "1e23489041ba90a66f317fe0deccb236a2fff3cb"
|
||||||
|
version = "v0.7.5"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/graphql-go/handler"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "f0393b2c10daeebea900292b8e092e73475399d9"
|
||||||
|
version = "v0.2.1"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/inconshreveable/mousetrap"
|
name = "github.com/inconshreveable/mousetrap"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
@ -88,6 +112,6 @@
|
|||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "412a40943b853e1f7488ac4facf6b87893c3b3dc91a94a3838632b40db5ade79"
|
inputs-digest = "afa5ad0f3fc2fcf050827b85570638dc9a787498e73200b01b01432bba1b1e1c"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
@ -53,6 +53,14 @@
|
|||||||
name = "github.com/spf13/cobra"
|
name = "github.com/spf13/cobra"
|
||||||
version = "v0.0.3"
|
version = "v0.0.3"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/graphql-go/graphql"
|
||||||
|
version = "v0.7.5"
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/graphql-go/handler"
|
||||||
|
version = "v0.2.1"
|
||||||
|
|
||||||
# required for test on travis with go 1.8
|
# required for test on travis with go 1.8
|
||||||
[[override]]
|
[[override]]
|
||||||
name = "github.com/spf13/viper"
|
name = "github.com/spf13/viper"
|
||||||
|
@ -2,6 +2,7 @@ package commands
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/MichaelMure/git-bug/graphql"
|
||||||
"github.com/MichaelMure/git-bug/webui"
|
"github.com/MichaelMure/git-bug/webui"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/phayes/freeport"
|
"github.com/phayes/freeport"
|
||||||
@ -18,11 +19,23 @@ func runWebUI(cmd *cobra.Command, args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addr := fmt.Sprintf("127.0.0.1:%d", port)
|
addr := fmt.Sprintf("127.0.0.1:%d", port)
|
||||||
|
webUiAddr := fmt.Sprintf("http://%s", addr)
|
||||||
|
|
||||||
|
fmt.Printf("Web UI available at %s\n", webUiAddr)
|
||||||
|
|
||||||
|
graphqlHandler, err := graphql.NewHandler()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
|
|
||||||
|
// Routes
|
||||||
|
router.Path("/graphql").Handler(graphqlHandler)
|
||||||
router.PathPrefix("/").Handler(http.FileServer(webui.WebUIAssets))
|
router.PathPrefix("/").Handler(http.FileServer(webui.WebUIAssets))
|
||||||
|
|
||||||
open.Run(fmt.Sprintf("http://%s", addr))
|
open.Run(webUiAddr)
|
||||||
|
|
||||||
log.Fatal(http.ListenAndServe(addr, router))
|
log.Fatal(http.ListenAndServe(addr, router))
|
||||||
|
|
||||||
|
17
graphql/handler.go
Normal file
17
graphql/handler.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package graphql
|
||||||
|
|
||||||
|
import "github.com/graphql-go/handler"
|
||||||
|
|
||||||
|
func NewHandler() (*handler.Handler, error) {
|
||||||
|
schema, err := graphqlSchema()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return handler.New(&handler.Config{
|
||||||
|
Schema: &schema,
|
||||||
|
Pretty: true,
|
||||||
|
GraphiQL: true,
|
||||||
|
}), nil
|
||||||
|
}
|
17
graphql/schema.go
Normal file
17
graphql/schema.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package graphql
|
||||||
|
|
||||||
|
import "github.com/graphql-go/graphql"
|
||||||
|
|
||||||
|
func graphqlSchema() (graphql.Schema, error) {
|
||||||
|
fields := graphql.Fields{
|
||||||
|
"hello": &graphql.Field{
|
||||||
|
Type: graphql.String,
|
||||||
|
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
|
||||||
|
return "world", nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
rootQuery := graphql.ObjectConfig{Name: "RootQuery", Fields: fields}
|
||||||
|
schemaConfig := graphql.SchemaConfig{Query: graphql.NewObject(rootQuery)}
|
||||||
|
return graphql.NewSchema(schemaConfig)
|
||||||
|
}
|
2
vendor/github.com/graphql-go/graphql/.gitignore
generated
vendored
Normal file
2
vendor/github.com/graphql-go/graphql/.gitignore
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
.DS_Store
|
||||||
|
.idea
|
20
vendor/github.com/graphql-go/graphql/.travis.yml
generated
vendored
Normal file
20
vendor/github.com/graphql-go/graphql/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.8.x
|
||||||
|
- 1.9.x
|
||||||
|
- 1.10.x
|
||||||
|
- tip
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
allow_failures:
|
||||||
|
- go: tip
|
||||||
|
fast_finish: true
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- go get github.com/axw/gocov/gocov
|
||||||
|
- go get github.com/mattn/goveralls
|
||||||
|
|
||||||
|
script:
|
||||||
|
- $HOME/gopath/bin/goveralls -race -service=travis-ci
|
||||||
|
- go vet ./...
|
139
vendor/github.com/graphql-go/graphql/CONTRIBUTING.md
generated
vendored
Normal file
139
vendor/github.com/graphql-go/graphql/CONTRIBUTING.md
generated
vendored
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
# Contributing to graphql
|
||||||
|
|
||||||
|
This document is based on the [Node.js contribution guidelines](https://github.com/nodejs/node/blob/master/CONTRIBUTING.md)
|
||||||
|
|
||||||
|
## Chat room
|
||||||
|
|
||||||
|
[![Join the chat at https://gitter.im/graphql-go/graphql](https://badges.gitter.im/Join%20Chat.svg)]
|
||||||
|
(https://gitter.im/graphql-go/graphql?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
|
||||||
|
Feel free to participate in the chat room for informal discussions and queries.
|
||||||
|
|
||||||
|
Just drop by and say hi!
|
||||||
|
|
||||||
|
## Issue Contributions
|
||||||
|
|
||||||
|
When opening new issues or commenting on existing issues on this repository
|
||||||
|
please make sure discussions are related to concrete technical issues with the
|
||||||
|
`graphql` implementation.
|
||||||
|
|
||||||
|
## Code Contributions
|
||||||
|
|
||||||
|
The `graphql` project welcomes new contributors.
|
||||||
|
|
||||||
|
This document will guide you through the contribution process.
|
||||||
|
|
||||||
|
What do you want to contribute?
|
||||||
|
|
||||||
|
- I want to otherwise correct or improve the docs or examples
|
||||||
|
- I want to report a bug
|
||||||
|
- I want to add some feature or functionality to an existing hardware platform
|
||||||
|
- I want to add support for a new hardware platform
|
||||||
|
|
||||||
|
Descriptions for each of these will eventually be provided below.
|
||||||
|
|
||||||
|
## General Guidelines
|
||||||
|
* Reading up on [CodeReviewComments](https://github.com/golang/go/wiki/CodeReviewComments) would be a great start.
|
||||||
|
* Submit a Github Pull Request to the appropriate branch and ideally discuss the changes with us in the [chat room](#chat-room).
|
||||||
|
* We will look at the patch, test it out, and give you feedback.
|
||||||
|
* Avoid doing minor whitespace changes, renaming, etc. along with merged content. These will be done by the maintainers from time to time but they can complicate merges and should be done separately.
|
||||||
|
* Take care to maintain the existing coding style.
|
||||||
|
* Always `golint` and `go fmt` your code.
|
||||||
|
* Add unit tests for any new or changed functionality, especially for public APIs.
|
||||||
|
* Run `go test` before submitting a PR.
|
||||||
|
* For git help see [progit](http://git-scm.com/book) which is an awesome (and free) book on git
|
||||||
|
|
||||||
|
|
||||||
|
## Creating Pull Requests
|
||||||
|
Because `graphql` makes use of self-referencing import paths, you will want
|
||||||
|
to implement the local copy of your fork as a remote on your copy of the
|
||||||
|
original `graphql` repo. Katrina Owen has [an excellent post on this workflow](https://splice.com/blog/contributing-open-source-git-repositories-go/).
|
||||||
|
|
||||||
|
The basics are as follows:
|
||||||
|
|
||||||
|
1. Fork the project via the GitHub UI
|
||||||
|
|
||||||
|
2. `go get` the upstream repo and set it up as the `upstream` remote and your own repo as the `origin` remote:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ go get github.com/graphql-go/graphql
|
||||||
|
$ cd $GOPATH/src/github.com/graphql-go/graphql
|
||||||
|
$ git remote rename origin upstream
|
||||||
|
$ git remote add origin git@github.com/YOUR_GITHUB_NAME/graphql
|
||||||
|
```
|
||||||
|
All import paths should now work fine assuming that you've got the
|
||||||
|
proper branch checked out.
|
||||||
|
|
||||||
|
|
||||||
|
## Landing Pull Requests
|
||||||
|
(This is for committers only. If you are unsure whether you are a committer, you are not.)
|
||||||
|
|
||||||
|
1. Set the contributor's fork as an upstream on your checkout
|
||||||
|
|
||||||
|
```git remote add contrib1 https://github.com/contrib1/graphql```
|
||||||
|
|
||||||
|
2. Fetch the contributor's repo
|
||||||
|
|
||||||
|
```git fetch contrib1```
|
||||||
|
|
||||||
|
3. Checkout a copy of the PR branch
|
||||||
|
|
||||||
|
```git checkout pr-1234 --track contrib1/branch-for-pr-1234```
|
||||||
|
|
||||||
|
4. Review the PR as normal
|
||||||
|
|
||||||
|
5. Land when you're ready via the GitHub UI
|
||||||
|
|
||||||
|
## Developer's Certificate of Origin 1.0
|
||||||
|
|
||||||
|
By making a contribution to this project, I certify that:
|
||||||
|
|
||||||
|
* (a) The contribution was created in whole or in part by me and I
|
||||||
|
have the right to submit it under the open source license indicated
|
||||||
|
in the file; or
|
||||||
|
* (b) The contribution is based upon previous work that, to the best
|
||||||
|
of my knowledge, is covered under an appropriate open source license
|
||||||
|
and I have the right under that license to submit that work with
|
||||||
|
modifications, whether created in whole or in part by me, under the
|
||||||
|
same open source license (unless I am permitted to submit under a
|
||||||
|
different license), as indicated in the file; or
|
||||||
|
* (c) The contribution was provided directly to me by some other
|
||||||
|
person who certified (a), (b) or (c) and I have not modified it.
|
||||||
|
|
||||||
|
|
||||||
|
## Code of Conduct
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from [Rust's wonderful
|
||||||
|
CoC](http://www.rust-lang.org/conduct.html).
|
||||||
|
|
||||||
|
* We are committed to providing a friendly, safe and welcoming
|
||||||
|
environment for all, regardless of gender, sexual orientation,
|
||||||
|
disability, ethnicity, religion, or similar personal characteristic.
|
||||||
|
* Please avoid using overtly sexual nicknames or other nicknames that
|
||||||
|
might detract from a friendly, safe and welcoming environment for
|
||||||
|
all.
|
||||||
|
* Please be kind and courteous. There's no need to be mean or rude.
|
||||||
|
* Respect that people have differences of opinion and that every
|
||||||
|
design or implementation choice carries a trade-off and numerous
|
||||||
|
costs. There is seldom a right answer.
|
||||||
|
* Please keep unstructured critique to a minimum. If you have solid
|
||||||
|
ideas you want to experiment with, make a fork and see how it works.
|
||||||
|
* We will exclude you from interaction if you insult, demean or harass
|
||||||
|
anyone. That is not welcome behaviour. We interpret the term
|
||||||
|
"harassment" as including the definition in the [Citizen Code of
|
||||||
|
Conduct](http://citizencodeofconduct.org/); if you have any lack of
|
||||||
|
clarity about what might be included in that concept, please read
|
||||||
|
their definition. In particular, we don't tolerate behavior that
|
||||||
|
excludes people in socially marginalized groups.
|
||||||
|
* Private harassment is also unacceptable. No matter who you are, if
|
||||||
|
you feel you have been or are being harassed or made uncomfortable
|
||||||
|
by a community member, please contact one of the channel ops or any
|
||||||
|
of the TC members immediately with a capture (log, photo, email) of
|
||||||
|
the harassment if possible. Whether you're a regular contributor or
|
||||||
|
a newcomer, we care about making this community a safe place for you
|
||||||
|
and we've got your back.
|
||||||
|
* Likewise any spamming, trolling, flaming, baiting or other
|
||||||
|
attention-stealing behaviour is not welcome.
|
||||||
|
* Avoid the use of personal pronouns in code comments or
|
||||||
|
documentation. There is no need to address persons when explaining
|
||||||
|
code (e.g. "When the developer")
|
21
vendor/github.com/graphql-go/graphql/LICENSE
generated
vendored
Normal file
21
vendor/github.com/graphql-go/graphql/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Chris Ramón
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
75
vendor/github.com/graphql-go/graphql/README.md
generated
vendored
Normal file
75
vendor/github.com/graphql-go/graphql/README.md
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
# graphql [![Build Status](https://travis-ci.org/graphql-go/graphql.svg)](https://travis-ci.org/graphql-go/graphql) [![GoDoc](https://godoc.org/graphql.co/graphql?status.svg)](https://godoc.org/github.com/graphql-go/graphql) [![Coverage Status](https://coveralls.io/repos/graphql-go/graphql/badge.svg?branch=master&service=github)](https://coveralls.io/github/graphql-go/graphql?branch=master) [![Join the chat at https://gitter.im/graphql-go/graphql](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/graphql-go/graphql?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
|
||||||
|
An implementation of GraphQL in Go. Follows the official reference implementation [`graphql-js`](https://github.com/graphql/graphql-js).
|
||||||
|
|
||||||
|
Supports: queries, mutations & subscriptions.
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
godoc: https://godoc.org/github.com/graphql-go/graphql
|
||||||
|
|
||||||
|
### Getting Started
|
||||||
|
|
||||||
|
To install the library, run:
|
||||||
|
```bash
|
||||||
|
go get github.com/graphql-go/graphql
|
||||||
|
```
|
||||||
|
|
||||||
|
The following is a simple example which defines a schema with a single `hello` string-type field and a `Resolve` method which returns the string `world`. A GraphQL query is performed against this schema with the resulting output printed in JSON format.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/graphql-go/graphql"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Schema
|
||||||
|
fields := graphql.Fields{
|
||||||
|
"hello": &graphql.Field{
|
||||||
|
Type: graphql.String,
|
||||||
|
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
|
||||||
|
return "world", nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
rootQuery := graphql.ObjectConfig{Name: "RootQuery", Fields: fields}
|
||||||
|
schemaConfig := graphql.SchemaConfig{Query: graphql.NewObject(rootQuery)}
|
||||||
|
schema, err := graphql.NewSchema(schemaConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to create new schema, error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query
|
||||||
|
query := `
|
||||||
|
{
|
||||||
|
hello
|
||||||
|
}
|
||||||
|
`
|
||||||
|
params := graphql.Params{Schema: schema, RequestString: query}
|
||||||
|
r := graphql.Do(params)
|
||||||
|
if len(r.Errors) > 0 {
|
||||||
|
log.Fatalf("failed to execute graphql operation, errors: %+v", r.Errors)
|
||||||
|
}
|
||||||
|
rJSON, _ := json.Marshal(r)
|
||||||
|
fmt.Printf("%s \n", rJSON) // {“data”:{“hello”:”world”}}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
For more complex examples, refer to the [examples/](https://github.com/graphql-go/graphql/tree/master/examples/) directory and [graphql_test.go](https://github.com/graphql-go/graphql/blob/master/graphql_test.go).
|
||||||
|
|
||||||
|
### Third Party Libraries
|
||||||
|
| Name | Author | Description |
|
||||||
|
|:-------------:|:-------------:|:------------:|
|
||||||
|
| [graphql-go-handler](https://github.com/graphql-go/graphql-go-handler) | [Hafiz Ismail](https://github.com/sogko) | Middleware to handle GraphQL queries through HTTP requests. |
|
||||||
|
| [graphql-relay-go](https://github.com/graphql-go/graphql-relay-go) | [Hafiz Ismail](https://github.com/sogko) | Lib to construct a graphql-go server supporting react-relay. |
|
||||||
|
| [golang-relay-starter-kit](https://github.com/sogko/golang-relay-starter-kit) | [Hafiz Ismail](https://github.com/sogko) | Barebones starting point for a Relay application with Golang GraphQL server. |
|
||||||
|
| [dataloader](https://github.com/nicksrandall/dataloader) | [Nick Randall](https://github.com/nicksrandall) | [DataLoader](https://github.com/facebook/dataloader) implementation in Go. |
|
||||||
|
|
||||||
|
### Blog Posts
|
||||||
|
- [Golang + GraphQL + Relay](http://wehavefaces.net/)
|
||||||
|
|
1340
vendor/github.com/graphql-go/graphql/definition.go
generated
vendored
Normal file
1340
vendor/github.com/graphql-go/graphql/definition.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
156
vendor/github.com/graphql-go/graphql/directives.go
generated
vendored
Normal file
156
vendor/github.com/graphql-go/graphql/directives.go
generated
vendored
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
package graphql
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Operations
|
||||||
|
DirectiveLocationQuery = "QUERY"
|
||||||
|
DirectiveLocationMutation = "MUTATION"
|
||||||
|
DirectiveLocationSubscription = "SUBSCRIPTION"
|
||||||
|
DirectiveLocationField = "FIELD"
|
||||||
|
DirectiveLocationFragmentDefinition = "FRAGMENT_DEFINITION"
|
||||||
|
DirectiveLocationFragmentSpread = "FRAGMENT_SPREAD"
|
||||||
|
DirectiveLocationInlineFragment = "INLINE_FRAGMENT"
|
||||||
|
|
||||||
|
// Schema Definitions
|
||||||
|
DirectiveLocationSchema = "SCHEMA"
|
||||||
|
DirectiveLocationScalar = "SCALAR"
|
||||||
|
DirectiveLocationObject = "OBJECT"
|
||||||
|
DirectiveLocationFieldDefinition = "FIELD_DEFINITION"
|
||||||
|
DirectiveLocationArgumentDefinition = "ARGUMENT_DEFINITION"
|
||||||
|
DirectiveLocationInterface = "INTERFACE"
|
||||||
|
DirectiveLocationUnion = "UNION"
|
||||||
|
DirectiveLocationEnum = "ENUM"
|
||||||
|
DirectiveLocationEnumValue = "ENUM_VALUE"
|
||||||
|
DirectiveLocationInputObject = "INPUT_OBJECT"
|
||||||
|
DirectiveLocationInputFieldDefinition = "INPUT_FIELD_DEFINITION"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DefaultDeprecationReason Constant string used for default reason for a deprecation.
|
||||||
|
const DefaultDeprecationReason = "No longer supported"
|
||||||
|
|
||||||
|
// SpecifiedRules The full list of specified directives.
|
||||||
|
var SpecifiedDirectives = []*Directive{
|
||||||
|
IncludeDirective,
|
||||||
|
SkipDirective,
|
||||||
|
DeprecatedDirective,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Directive structs are used by the GraphQL runtime as a way of modifying execution
|
||||||
|
// behavior. Type system creators will usually not create these directly.
|
||||||
|
type Directive struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Locations []string `json:"locations"`
|
||||||
|
Args []*Argument `json:"args"`
|
||||||
|
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
// DirectiveConfig options for creating a new GraphQLDirective
|
||||||
|
type DirectiveConfig struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Locations []string `json:"locations"`
|
||||||
|
Args FieldConfigArgument `json:"args"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDirective(config DirectiveConfig) *Directive {
|
||||||
|
dir := &Directive{}
|
||||||
|
|
||||||
|
// Ensure directive is named
|
||||||
|
err := invariant(config.Name != "", "Directive must be named.")
|
||||||
|
if err != nil {
|
||||||
|
dir.err = err
|
||||||
|
return dir
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure directive name is valid
|
||||||
|
err = assertValidName(config.Name)
|
||||||
|
if err != nil {
|
||||||
|
dir.err = err
|
||||||
|
return dir
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure locations are provided for directive
|
||||||
|
err = invariant(len(config.Locations) > 0, "Must provide locations for directive.")
|
||||||
|
if err != nil {
|
||||||
|
dir.err = err
|
||||||
|
return dir
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []*Argument{}
|
||||||
|
|
||||||
|
for argName, argConfig := range config.Args {
|
||||||
|
err := assertValidName(argName)
|
||||||
|
if err != nil {
|
||||||
|
dir.err = err
|
||||||
|
return dir
|
||||||
|
}
|
||||||
|
args = append(args, &Argument{
|
||||||
|
PrivateName: argName,
|
||||||
|
PrivateDescription: argConfig.Description,
|
||||||
|
Type: argConfig.Type,
|
||||||
|
DefaultValue: argConfig.DefaultValue,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
dir.Name = config.Name
|
||||||
|
dir.Description = config.Description
|
||||||
|
dir.Locations = config.Locations
|
||||||
|
dir.Args = args
|
||||||
|
return dir
|
||||||
|
}
|
||||||
|
|
||||||
|
// IncludeDirective is used to conditionally include fields or fragments.
|
||||||
|
var IncludeDirective = NewDirective(DirectiveConfig{
|
||||||
|
Name: "include",
|
||||||
|
Description: "Directs the executor to include this field or fragment only when " +
|
||||||
|
"the `if` argument is true.",
|
||||||
|
Locations: []string{
|
||||||
|
DirectiveLocationField,
|
||||||
|
DirectiveLocationFragmentSpread,
|
||||||
|
DirectiveLocationInlineFragment,
|
||||||
|
},
|
||||||
|
Args: FieldConfigArgument{
|
||||||
|
"if": &ArgumentConfig{
|
||||||
|
Type: NewNonNull(Boolean),
|
||||||
|
Description: "Included when true.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// SkipDirective Used to conditionally skip (exclude) fields or fragments.
|
||||||
|
var SkipDirective = NewDirective(DirectiveConfig{
|
||||||
|
Name: "skip",
|
||||||
|
Description: "Directs the executor to skip this field or fragment when the `if` " +
|
||||||
|
"argument is true.",
|
||||||
|
Args: FieldConfigArgument{
|
||||||
|
"if": &ArgumentConfig{
|
||||||
|
Type: NewNonNull(Boolean),
|
||||||
|
Description: "Skipped when true.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Locations: []string{
|
||||||
|
DirectiveLocationField,
|
||||||
|
DirectiveLocationFragmentSpread,
|
||||||
|
DirectiveLocationInlineFragment,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// DeprecatedDirective Used to declare element of a GraphQL schema as deprecated.
|
||||||
|
var DeprecatedDirective = NewDirective(DirectiveConfig{
|
||||||
|
Name: "deprecated",
|
||||||
|
Description: "Marks an element of a GraphQL schema as no longer supported.",
|
||||||
|
Args: FieldConfigArgument{
|
||||||
|
"reason": &ArgumentConfig{
|
||||||
|
Type: String,
|
||||||
|
Description: "Explains why this element was deprecated, usually also including a " +
|
||||||
|
"suggestion for how to access supported similar data. Formatted" +
|
||||||
|
"in [Markdown](https://daringfireball.net/projects/markdown/).",
|
||||||
|
DefaultValue: DefaultDeprecationReason,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Locations: []string{
|
||||||
|
DirectiveLocationFieldDefinition,
|
||||||
|
DirectiveLocationEnumValue,
|
||||||
|
},
|
||||||
|
})
|
921
vendor/github.com/graphql-go/graphql/executor.go
generated
vendored
Normal file
921
vendor/github.com/graphql-go/graphql/executor.go
generated
vendored
Normal file
@ -0,0 +1,921 @@
|
|||||||
|
package graphql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/graphql-go/graphql/gqlerrors"
|
||||||
|
"github.com/graphql-go/graphql/language/ast"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ExecuteParams struct {
|
||||||
|
Schema Schema
|
||||||
|
Root interface{}
|
||||||
|
AST *ast.Document
|
||||||
|
OperationName string
|
||||||
|
Args map[string]interface{}
|
||||||
|
|
||||||
|
// Context may be provided to pass application-specific per-request
|
||||||
|
// information to resolve functions.
|
||||||
|
Context context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func Execute(p ExecuteParams) (result *Result) {
|
||||||
|
// Use background context if no context was provided
|
||||||
|
ctx := p.Context
|
||||||
|
if ctx == nil {
|
||||||
|
ctx = context.Background()
|
||||||
|
}
|
||||||
|
|
||||||
|
resultChannel := make(chan *Result)
|
||||||
|
|
||||||
|
go func(out chan<- *Result, done <-chan struct{}) {
|
||||||
|
result := &Result{}
|
||||||
|
|
||||||
|
exeContext, err := buildExecutionContext(buildExecutionCtxParams{
|
||||||
|
Schema: p.Schema,
|
||||||
|
Root: p.Root,
|
||||||
|
AST: p.AST,
|
||||||
|
OperationName: p.OperationName,
|
||||||
|
Args: p.Args,
|
||||||
|
Errors: nil,
|
||||||
|
Result: result,
|
||||||
|
Context: p.Context,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
result.Errors = append(result.Errors, gqlerrors.FormatError(err))
|
||||||
|
select {
|
||||||
|
case out <- result:
|
||||||
|
case <-done:
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
var err error
|
||||||
|
if r, ok := r.(error); ok {
|
||||||
|
err = gqlerrors.FormatError(r)
|
||||||
|
}
|
||||||
|
exeContext.Errors = append(exeContext.Errors, gqlerrors.FormatError(err))
|
||||||
|
result.Errors = exeContext.Errors
|
||||||
|
select {
|
||||||
|
case out <- result:
|
||||||
|
case <-done:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
result = executeOperation(executeOperationParams{
|
||||||
|
ExecutionContext: exeContext,
|
||||||
|
Root: p.Root,
|
||||||
|
Operation: exeContext.Operation,
|
||||||
|
})
|
||||||
|
select {
|
||||||
|
case out <- result:
|
||||||
|
case <-done:
|
||||||
|
}
|
||||||
|
|
||||||
|
}(resultChannel, ctx.Done())
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
result = &Result{}
|
||||||
|
result.Errors = append(result.Errors, gqlerrors.FormatError(ctx.Err()))
|
||||||
|
case r := <-resultChannel:
|
||||||
|
result = r
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type buildExecutionCtxParams struct {
|
||||||
|
Schema Schema
|
||||||
|
Root interface{}
|
||||||
|
AST *ast.Document
|
||||||
|
OperationName string
|
||||||
|
Args map[string]interface{}
|
||||||
|
Errors []gqlerrors.FormattedError
|
||||||
|
Result *Result
|
||||||
|
Context context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
type executionContext struct {
|
||||||
|
Schema Schema
|
||||||
|
Fragments map[string]ast.Definition
|
||||||
|
Root interface{}
|
||||||
|
Operation ast.Definition
|
||||||
|
VariableValues map[string]interface{}
|
||||||
|
Errors []gqlerrors.FormattedError
|
||||||
|
Context context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildExecutionContext(p buildExecutionCtxParams) (*executionContext, error) {
|
||||||
|
eCtx := &executionContext{}
|
||||||
|
var operation *ast.OperationDefinition
|
||||||
|
fragments := map[string]ast.Definition{}
|
||||||
|
|
||||||
|
for _, definition := range p.AST.Definitions {
|
||||||
|
switch definition := definition.(type) {
|
||||||
|
case *ast.OperationDefinition:
|
||||||
|
if (p.OperationName == "") && operation != nil {
|
||||||
|
return nil, errors.New("Must provide operation name if query contains multiple operations.")
|
||||||
|
}
|
||||||
|
if p.OperationName == "" || definition.GetName() != nil && definition.GetName().Value == p.OperationName {
|
||||||
|
operation = definition
|
||||||
|
}
|
||||||
|
case *ast.FragmentDefinition:
|
||||||
|
key := ""
|
||||||
|
if definition.GetName() != nil && definition.GetName().Value != "" {
|
||||||
|
key = definition.GetName().Value
|
||||||
|
}
|
||||||
|
fragments[key] = definition
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("GraphQL cannot execute a request containing a %v", definition.GetKind())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if operation == nil {
|
||||||
|
if p.OperationName != "" {
|
||||||
|
return nil, fmt.Errorf(`Unknown operation named "%v".`, p.OperationName)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf(`Must provide an operation.`)
|
||||||
|
}
|
||||||
|
|
||||||
|
variableValues, err := getVariableValues(p.Schema, operation.GetVariableDefinitions(), p.Args)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
eCtx.Schema = p.Schema
|
||||||
|
eCtx.Fragments = fragments
|
||||||
|
eCtx.Root = p.Root
|
||||||
|
eCtx.Operation = operation
|
||||||
|
eCtx.VariableValues = variableValues
|
||||||
|
eCtx.Errors = p.Errors
|
||||||
|
eCtx.Context = p.Context
|
||||||
|
return eCtx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type executeOperationParams struct {
|
||||||
|
ExecutionContext *executionContext
|
||||||
|
Root interface{}
|
||||||
|
Operation ast.Definition
|
||||||
|
}
|
||||||
|
|
||||||
|
func executeOperation(p executeOperationParams) *Result {
|
||||||
|
operationType, err := getOperationRootType(p.ExecutionContext.Schema, p.Operation)
|
||||||
|
if err != nil {
|
||||||
|
return &Result{Errors: gqlerrors.FormatErrors(err)}
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := collectFields(collectFieldsParams{
|
||||||
|
ExeContext: p.ExecutionContext,
|
||||||
|
RuntimeType: operationType,
|
||||||
|
SelectionSet: p.Operation.GetSelectionSet(),
|
||||||
|
})
|
||||||
|
|
||||||
|
executeFieldsParams := executeFieldsParams{
|
||||||
|
ExecutionContext: p.ExecutionContext,
|
||||||
|
ParentType: operationType,
|
||||||
|
Source: p.Root,
|
||||||
|
Fields: fields,
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.Operation.GetOperation() == ast.OperationTypeMutation {
|
||||||
|
return executeFieldsSerially(executeFieldsParams)
|
||||||
|
}
|
||||||
|
return executeFields(executeFieldsParams)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extracts the root type of the operation from the schema.
|
||||||
|
func getOperationRootType(schema Schema, operation ast.Definition) (*Object, error) {
|
||||||
|
if operation == nil {
|
||||||
|
return nil, errors.New("Can only execute queries and mutations")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch operation.GetOperation() {
|
||||||
|
case ast.OperationTypeQuery:
|
||||||
|
return schema.QueryType(), nil
|
||||||
|
case ast.OperationTypeMutation:
|
||||||
|
mutationType := schema.MutationType()
|
||||||
|
if mutationType.PrivateName == "" {
|
||||||
|
return nil, gqlerrors.NewError(
|
||||||
|
"Schema is not configured for mutations",
|
||||||
|
[]ast.Node{operation},
|
||||||
|
"",
|
||||||
|
nil,
|
||||||
|
[]int{},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return mutationType, nil
|
||||||
|
case ast.OperationTypeSubscription:
|
||||||
|
subscriptionType := schema.SubscriptionType()
|
||||||
|
if subscriptionType.PrivateName == "" {
|
||||||
|
return nil, gqlerrors.NewError(
|
||||||
|
"Schema is not configured for subscriptions",
|
||||||
|
[]ast.Node{operation},
|
||||||
|
"",
|
||||||
|
nil,
|
||||||
|
[]int{},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return subscriptionType, nil
|
||||||
|
default:
|
||||||
|
return nil, gqlerrors.NewError(
|
||||||
|
"Can only execute queries, mutations and subscription",
|
||||||
|
[]ast.Node{operation},
|
||||||
|
"",
|
||||||
|
nil,
|
||||||
|
[]int{},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type executeFieldsParams struct {
|
||||||
|
ExecutionContext *executionContext
|
||||||
|
ParentType *Object
|
||||||
|
Source interface{}
|
||||||
|
Fields map[string][]*ast.Field
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements the "Evaluating selection sets" section of the spec for "write" mode.
|
||||||
|
func executeFieldsSerially(p executeFieldsParams) *Result {
|
||||||
|
if p.Source == nil {
|
||||||
|
p.Source = map[string]interface{}{}
|
||||||
|
}
|
||||||
|
if p.Fields == nil {
|
||||||
|
p.Fields = map[string][]*ast.Field{}
|
||||||
|
}
|
||||||
|
|
||||||
|
finalResults := map[string]interface{}{}
|
||||||
|
for responseName, fieldASTs := range p.Fields {
|
||||||
|
resolved, state := resolveField(p.ExecutionContext, p.ParentType, p.Source, fieldASTs)
|
||||||
|
if state.hasNoFieldDefs {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
finalResults[responseName] = resolved
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Result{
|
||||||
|
Data: finalResults,
|
||||||
|
Errors: p.ExecutionContext.Errors,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements the "Evaluating selection sets" section of the spec for "read" mode.
|
||||||
|
func executeFields(p executeFieldsParams) *Result {
|
||||||
|
if p.Source == nil {
|
||||||
|
p.Source = map[string]interface{}{}
|
||||||
|
}
|
||||||
|
if p.Fields == nil {
|
||||||
|
p.Fields = map[string][]*ast.Field{}
|
||||||
|
}
|
||||||
|
|
||||||
|
finalResults := map[string]interface{}{}
|
||||||
|
for responseName, fieldASTs := range p.Fields {
|
||||||
|
resolved, state := resolveField(p.ExecutionContext, p.ParentType, p.Source, fieldASTs)
|
||||||
|
if state.hasNoFieldDefs {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
finalResults[responseName] = resolved
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Result{
|
||||||
|
Data: finalResults,
|
||||||
|
Errors: p.ExecutionContext.Errors,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type collectFieldsParams struct {
|
||||||
|
ExeContext *executionContext
|
||||||
|
RuntimeType *Object // previously known as OperationType
|
||||||
|
SelectionSet *ast.SelectionSet
|
||||||
|
Fields map[string][]*ast.Field
|
||||||
|
VisitedFragmentNames map[string]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given a selectionSet, adds all of the fields in that selection to
|
||||||
|
// the passed in map of fields, and returns it at the end.
|
||||||
|
// CollectFields requires the "runtime type" of an object. For a field which
|
||||||
|
// returns and Interface or Union type, the "runtime type" will be the actual
|
||||||
|
// Object type returned by that field.
|
||||||
|
func collectFields(p collectFieldsParams) map[string][]*ast.Field {
|
||||||
|
|
||||||
|
fields := p.Fields
|
||||||
|
if fields == nil {
|
||||||
|
fields = map[string][]*ast.Field{}
|
||||||
|
}
|
||||||
|
if p.VisitedFragmentNames == nil {
|
||||||
|
p.VisitedFragmentNames = map[string]bool{}
|
||||||
|
}
|
||||||
|
if p.SelectionSet == nil {
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
for _, iSelection := range p.SelectionSet.Selections {
|
||||||
|
switch selection := iSelection.(type) {
|
||||||
|
case *ast.Field:
|
||||||
|
if !shouldIncludeNode(p.ExeContext, selection.Directives) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
name := getFieldEntryKey(selection)
|
||||||
|
if _, ok := fields[name]; !ok {
|
||||||
|
fields[name] = []*ast.Field{}
|
||||||
|
}
|
||||||
|
fields[name] = append(fields[name], selection)
|
||||||
|
case *ast.InlineFragment:
|
||||||
|
|
||||||
|
if !shouldIncludeNode(p.ExeContext, selection.Directives) ||
|
||||||
|
!doesFragmentConditionMatch(p.ExeContext, selection, p.RuntimeType) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
innerParams := collectFieldsParams{
|
||||||
|
ExeContext: p.ExeContext,
|
||||||
|
RuntimeType: p.RuntimeType,
|
||||||
|
SelectionSet: selection.SelectionSet,
|
||||||
|
Fields: fields,
|
||||||
|
VisitedFragmentNames: p.VisitedFragmentNames,
|
||||||
|
}
|
||||||
|
collectFields(innerParams)
|
||||||
|
case *ast.FragmentSpread:
|
||||||
|
fragName := ""
|
||||||
|
if selection.Name != nil {
|
||||||
|
fragName = selection.Name.Value
|
||||||
|
}
|
||||||
|
if visited, ok := p.VisitedFragmentNames[fragName]; (ok && visited) ||
|
||||||
|
!shouldIncludeNode(p.ExeContext, selection.Directives) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
p.VisitedFragmentNames[fragName] = true
|
||||||
|
fragment, hasFragment := p.ExeContext.Fragments[fragName]
|
||||||
|
if !hasFragment {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if fragment, ok := fragment.(*ast.FragmentDefinition); ok {
|
||||||
|
if !doesFragmentConditionMatch(p.ExeContext, fragment, p.RuntimeType) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
innerParams := collectFieldsParams{
|
||||||
|
ExeContext: p.ExeContext,
|
||||||
|
RuntimeType: p.RuntimeType,
|
||||||
|
SelectionSet: fragment.GetSelectionSet(),
|
||||||
|
Fields: fields,
|
||||||
|
VisitedFragmentNames: p.VisitedFragmentNames,
|
||||||
|
}
|
||||||
|
collectFields(innerParams)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determines if a field should be included based on the @include and @skip
|
||||||
|
// directives, where @skip has higher precedence than @include.
|
||||||
|
func shouldIncludeNode(eCtx *executionContext, directives []*ast.Directive) bool {
|
||||||
|
|
||||||
|
defaultReturnValue := true
|
||||||
|
|
||||||
|
var skipAST *ast.Directive
|
||||||
|
var includeAST *ast.Directive
|
||||||
|
for _, directive := range directives {
|
||||||
|
if directive == nil || directive.Name == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if directive.Name.Value == SkipDirective.Name {
|
||||||
|
skipAST = directive
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if skipAST != nil {
|
||||||
|
argValues, err := getArgumentValues(
|
||||||
|
SkipDirective.Args,
|
||||||
|
skipAST.Arguments,
|
||||||
|
eCtx.VariableValues,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return defaultReturnValue
|
||||||
|
}
|
||||||
|
if skipIf, ok := argValues["if"].(bool); ok {
|
||||||
|
if skipIf == true {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, directive := range directives {
|
||||||
|
if directive == nil || directive.Name == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if directive.Name.Value == IncludeDirective.Name {
|
||||||
|
includeAST = directive
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if includeAST != nil {
|
||||||
|
argValues, err := getArgumentValues(
|
||||||
|
IncludeDirective.Args,
|
||||||
|
includeAST.Arguments,
|
||||||
|
eCtx.VariableValues,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return defaultReturnValue
|
||||||
|
}
|
||||||
|
if includeIf, ok := argValues["if"].(bool); ok {
|
||||||
|
if includeIf == false {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultReturnValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determines if a fragment is applicable to the given type.
|
||||||
|
func doesFragmentConditionMatch(eCtx *executionContext, fragment ast.Node, ttype *Object) bool {
|
||||||
|
|
||||||
|
switch fragment := fragment.(type) {
|
||||||
|
case *ast.FragmentDefinition:
|
||||||
|
typeConditionAST := fragment.TypeCondition
|
||||||
|
if typeConditionAST == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
conditionalType, err := typeFromAST(eCtx.Schema, typeConditionAST)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if conditionalType == ttype {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if conditionalType.Name() == ttype.Name() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if conditionalType, ok := conditionalType.(*Interface); ok {
|
||||||
|
return eCtx.Schema.IsPossibleType(conditionalType, ttype)
|
||||||
|
}
|
||||||
|
if conditionalType, ok := conditionalType.(*Union); ok {
|
||||||
|
return eCtx.Schema.IsPossibleType(conditionalType, ttype)
|
||||||
|
}
|
||||||
|
case *ast.InlineFragment:
|
||||||
|
typeConditionAST := fragment.TypeCondition
|
||||||
|
if typeConditionAST == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
conditionalType, err := typeFromAST(eCtx.Schema, typeConditionAST)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if conditionalType == ttype {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if conditionalType.Name() == ttype.Name() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if conditionalType, ok := conditionalType.(*Interface); ok {
|
||||||
|
return eCtx.Schema.IsPossibleType(conditionalType, ttype)
|
||||||
|
}
|
||||||
|
if conditionalType, ok := conditionalType.(*Union); ok {
|
||||||
|
return eCtx.Schema.IsPossibleType(conditionalType, ttype)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements the logic to compute the key of a given field’s entry
|
||||||
|
func getFieldEntryKey(node *ast.Field) string {
|
||||||
|
|
||||||
|
if node.Alias != nil && node.Alias.Value != "" {
|
||||||
|
return node.Alias.Value
|
||||||
|
}
|
||||||
|
if node.Name != nil && node.Name.Value != "" {
|
||||||
|
return node.Name.Value
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal resolveField state
|
||||||
|
type resolveFieldResultState struct {
|
||||||
|
hasNoFieldDefs bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolves the field on the given source object. In particular, this
|
||||||
|
// figures out the value that the field returns by calling its resolve function,
|
||||||
|
// then calls completeValue to complete promises, serialize scalars, or execute
|
||||||
|
// the sub-selection-set for objects.
|
||||||
|
func resolveField(eCtx *executionContext, parentType *Object, source interface{}, fieldASTs []*ast.Field) (result interface{}, resultState resolveFieldResultState) {
|
||||||
|
// catch panic from resolveFn
|
||||||
|
var returnType Output
|
||||||
|
defer func() (interface{}, resolveFieldResultState) {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
|
||||||
|
var err error
|
||||||
|
if r, ok := r.(string); ok {
|
||||||
|
err = NewLocatedError(
|
||||||
|
fmt.Sprintf("%v", r),
|
||||||
|
FieldASTsToNodeASTs(fieldASTs),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if r, ok := r.(error); ok {
|
||||||
|
err = gqlerrors.FormatError(r)
|
||||||
|
}
|
||||||
|
// send panic upstream
|
||||||
|
if _, ok := returnType.(*NonNull); ok {
|
||||||
|
panic(gqlerrors.FormatError(err))
|
||||||
|
}
|
||||||
|
eCtx.Errors = append(eCtx.Errors, gqlerrors.FormatError(err))
|
||||||
|
return result, resultState
|
||||||
|
}
|
||||||
|
return result, resultState
|
||||||
|
}()
|
||||||
|
|
||||||
|
fieldAST := fieldASTs[0]
|
||||||
|
fieldName := ""
|
||||||
|
if fieldAST.Name != nil {
|
||||||
|
fieldName = fieldAST.Name.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldDef := getFieldDef(eCtx.Schema, parentType, fieldName)
|
||||||
|
if fieldDef == nil {
|
||||||
|
resultState.hasNoFieldDefs = true
|
||||||
|
return nil, resultState
|
||||||
|
}
|
||||||
|
returnType = fieldDef.Type
|
||||||
|
resolveFn := fieldDef.Resolve
|
||||||
|
if resolveFn == nil {
|
||||||
|
resolveFn = DefaultResolveFn
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build a map of arguments from the field.arguments AST, using the
|
||||||
|
// variables scope to fulfill any variable references.
|
||||||
|
// TODO: find a way to memoize, in case this field is within a List type.
|
||||||
|
args, _ := getArgumentValues(fieldDef.Args, fieldAST.Arguments, eCtx.VariableValues)
|
||||||
|
|
||||||
|
info := ResolveInfo{
|
||||||
|
FieldName: fieldName,
|
||||||
|
FieldASTs: fieldASTs,
|
||||||
|
ReturnType: returnType,
|
||||||
|
ParentType: parentType,
|
||||||
|
Schema: eCtx.Schema,
|
||||||
|
Fragments: eCtx.Fragments,
|
||||||
|
RootValue: eCtx.Root,
|
||||||
|
Operation: eCtx.Operation,
|
||||||
|
VariableValues: eCtx.VariableValues,
|
||||||
|
}
|
||||||
|
|
||||||
|
var resolveFnError error
|
||||||
|
|
||||||
|
result, resolveFnError = resolveFn(ResolveParams{
|
||||||
|
Source: source,
|
||||||
|
Args: args,
|
||||||
|
Info: info,
|
||||||
|
Context: eCtx.Context,
|
||||||
|
})
|
||||||
|
|
||||||
|
if resolveFnError != nil {
|
||||||
|
panic(gqlerrors.FormatError(resolveFnError))
|
||||||
|
}
|
||||||
|
|
||||||
|
completed := completeValueCatchingError(eCtx, returnType, fieldASTs, info, result)
|
||||||
|
return completed, resultState
|
||||||
|
}
|
||||||
|
|
||||||
|
func completeValueCatchingError(eCtx *executionContext, returnType Type, fieldASTs []*ast.Field, info ResolveInfo, result interface{}) (completed interface{}) {
|
||||||
|
// catch panic
|
||||||
|
defer func() interface{} {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
//send panic upstream
|
||||||
|
if _, ok := returnType.(*NonNull); ok {
|
||||||
|
panic(r)
|
||||||
|
}
|
||||||
|
if err, ok := r.(gqlerrors.FormattedError); ok {
|
||||||
|
eCtx.Errors = append(eCtx.Errors, err)
|
||||||
|
}
|
||||||
|
return completed
|
||||||
|
}
|
||||||
|
return completed
|
||||||
|
}()
|
||||||
|
|
||||||
|
if returnType, ok := returnType.(*NonNull); ok {
|
||||||
|
completed := completeValue(eCtx, returnType, fieldASTs, info, result)
|
||||||
|
return completed
|
||||||
|
}
|
||||||
|
completed = completeValue(eCtx, returnType, fieldASTs, info, result)
|
||||||
|
return completed
|
||||||
|
}
|
||||||
|
|
||||||
|
func completeValue(eCtx *executionContext, returnType Type, fieldASTs []*ast.Field, info ResolveInfo, result interface{}) interface{} {
|
||||||
|
|
||||||
|
resultVal := reflect.ValueOf(result)
|
||||||
|
if resultVal.IsValid() && resultVal.Type().Kind() == reflect.Func {
|
||||||
|
if propertyFn, ok := result.(func() interface{}); ok {
|
||||||
|
return propertyFn()
|
||||||
|
}
|
||||||
|
err := gqlerrors.NewFormattedError("Error resolving func. Expected `func() interface{}` signature")
|
||||||
|
panic(gqlerrors.FormatError(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
// If field type is NonNull, complete for inner type, and throw field error
|
||||||
|
// if result is null.
|
||||||
|
if returnType, ok := returnType.(*NonNull); ok {
|
||||||
|
completed := completeValue(eCtx, returnType.OfType, fieldASTs, info, result)
|
||||||
|
if completed == nil {
|
||||||
|
err := NewLocatedError(
|
||||||
|
fmt.Sprintf("Cannot return null for non-nullable field %v.%v.", info.ParentType, info.FieldName),
|
||||||
|
FieldASTsToNodeASTs(fieldASTs),
|
||||||
|
)
|
||||||
|
panic(gqlerrors.FormatError(err))
|
||||||
|
}
|
||||||
|
return completed
|
||||||
|
}
|
||||||
|
|
||||||
|
// If result value is null-ish (null, undefined, or NaN) then return null.
|
||||||
|
if isNullish(result) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// If field type is List, complete each item in the list with the inner type
|
||||||
|
if returnType, ok := returnType.(*List); ok {
|
||||||
|
return completeListValue(eCtx, returnType, fieldASTs, info, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If field type is a leaf type, Scalar or Enum, serialize to a valid value,
|
||||||
|
// returning null if serialization is not possible.
|
||||||
|
if returnType, ok := returnType.(*Scalar); ok {
|
||||||
|
return completeLeafValue(returnType, result)
|
||||||
|
}
|
||||||
|
if returnType, ok := returnType.(*Enum); ok {
|
||||||
|
return completeLeafValue(returnType, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If field type is an abstract type, Interface or Union, determine the
|
||||||
|
// runtime Object type and complete for that type.
|
||||||
|
if returnType, ok := returnType.(*Union); ok {
|
||||||
|
return completeAbstractValue(eCtx, returnType, fieldASTs, info, result)
|
||||||
|
}
|
||||||
|
if returnType, ok := returnType.(*Interface); ok {
|
||||||
|
return completeAbstractValue(eCtx, returnType, fieldASTs, info, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If field type is Object, execute and complete all sub-selections.
|
||||||
|
if returnType, ok := returnType.(*Object); ok {
|
||||||
|
return completeObjectValue(eCtx, returnType, fieldASTs, info, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not reachable. All possible output types have been considered.
|
||||||
|
err := invariantf(false,
|
||||||
|
`Cannot complete value of unexpected type "%v."`, returnType)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(gqlerrors.FormatError(err))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// completeAbstractValue completes value of an Abstract type (Union / Interface) by determining the runtime type
|
||||||
|
// of that value, then completing based on that type.
|
||||||
|
func completeAbstractValue(eCtx *executionContext, returnType Abstract, fieldASTs []*ast.Field, info ResolveInfo, result interface{}) interface{} {
|
||||||
|
|
||||||
|
var runtimeType *Object
|
||||||
|
|
||||||
|
resolveTypeParams := ResolveTypeParams{
|
||||||
|
Value: result,
|
||||||
|
Info: info,
|
||||||
|
Context: eCtx.Context,
|
||||||
|
}
|
||||||
|
if unionReturnType, ok := returnType.(*Union); ok && unionReturnType.ResolveType != nil {
|
||||||
|
runtimeType = unionReturnType.ResolveType(resolveTypeParams)
|
||||||
|
} else if interfaceReturnType, ok := returnType.(*Interface); ok && interfaceReturnType.ResolveType != nil {
|
||||||
|
runtimeType = interfaceReturnType.ResolveType(resolveTypeParams)
|
||||||
|
} else {
|
||||||
|
runtimeType = defaultResolveTypeFn(resolveTypeParams, returnType)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := invariant(runtimeType != nil,
|
||||||
|
fmt.Sprintf(`Abstract type %v must resolve to an Object type at runtime `+
|
||||||
|
`for field %v.%v with value "%v", received "%v".`,
|
||||||
|
returnType, info.ParentType, info.FieldName, result, runtimeType),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !eCtx.Schema.IsPossibleType(returnType, runtimeType) {
|
||||||
|
panic(gqlerrors.NewFormattedError(
|
||||||
|
fmt.Sprintf(`Runtime Object type "%v" is not a possible type `+
|
||||||
|
`for "%v".`, runtimeType, returnType),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
return completeObjectValue(eCtx, runtimeType, fieldASTs, info, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
// completeObjectValue complete an Object value by executing all sub-selections.
|
||||||
|
func completeObjectValue(eCtx *executionContext, returnType *Object, fieldASTs []*ast.Field, info ResolveInfo, result interface{}) interface{} {
|
||||||
|
|
||||||
|
// If there is an isTypeOf predicate function, call it with the
|
||||||
|
// current result. If isTypeOf returns false, then raise an error rather
|
||||||
|
// than continuing execution.
|
||||||
|
if returnType.IsTypeOf != nil {
|
||||||
|
p := IsTypeOfParams{
|
||||||
|
Value: result,
|
||||||
|
Info: info,
|
||||||
|
Context: eCtx.Context,
|
||||||
|
}
|
||||||
|
if !returnType.IsTypeOf(p) {
|
||||||
|
panic(gqlerrors.NewFormattedError(
|
||||||
|
fmt.Sprintf(`Expected value of type "%v" but got: %T.`, returnType, result),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect sub-fields to execute to complete this value.
|
||||||
|
subFieldASTs := map[string][]*ast.Field{}
|
||||||
|
visitedFragmentNames := map[string]bool{}
|
||||||
|
for _, fieldAST := range fieldASTs {
|
||||||
|
if fieldAST == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
selectionSet := fieldAST.SelectionSet
|
||||||
|
if selectionSet != nil {
|
||||||
|
innerParams := collectFieldsParams{
|
||||||
|
ExeContext: eCtx,
|
||||||
|
RuntimeType: returnType,
|
||||||
|
SelectionSet: selectionSet,
|
||||||
|
Fields: subFieldASTs,
|
||||||
|
VisitedFragmentNames: visitedFragmentNames,
|
||||||
|
}
|
||||||
|
subFieldASTs = collectFields(innerParams)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
executeFieldsParams := executeFieldsParams{
|
||||||
|
ExecutionContext: eCtx,
|
||||||
|
ParentType: returnType,
|
||||||
|
Source: result,
|
||||||
|
Fields: subFieldASTs,
|
||||||
|
}
|
||||||
|
results := executeFields(executeFieldsParams)
|
||||||
|
|
||||||
|
return results.Data
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// completeLeafValue complete a leaf value (Scalar / Enum) by serializing to a valid value, returning nil if serialization is not possible.
|
||||||
|
func completeLeafValue(returnType Leaf, result interface{}) interface{} {
|
||||||
|
serializedResult := returnType.Serialize(result)
|
||||||
|
if isNullish(serializedResult) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return serializedResult
|
||||||
|
}
|
||||||
|
|
||||||
|
// completeListValue complete a list value by completing each item in the list with the inner type
|
||||||
|
func completeListValue(eCtx *executionContext, returnType *List, fieldASTs []*ast.Field, info ResolveInfo, result interface{}) interface{} {
|
||||||
|
resultVal := reflect.ValueOf(result)
|
||||||
|
parentTypeName := ""
|
||||||
|
if info.ParentType != nil {
|
||||||
|
parentTypeName = info.ParentType.Name()
|
||||||
|
}
|
||||||
|
err := invariantf(
|
||||||
|
resultVal.IsValid() && resultVal.Type().Kind() == reflect.Slice,
|
||||||
|
"User Error: expected iterable, but did not find one "+
|
||||||
|
"for field %v.%v.", parentTypeName, info.FieldName)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(gqlerrors.FormatError(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
itemType := returnType.OfType
|
||||||
|
completedResults := []interface{}{}
|
||||||
|
for i := 0; i < resultVal.Len(); i++ {
|
||||||
|
val := resultVal.Index(i).Interface()
|
||||||
|
completedItem := completeValueCatchingError(eCtx, itemType, fieldASTs, info, val)
|
||||||
|
completedResults = append(completedResults, completedItem)
|
||||||
|
}
|
||||||
|
return completedResults
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultResolveTypeFn If a resolveType function is not given, then a default resolve behavior is
|
||||||
|
// used which tests each possible type for the abstract type by calling
|
||||||
|
// isTypeOf for the object being coerced, returning the first type that matches.
|
||||||
|
func defaultResolveTypeFn(p ResolveTypeParams, abstractType Abstract) *Object {
|
||||||
|
possibleTypes := p.Info.Schema.PossibleTypes(abstractType)
|
||||||
|
for _, possibleType := range possibleTypes {
|
||||||
|
if possibleType.IsTypeOf == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
isTypeOfParams := IsTypeOfParams{
|
||||||
|
Value: p.Value,
|
||||||
|
Info: p.Info,
|
||||||
|
Context: p.Context,
|
||||||
|
}
|
||||||
|
if res := possibleType.IsTypeOf(isTypeOfParams); res {
|
||||||
|
return possibleType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FieldResolver is used in DefaultResolveFn when the the source value implements this interface.
|
||||||
|
type FieldResolver interface {
|
||||||
|
// Resolve resolves the value for the given ResolveParams. It has the same semantics as FieldResolveFn.
|
||||||
|
Resolve(p ResolveParams) (interface{}, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultResolveFn If a resolve function is not given, then a default resolve behavior is used
|
||||||
|
// which takes the property of the source object of the same name as the field
|
||||||
|
// and returns it as the result, or if it's a function, returns the result
|
||||||
|
// of calling that function.
|
||||||
|
func DefaultResolveFn(p ResolveParams) (interface{}, error) {
|
||||||
|
// try to resolve p.Source as a struct first
|
||||||
|
sourceVal := reflect.ValueOf(p.Source)
|
||||||
|
if sourceVal.IsValid() && sourceVal.Type().Kind() == reflect.Ptr {
|
||||||
|
sourceVal = sourceVal.Elem()
|
||||||
|
}
|
||||||
|
if !sourceVal.IsValid() {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if value implements 'Resolver' interface
|
||||||
|
if resolver, ok := sourceVal.Interface().(FieldResolver); ok {
|
||||||
|
return resolver.Resolve(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sourceVal.Type().Kind() == reflect.Struct {
|
||||||
|
for i := 0; i < sourceVal.NumField(); i++ {
|
||||||
|
valueField := sourceVal.Field(i)
|
||||||
|
typeField := sourceVal.Type().Field(i)
|
||||||
|
// try matching the field name first
|
||||||
|
if typeField.Name == p.Info.FieldName {
|
||||||
|
return valueField.Interface(), nil
|
||||||
|
}
|
||||||
|
tag := typeField.Tag
|
||||||
|
checkTag := func(tagName string) bool {
|
||||||
|
t := tag.Get(tagName)
|
||||||
|
tOptions := strings.Split(t, ",")
|
||||||
|
if len(tOptions) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if tOptions[0] != p.Info.FieldName {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if checkTag("json") || checkTag("graphql") {
|
||||||
|
return valueField.Interface(), nil
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// try p.Source as a map[string]interface
|
||||||
|
if sourceMap, ok := p.Source.(map[string]interface{}); ok {
|
||||||
|
property := sourceMap[p.Info.FieldName]
|
||||||
|
val := reflect.ValueOf(property)
|
||||||
|
if val.IsValid() && val.Type().Kind() == reflect.Func {
|
||||||
|
// try type casting the func to the most basic func signature
|
||||||
|
// for more complex signatures, user have to define ResolveFn
|
||||||
|
if propertyFn, ok := property.(func() interface{}); ok {
|
||||||
|
return propertyFn(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return property, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// last resort, return nil
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method looks up the field on the given type definition.
|
||||||
|
// It has special casing for the two introspection fields, __schema
|
||||||
|
// and __typename. __typename is special because it can always be
|
||||||
|
// queried as a field, even in situations where no other fields
|
||||||
|
// are allowed, like on a Union. __schema could get automatically
|
||||||
|
// added to the query type, but that would require mutating type
|
||||||
|
// definitions, which would cause issues.
|
||||||
|
func getFieldDef(schema Schema, parentType *Object, fieldName string) *FieldDefinition {
|
||||||
|
|
||||||
|
if parentType == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if fieldName == SchemaMetaFieldDef.Name &&
|
||||||
|
schema.QueryType() == parentType {
|
||||||
|
return SchemaMetaFieldDef
|
||||||
|
}
|
||||||
|
if fieldName == TypeMetaFieldDef.Name &&
|
||||||
|
schema.QueryType() == parentType {
|
||||||
|
return TypeMetaFieldDef
|
||||||
|
}
|
||||||
|
if fieldName == TypeNameMetaFieldDef.Name {
|
||||||
|
return TypeNameMetaFieldDef
|
||||||
|
}
|
||||||
|
return parentType.Fields()[fieldName]
|
||||||
|
}
|
68
vendor/github.com/graphql-go/graphql/gqlerrors/error.go
generated
vendored
Normal file
68
vendor/github.com/graphql-go/graphql/gqlerrors/error.go
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
package gqlerrors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/graphql-go/graphql/language/ast"
|
||||||
|
"github.com/graphql-go/graphql/language/location"
|
||||||
|
"github.com/graphql-go/graphql/language/source"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Error struct {
|
||||||
|
Message string
|
||||||
|
Stack string
|
||||||
|
Nodes []ast.Node
|
||||||
|
Source *source.Source
|
||||||
|
Positions []int
|
||||||
|
Locations []location.SourceLocation
|
||||||
|
OriginalError error
|
||||||
|
}
|
||||||
|
|
||||||
|
// implements Golang's built-in `error` interface
|
||||||
|
func (g Error) Error() string {
|
||||||
|
return fmt.Sprintf("%v", g.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewError(message string, nodes []ast.Node, stack string, source *source.Source, positions []int, origError error) *Error {
|
||||||
|
if stack == "" && message != "" {
|
||||||
|
stack = message
|
||||||
|
}
|
||||||
|
if source == nil {
|
||||||
|
for _, node := range nodes {
|
||||||
|
// get source from first node
|
||||||
|
if node == nil || reflect.ValueOf(node).IsNil() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if node.GetLoc() != nil {
|
||||||
|
source = node.GetLoc().Source
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(positions) == 0 && len(nodes) > 0 {
|
||||||
|
for _, node := range nodes {
|
||||||
|
if node == nil || reflect.ValueOf(node).IsNil() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if node.GetLoc() == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
positions = append(positions, node.GetLoc().Start)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
locations := []location.SourceLocation{}
|
||||||
|
for _, pos := range positions {
|
||||||
|
loc := location.GetLocation(source, pos)
|
||||||
|
locations = append(locations, loc)
|
||||||
|
}
|
||||||
|
return &Error{
|
||||||
|
Message: message,
|
||||||
|
Stack: stack,
|
||||||
|
Nodes: nodes,
|
||||||
|
Source: source,
|
||||||
|
Positions: positions,
|
||||||
|
Locations: locations,
|
||||||
|
OriginalError: origError,
|
||||||
|
}
|
||||||
|
}
|
51
vendor/github.com/graphql-go/graphql/gqlerrors/formatted.go
generated
vendored
Normal file
51
vendor/github.com/graphql-go/graphql/gqlerrors/formatted.go
generated
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package gqlerrors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/graphql-go/graphql/language/location"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FormattedError struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
Locations []location.SourceLocation `json:"locations"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g FormattedError) Error() string {
|
||||||
|
return g.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFormattedError(message string) FormattedError {
|
||||||
|
err := errors.New(message)
|
||||||
|
return FormatError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FormatError(err error) FormattedError {
|
||||||
|
switch err := err.(type) {
|
||||||
|
case FormattedError:
|
||||||
|
return err
|
||||||
|
case *Error:
|
||||||
|
return FormattedError{
|
||||||
|
Message: err.Error(),
|
||||||
|
Locations: err.Locations,
|
||||||
|
}
|
||||||
|
case Error:
|
||||||
|
return FormattedError{
|
||||||
|
Message: err.Error(),
|
||||||
|
Locations: err.Locations,
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return FormattedError{
|
||||||
|
Message: err.Error(),
|
||||||
|
Locations: []location.SourceLocation{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func FormatErrors(errs ...error) []FormattedError {
|
||||||
|
formattedErrors := []FormattedError{}
|
||||||
|
for _, err := range errs {
|
||||||
|
formattedErrors = append(formattedErrors, FormatError(err))
|
||||||
|
}
|
||||||
|
return formattedErrors
|
||||||
|
}
|
39
vendor/github.com/graphql-go/graphql/gqlerrors/located.go
generated
vendored
Normal file
39
vendor/github.com/graphql-go/graphql/gqlerrors/located.go
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package gqlerrors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/graphql-go/graphql/language/ast"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewLocatedError creates a graphql.Error with location info
|
||||||
|
// @deprecated 0.4.18
|
||||||
|
// Already exists in `graphql.NewLocatedError()`
|
||||||
|
func NewLocatedError(err interface{}, nodes []ast.Node) *Error {
|
||||||
|
var origError error
|
||||||
|
message := "An unknown error occurred."
|
||||||
|
if err, ok := err.(error); ok {
|
||||||
|
message = err.Error()
|
||||||
|
origError = err
|
||||||
|
}
|
||||||
|
if err, ok := err.(string); ok {
|
||||||
|
message = err
|
||||||
|
origError = errors.New(err)
|
||||||
|
}
|
||||||
|
stack := message
|
||||||
|
return NewError(
|
||||||
|
message,
|
||||||
|
nodes,
|
||||||
|
stack,
|
||||||
|
nil,
|
||||||
|
[]int{},
|
||||||
|
origError,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FieldASTsToNodeASTs(fieldASTs []*ast.Field) []ast.Node {
|
||||||
|
nodes := []ast.Node{}
|
||||||
|
for _, fieldAST := range fieldASTs {
|
||||||
|
nodes = append(nodes, fieldAST)
|
||||||
|
}
|
||||||
|
return nodes
|
||||||
|
}
|
30
vendor/github.com/graphql-go/graphql/gqlerrors/sortutil.go
generated
vendored
Normal file
30
vendor/github.com/graphql-go/graphql/gqlerrors/sortutil.go
generated
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package gqlerrors
|
||||||
|
|
||||||
|
import "bytes"
|
||||||
|
|
||||||
|
type FormattedErrors []FormattedError
|
||||||
|
|
||||||
|
func (errs FormattedErrors) Len() int {
|
||||||
|
return len(errs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (errs FormattedErrors) Swap(i, j int) {
|
||||||
|
errs[i], errs[j] = errs[j], errs[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (errs FormattedErrors) Less(i, j int) bool {
|
||||||
|
mCompare := bytes.Compare([]byte(errs[i].Message), []byte(errs[j].Message))
|
||||||
|
lesserLine := errs[i].Locations[0].Line < errs[j].Locations[0].Line
|
||||||
|
eqLine := errs[i].Locations[0].Line == errs[j].Locations[0].Line
|
||||||
|
lesserColumn := errs[i].Locations[0].Column < errs[j].Locations[0].Column
|
||||||
|
if mCompare < 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if mCompare == 0 && lesserLine {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if mCompare == 0 && eqLine && lesserColumn {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
69
vendor/github.com/graphql-go/graphql/gqlerrors/syntax.go
generated
vendored
Normal file
69
vendor/github.com/graphql-go/graphql/gqlerrors/syntax.go
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package gqlerrors
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/graphql-go/graphql/language/ast"
|
||||||
|
"github.com/graphql-go/graphql/language/location"
|
||||||
|
"github.com/graphql-go/graphql/language/source"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewSyntaxError(s *source.Source, position int, description string) *Error {
|
||||||
|
l := location.GetLocation(s, position)
|
||||||
|
return NewError(
|
||||||
|
fmt.Sprintf("Syntax Error %s (%d:%d) %s\n\n%s", s.Name, l.Line, l.Column, description, highlightSourceAtLocation(s, l)),
|
||||||
|
[]ast.Node{},
|
||||||
|
"",
|
||||||
|
s,
|
||||||
|
[]int{position},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// printCharCode here is slightly different from lexer.printCharCode()
|
||||||
|
func printCharCode(code rune) string {
|
||||||
|
// print as ASCII for printable range
|
||||||
|
if code >= 0x0020 {
|
||||||
|
return fmt.Sprintf(`%c`, code)
|
||||||
|
}
|
||||||
|
// Otherwise print the escaped form. e.g. `"\\u0007"`
|
||||||
|
return fmt.Sprintf(`\u%04X`, code)
|
||||||
|
}
|
||||||
|
func printLine(str string) string {
|
||||||
|
strSlice := []string{}
|
||||||
|
for _, runeValue := range str {
|
||||||
|
strSlice = append(strSlice, printCharCode(runeValue))
|
||||||
|
}
|
||||||
|
return fmt.Sprintf(`%s`, strings.Join(strSlice, ""))
|
||||||
|
}
|
||||||
|
func highlightSourceAtLocation(s *source.Source, l location.SourceLocation) string {
|
||||||
|
line := l.Line
|
||||||
|
prevLineNum := fmt.Sprintf("%d", (line - 1))
|
||||||
|
lineNum := fmt.Sprintf("%d", line)
|
||||||
|
nextLineNum := fmt.Sprintf("%d", (line + 1))
|
||||||
|
padLen := len(nextLineNum)
|
||||||
|
lines := regexp.MustCompile("\r\n|[\n\r]").Split(string(s.Body), -1)
|
||||||
|
var highlight string
|
||||||
|
if line >= 2 {
|
||||||
|
highlight += fmt.Sprintf("%s: %s\n", lpad(padLen, prevLineNum), printLine(lines[line-2]))
|
||||||
|
}
|
||||||
|
highlight += fmt.Sprintf("%s: %s\n", lpad(padLen, lineNum), printLine(lines[line-1]))
|
||||||
|
for i := 1; i < (2 + padLen + l.Column); i++ {
|
||||||
|
highlight += " "
|
||||||
|
}
|
||||||
|
highlight += "^\n"
|
||||||
|
if line < len(lines) {
|
||||||
|
highlight += fmt.Sprintf("%s: %s\n", lpad(padLen, nextLineNum), printLine(lines[line]))
|
||||||
|
}
|
||||||
|
return highlight
|
||||||
|
}
|
||||||
|
|
||||||
|
func lpad(l int, s string) string {
|
||||||
|
var r string
|
||||||
|
for i := 1; i < (l - len(s) + 1); i++ {
|
||||||
|
r += " "
|
||||||
|
}
|
||||||
|
return r + s
|
||||||
|
}
|
63
vendor/github.com/graphql-go/graphql/graphql.go
generated
vendored
Normal file
63
vendor/github.com/graphql-go/graphql/graphql.go
generated
vendored
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package graphql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/graphql-go/graphql/gqlerrors"
|
||||||
|
"github.com/graphql-go/graphql/language/parser"
|
||||||
|
"github.com/graphql-go/graphql/language/source"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Params struct {
|
||||||
|
// The GraphQL type system to use when validating and executing a query.
|
||||||
|
Schema Schema
|
||||||
|
|
||||||
|
// A GraphQL language formatted string representing the requested operation.
|
||||||
|
RequestString string
|
||||||
|
|
||||||
|
// The value provided as the first argument to resolver functions on the top
|
||||||
|
// level type (e.g. the query object type).
|
||||||
|
RootObject map[string]interface{}
|
||||||
|
|
||||||
|
// A mapping of variable name to runtime value to use for all variables
|
||||||
|
// defined in the requestString.
|
||||||
|
VariableValues map[string]interface{}
|
||||||
|
|
||||||
|
// The name of the operation to use if requestString contains multiple
|
||||||
|
// possible operations. Can be omitted if requestString contains only
|
||||||
|
// one operation.
|
||||||
|
OperationName string
|
||||||
|
|
||||||
|
// Context may be provided to pass application-specific per-request
|
||||||
|
// information to resolve functions.
|
||||||
|
Context context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func Do(p Params) *Result {
|
||||||
|
source := source.NewSource(&source.Source{
|
||||||
|
Body: []byte(p.RequestString),
|
||||||
|
Name: "GraphQL request",
|
||||||
|
})
|
||||||
|
AST, err := parser.Parse(parser.ParseParams{Source: source})
|
||||||
|
if err != nil {
|
||||||
|
return &Result{
|
||||||
|
Errors: gqlerrors.FormatErrors(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
validationResult := ValidateDocument(&p.Schema, AST, nil)
|
||||||
|
|
||||||
|
if !validationResult.IsValid {
|
||||||
|
return &Result{
|
||||||
|
Errors: validationResult.Errors,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Execute(ExecuteParams{
|
||||||
|
Schema: p.Schema,
|
||||||
|
Root: p.RootObject,
|
||||||
|
AST: AST,
|
||||||
|
OperationName: p.OperationName,
|
||||||
|
Args: p.VariableValues,
|
||||||
|
Context: p.Context,
|
||||||
|
})
|
||||||
|
}
|
763
vendor/github.com/graphql-go/graphql/introspection.go
generated
vendored
Normal file
763
vendor/github.com/graphql-go/graphql/introspection.go
generated
vendored
Normal file
@ -0,0 +1,763 @@
|
|||||||
|
package graphql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/graphql-go/graphql/language/ast"
|
||||||
|
"github.com/graphql-go/graphql/language/printer"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
TypeKindScalar = "SCALAR"
|
||||||
|
TypeKindObject = "OBJECT"
|
||||||
|
TypeKindInterface = "INTERFACE"
|
||||||
|
TypeKindUnion = "UNION"
|
||||||
|
TypeKindEnum = "ENUM"
|
||||||
|
TypeKindInputObject = "INPUT_OBJECT"
|
||||||
|
TypeKindList = "LIST"
|
||||||
|
TypeKindNonNull = "NON_NULL"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SchemaType is type definition for __Schema
|
||||||
|
var SchemaType *Object
|
||||||
|
|
||||||
|
// DirectiveType is type definition for __Directive
|
||||||
|
var DirectiveType *Object
|
||||||
|
|
||||||
|
// TypeType is type definition for __Type
|
||||||
|
var TypeType *Object
|
||||||
|
|
||||||
|
// FieldType is type definition for __Field
|
||||||
|
var FieldType *Object
|
||||||
|
|
||||||
|
// InputValueType is type definition for __InputValue
|
||||||
|
var InputValueType *Object
|
||||||
|
|
||||||
|
// EnumValueType is type definition for __EnumValue
|
||||||
|
var EnumValueType *Object
|
||||||
|
|
||||||
|
// TypeKindEnumType is type definition for __TypeKind
|
||||||
|
var TypeKindEnumType *Enum
|
||||||
|
|
||||||
|
// DirectiveLocationEnumType is type definition for __DirectiveLocation
|
||||||
|
var DirectiveLocationEnumType *Enum
|
||||||
|
|
||||||
|
// Meta-field definitions.
|
||||||
|
|
||||||
|
// SchemaMetaFieldDef Meta field definition for Schema
|
||||||
|
var SchemaMetaFieldDef *FieldDefinition
|
||||||
|
|
||||||
|
// TypeMetaFieldDef Meta field definition for types
|
||||||
|
var TypeMetaFieldDef *FieldDefinition
|
||||||
|
|
||||||
|
// TypeNameMetaFieldDef Meta field definition for type names
|
||||||
|
var TypeNameMetaFieldDef *FieldDefinition
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
|
||||||
|
TypeKindEnumType = NewEnum(EnumConfig{
|
||||||
|
Name: "__TypeKind",
|
||||||
|
Description: "An enum describing what kind of type a given `__Type` is",
|
||||||
|
Values: EnumValueConfigMap{
|
||||||
|
"SCALAR": &EnumValueConfig{
|
||||||
|
Value: TypeKindScalar,
|
||||||
|
Description: "Indicates this type is a scalar.",
|
||||||
|
},
|
||||||
|
"OBJECT": &EnumValueConfig{
|
||||||
|
Value: TypeKindObject,
|
||||||
|
Description: "Indicates this type is an object. " +
|
||||||
|
"`fields` and `interfaces` are valid fields.",
|
||||||
|
},
|
||||||
|
"INTERFACE": &EnumValueConfig{
|
||||||
|
Value: TypeKindInterface,
|
||||||
|
Description: "Indicates this type is an interface. " +
|
||||||
|
"`fields` and `possibleTypes` are valid fields.",
|
||||||
|
},
|
||||||
|
"UNION": &EnumValueConfig{
|
||||||
|
Value: TypeKindUnion,
|
||||||
|
Description: "Indicates this type is a union. " +
|
||||||
|
"`possibleTypes` is a valid field.",
|
||||||
|
},
|
||||||
|
"ENUM": &EnumValueConfig{
|
||||||
|
Value: TypeKindEnum,
|
||||||
|
Description: "Indicates this type is an enum. " +
|
||||||
|
"`enumValues` is a valid field.",
|
||||||
|
},
|
||||||
|
"INPUT_OBJECT": &EnumValueConfig{
|
||||||
|
Value: TypeKindInputObject,
|
||||||
|
Description: "Indicates this type is an input object. " +
|
||||||
|
"`inputFields` is a valid field.",
|
||||||
|
},
|
||||||
|
"LIST": &EnumValueConfig{
|
||||||
|
Value: TypeKindList,
|
||||||
|
Description: "Indicates this type is a list. " +
|
||||||
|
"`ofType` is a valid field.",
|
||||||
|
},
|
||||||
|
"NON_NULL": &EnumValueConfig{
|
||||||
|
Value: TypeKindNonNull,
|
||||||
|
Description: "Indicates this type is a non-null. " +
|
||||||
|
"`ofType` is a valid field.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
DirectiveLocationEnumType = NewEnum(EnumConfig{
|
||||||
|
Name: "__DirectiveLocation",
|
||||||
|
Description: "A Directive can be adjacent to many parts of the GraphQL language, a " +
|
||||||
|
"__DirectiveLocation describes one such possible adjacencies.",
|
||||||
|
Values: EnumValueConfigMap{
|
||||||
|
"QUERY": &EnumValueConfig{
|
||||||
|
Value: DirectiveLocationQuery,
|
||||||
|
Description: "Location adjacent to a query operation.",
|
||||||
|
},
|
||||||
|
"MUTATION": &EnumValueConfig{
|
||||||
|
Value: DirectiveLocationMutation,
|
||||||
|
Description: "Location adjacent to a mutation operation.",
|
||||||
|
},
|
||||||
|
"SUBSCRIPTION": &EnumValueConfig{
|
||||||
|
Value: DirectiveLocationSubscription,
|
||||||
|
Description: "Location adjacent to a subscription operation.",
|
||||||
|
},
|
||||||
|
"FIELD": &EnumValueConfig{
|
||||||
|
Value: DirectiveLocationField,
|
||||||
|
Description: "Location adjacent to a field.",
|
||||||
|
},
|
||||||
|
"FRAGMENT_DEFINITION": &EnumValueConfig{
|
||||||
|
Value: DirectiveLocationFragmentDefinition,
|
||||||
|
Description: "Location adjacent to a fragment definition.",
|
||||||
|
},
|
||||||
|
"FRAGMENT_SPREAD": &EnumValueConfig{
|
||||||
|
Value: DirectiveLocationFragmentSpread,
|
||||||
|
Description: "Location adjacent to a fragment spread.",
|
||||||
|
},
|
||||||
|
"INLINE_FRAGMENT": &EnumValueConfig{
|
||||||
|
Value: DirectiveLocationInlineFragment,
|
||||||
|
Description: "Location adjacent to an inline fragment.",
|
||||||
|
},
|
||||||
|
"SCHEMA": &EnumValueConfig{
|
||||||
|
Value: DirectiveLocationSchema,
|
||||||
|
Description: "Location adjacent to a schema definition.",
|
||||||
|
},
|
||||||
|
"SCALAR": &EnumValueConfig{
|
||||||
|
Value: DirectiveLocationScalar,
|
||||||
|
Description: "Location adjacent to a scalar definition.",
|
||||||
|
},
|
||||||
|
"OBJECT": &EnumValueConfig{
|
||||||
|
Value: DirectiveLocationObject,
|
||||||
|
Description: "Location adjacent to a object definition.",
|
||||||
|
},
|
||||||
|
"FIELD_DEFINITION": &EnumValueConfig{
|
||||||
|
Value: DirectiveLocationFieldDefinition,
|
||||||
|
Description: "Location adjacent to a field definition.",
|
||||||
|
},
|
||||||
|
"ARGUMENT_DEFINITION": &EnumValueConfig{
|
||||||
|
Value: DirectiveLocationArgumentDefinition,
|
||||||
|
Description: "Location adjacent to an argument definition.",
|
||||||
|
},
|
||||||
|
"INTERFACE": &EnumValueConfig{
|
||||||
|
Value: DirectiveLocationInterface,
|
||||||
|
Description: "Location adjacent to an interface definition.",
|
||||||
|
},
|
||||||
|
"UNION": &EnumValueConfig{
|
||||||
|
Value: DirectiveLocationUnion,
|
||||||
|
Description: "Location adjacent to a union definition.",
|
||||||
|
},
|
||||||
|
"ENUM": &EnumValueConfig{
|
||||||
|
Value: DirectiveLocationEnum,
|
||||||
|
Description: "Location adjacent to an enum definition.",
|
||||||
|
},
|
||||||
|
"ENUM_VALUE": &EnumValueConfig{
|
||||||
|
Value: DirectiveLocationEnumValue,
|
||||||
|
Description: "Location adjacent to an enum value definition.",
|
||||||
|
},
|
||||||
|
"INPUT_OBJECT": &EnumValueConfig{
|
||||||
|
Value: DirectiveLocationInputObject,
|
||||||
|
Description: "Location adjacent to an input object type definition.",
|
||||||
|
},
|
||||||
|
"INPUT_FIELD_DEFINITION": &EnumValueConfig{
|
||||||
|
Value: DirectiveLocationInputFieldDefinition,
|
||||||
|
Description: "Location adjacent to an input object field definition.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Note: some fields (for e.g "fields", "interfaces") are defined later due to cyclic reference
|
||||||
|
TypeType = NewObject(ObjectConfig{
|
||||||
|
Name: "__Type",
|
||||||
|
Description: "The fundamental unit of any GraphQL Schema is the type. There are " +
|
||||||
|
"many kinds of types in GraphQL as represented by the `__TypeKind` enum." +
|
||||||
|
"\n\nDepending on the kind of a type, certain fields describe " +
|
||||||
|
"information about that type. Scalar types provide no information " +
|
||||||
|
"beyond a name and description, while Enum types provide their values. " +
|
||||||
|
"Object and Interface types provide the fields they describe. Abstract " +
|
||||||
|
"types, Union and Interface, provide the Object types possible " +
|
||||||
|
"at runtime. List and NonNull types compose other types.",
|
||||||
|
|
||||||
|
Fields: Fields{
|
||||||
|
"kind": &Field{
|
||||||
|
Type: NewNonNull(TypeKindEnumType),
|
||||||
|
Resolve: func(p ResolveParams) (interface{}, error) {
|
||||||
|
switch p.Source.(type) {
|
||||||
|
case *Scalar:
|
||||||
|
return TypeKindScalar, nil
|
||||||
|
case *Object:
|
||||||
|
return TypeKindObject, nil
|
||||||
|
case *Interface:
|
||||||
|
return TypeKindInterface, nil
|
||||||
|
case *Union:
|
||||||
|
return TypeKindUnion, nil
|
||||||
|
case *Enum:
|
||||||
|
return TypeKindEnum, nil
|
||||||
|
case *InputObject:
|
||||||
|
return TypeKindInputObject, nil
|
||||||
|
case *List:
|
||||||
|
return TypeKindList, nil
|
||||||
|
case *NonNull:
|
||||||
|
return TypeKindNonNull, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("Unknown kind of type: %v", p.Source)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"name": &Field{
|
||||||
|
Type: String,
|
||||||
|
},
|
||||||
|
"description": &Field{
|
||||||
|
Type: String,
|
||||||
|
},
|
||||||
|
"fields": &Field{},
|
||||||
|
"interfaces": &Field{},
|
||||||
|
"possibleTypes": &Field{},
|
||||||
|
"enumValues": &Field{},
|
||||||
|
"inputFields": &Field{},
|
||||||
|
"ofType": &Field{},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
InputValueType = NewObject(ObjectConfig{
|
||||||
|
Name: "__InputValue",
|
||||||
|
Description: "Arguments provided to Fields or Directives and the input fields of an " +
|
||||||
|
"InputObject are represented as Input Values which describe their type " +
|
||||||
|
"and optionally a default value.",
|
||||||
|
Fields: Fields{
|
||||||
|
"name": &Field{
|
||||||
|
Type: NewNonNull(String),
|
||||||
|
},
|
||||||
|
"description": &Field{
|
||||||
|
Type: String,
|
||||||
|
},
|
||||||
|
"type": &Field{
|
||||||
|
Type: NewNonNull(TypeType),
|
||||||
|
},
|
||||||
|
"defaultValue": &Field{
|
||||||
|
Type: String,
|
||||||
|
Description: "A GraphQL-formatted string representing the default value for this " +
|
||||||
|
"input value.",
|
||||||
|
Resolve: func(p ResolveParams) (interface{}, error) {
|
||||||
|
if inputVal, ok := p.Source.(*Argument); ok {
|
||||||
|
if inputVal.DefaultValue == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
if isNullish(inputVal.DefaultValue) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
astVal := astFromValue(inputVal.DefaultValue, inputVal)
|
||||||
|
return printer.Print(astVal), nil
|
||||||
|
}
|
||||||
|
if inputVal, ok := p.Source.(*InputObjectField); ok {
|
||||||
|
if inputVal.DefaultValue == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
astVal := astFromValue(inputVal.DefaultValue, inputVal)
|
||||||
|
return printer.Print(astVal), nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
FieldType = NewObject(ObjectConfig{
|
||||||
|
Name: "__Field",
|
||||||
|
Description: "Object and Interface types are described by a list of Fields, each of " +
|
||||||
|
"which has a name, potentially a list of arguments, and a return type.",
|
||||||
|
Fields: Fields{
|
||||||
|
"name": &Field{
|
||||||
|
Type: NewNonNull(String),
|
||||||
|
},
|
||||||
|
"description": &Field{
|
||||||
|
Type: String,
|
||||||
|
},
|
||||||
|
"args": &Field{
|
||||||
|
Type: NewNonNull(NewList(NewNonNull(InputValueType))),
|
||||||
|
Resolve: func(p ResolveParams) (interface{}, error) {
|
||||||
|
if field, ok := p.Source.(*FieldDefinition); ok {
|
||||||
|
return field.Args, nil
|
||||||
|
}
|
||||||
|
return []interface{}{}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"type": &Field{
|
||||||
|
Type: NewNonNull(TypeType),
|
||||||
|
},
|
||||||
|
"isDeprecated": &Field{
|
||||||
|
Type: NewNonNull(Boolean),
|
||||||
|
Resolve: func(p ResolveParams) (interface{}, error) {
|
||||||
|
if field, ok := p.Source.(*FieldDefinition); ok {
|
||||||
|
return (field.DeprecationReason != ""), nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"deprecationReason": &Field{
|
||||||
|
Type: String,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
DirectiveType = NewObject(ObjectConfig{
|
||||||
|
Name: "__Directive",
|
||||||
|
Description: "A Directive provides a way to describe alternate runtime execution and " +
|
||||||
|
"type validation behavior in a GraphQL document. " +
|
||||||
|
"\n\nIn some cases, you need to provide options to alter GraphQL's " +
|
||||||
|
"execution behavior in ways field arguments will not suffice, such as " +
|
||||||
|
"conditionally including or skipping a field. Directives provide this by " +
|
||||||
|
"describing additional information to the executor.",
|
||||||
|
Fields: Fields{
|
||||||
|
"name": &Field{
|
||||||
|
Type: NewNonNull(String),
|
||||||
|
},
|
||||||
|
"description": &Field{
|
||||||
|
Type: String,
|
||||||
|
},
|
||||||
|
"locations": &Field{
|
||||||
|
Type: NewNonNull(NewList(
|
||||||
|
NewNonNull(DirectiveLocationEnumType),
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
"args": &Field{
|
||||||
|
Type: NewNonNull(NewList(
|
||||||
|
NewNonNull(InputValueType),
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
// NOTE: the following three fields are deprecated and are no longer part
|
||||||
|
// of the GraphQL specification.
|
||||||
|
"onOperation": &Field{
|
||||||
|
DeprecationReason: "Use `locations`.",
|
||||||
|
Type: NewNonNull(Boolean),
|
||||||
|
Resolve: func(p ResolveParams) (interface{}, error) {
|
||||||
|
if dir, ok := p.Source.(*Directive); ok {
|
||||||
|
res := false
|
||||||
|
for _, loc := range dir.Locations {
|
||||||
|
if loc == DirectiveLocationQuery ||
|
||||||
|
loc == DirectiveLocationMutation ||
|
||||||
|
loc == DirectiveLocationSubscription {
|
||||||
|
res = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"onFragment": &Field{
|
||||||
|
DeprecationReason: "Use `locations`.",
|
||||||
|
Type: NewNonNull(Boolean),
|
||||||
|
Resolve: func(p ResolveParams) (interface{}, error) {
|
||||||
|
if dir, ok := p.Source.(*Directive); ok {
|
||||||
|
res := false
|
||||||
|
for _, loc := range dir.Locations {
|
||||||
|
if loc == DirectiveLocationFragmentSpread ||
|
||||||
|
loc == DirectiveLocationInlineFragment ||
|
||||||
|
loc == DirectiveLocationFragmentDefinition {
|
||||||
|
res = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"onField": &Field{
|
||||||
|
DeprecationReason: "Use `locations`.",
|
||||||
|
Type: NewNonNull(Boolean),
|
||||||
|
Resolve: func(p ResolveParams) (interface{}, error) {
|
||||||
|
if dir, ok := p.Source.(*Directive); ok {
|
||||||
|
res := false
|
||||||
|
for _, loc := range dir.Locations {
|
||||||
|
if loc == DirectiveLocationField {
|
||||||
|
res = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
SchemaType = NewObject(ObjectConfig{
|
||||||
|
Name: "__Schema",
|
||||||
|
Description: `A GraphQL Schema defines the capabilities of a GraphQL server. ` +
|
||||||
|
`It exposes all available types and directives on the server, as well as ` +
|
||||||
|
`the entry points for query, mutation, and subscription operations.`,
|
||||||
|
Fields: Fields{
|
||||||
|
"types": &Field{
|
||||||
|
Description: "A list of all types supported by this server.",
|
||||||
|
Type: NewNonNull(NewList(
|
||||||
|
NewNonNull(TypeType),
|
||||||
|
)),
|
||||||
|
Resolve: func(p ResolveParams) (interface{}, error) {
|
||||||
|
if schema, ok := p.Source.(Schema); ok {
|
||||||
|
results := []Type{}
|
||||||
|
for _, ttype := range schema.TypeMap() {
|
||||||
|
results = append(results, ttype)
|
||||||
|
}
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
return []Type{}, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"queryType": &Field{
|
||||||
|
Description: "The type that query operations will be rooted at.",
|
||||||
|
Type: NewNonNull(TypeType),
|
||||||
|
Resolve: func(p ResolveParams) (interface{}, error) {
|
||||||
|
if schema, ok := p.Source.(Schema); ok {
|
||||||
|
return schema.QueryType(), nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"mutationType": &Field{
|
||||||
|
Description: `If this server supports mutation, the type that ` +
|
||||||
|
`mutation operations will be rooted at.`,
|
||||||
|
Type: TypeType,
|
||||||
|
Resolve: func(p ResolveParams) (interface{}, error) {
|
||||||
|
if schema, ok := p.Source.(Schema); ok {
|
||||||
|
if schema.MutationType() != nil {
|
||||||
|
return schema.MutationType(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"subscriptionType": &Field{
|
||||||
|
Description: `If this server supports subscription, the type that ` +
|
||||||
|
`subscription operations will be rooted at.`,
|
||||||
|
Type: TypeType,
|
||||||
|
Resolve: func(p ResolveParams) (interface{}, error) {
|
||||||
|
if schema, ok := p.Source.(Schema); ok {
|
||||||
|
if schema.SubscriptionType() != nil {
|
||||||
|
return schema.SubscriptionType(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"directives": &Field{
|
||||||
|
Description: `A list of all directives supported by this server.`,
|
||||||
|
Type: NewNonNull(NewList(
|
||||||
|
NewNonNull(DirectiveType),
|
||||||
|
)),
|
||||||
|
Resolve: func(p ResolveParams) (interface{}, error) {
|
||||||
|
if schema, ok := p.Source.(Schema); ok {
|
||||||
|
return schema.Directives(), nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
EnumValueType = NewObject(ObjectConfig{
|
||||||
|
Name: "__EnumValue",
|
||||||
|
Description: "One possible value for a given Enum. Enum values are unique values, not " +
|
||||||
|
"a placeholder for a string or numeric value. However an Enum value is " +
|
||||||
|
"returned in a JSON response as a string.",
|
||||||
|
Fields: Fields{
|
||||||
|
"name": &Field{
|
||||||
|
Type: NewNonNull(String),
|
||||||
|
},
|
||||||
|
"description": &Field{
|
||||||
|
Type: String,
|
||||||
|
},
|
||||||
|
"isDeprecated": &Field{
|
||||||
|
Type: NewNonNull(Boolean),
|
||||||
|
Resolve: func(p ResolveParams) (interface{}, error) {
|
||||||
|
if field, ok := p.Source.(*EnumValueDefinition); ok {
|
||||||
|
return (field.DeprecationReason != ""), nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"deprecationReason": &Field{
|
||||||
|
Type: String,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Again, adding field configs to __Type that have cyclic reference here
|
||||||
|
// because golang don't like them too much during init/compile-time
|
||||||
|
TypeType.AddFieldConfig("fields", &Field{
|
||||||
|
Type: NewList(NewNonNull(FieldType)),
|
||||||
|
Args: FieldConfigArgument{
|
||||||
|
"includeDeprecated": &ArgumentConfig{
|
||||||
|
Type: Boolean,
|
||||||
|
DefaultValue: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Resolve: func(p ResolveParams) (interface{}, error) {
|
||||||
|
includeDeprecated, _ := p.Args["includeDeprecated"].(bool)
|
||||||
|
switch ttype := p.Source.(type) {
|
||||||
|
case *Object:
|
||||||
|
if ttype == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
fields := []*FieldDefinition{}
|
||||||
|
var fieldNames sort.StringSlice
|
||||||
|
for name, field := range ttype.Fields() {
|
||||||
|
if !includeDeprecated && field.DeprecationReason != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fieldNames = append(fieldNames, name)
|
||||||
|
}
|
||||||
|
sort.Sort(fieldNames)
|
||||||
|
for _, name := range fieldNames {
|
||||||
|
fields = append(fields, ttype.Fields()[name])
|
||||||
|
}
|
||||||
|
return fields, nil
|
||||||
|
case *Interface:
|
||||||
|
if ttype == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
fields := []*FieldDefinition{}
|
||||||
|
for _, field := range ttype.Fields() {
|
||||||
|
if !includeDeprecated && field.DeprecationReason != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fields = append(fields, field)
|
||||||
|
}
|
||||||
|
return fields, nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
TypeType.AddFieldConfig("interfaces", &Field{
|
||||||
|
Type: NewList(NewNonNull(TypeType)),
|
||||||
|
Resolve: func(p ResolveParams) (interface{}, error) {
|
||||||
|
switch ttype := p.Source.(type) {
|
||||||
|
case *Object:
|
||||||
|
return ttype.Interfaces(), nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
TypeType.AddFieldConfig("possibleTypes", &Field{
|
||||||
|
Type: NewList(NewNonNull(TypeType)),
|
||||||
|
Resolve: func(p ResolveParams) (interface{}, error) {
|
||||||
|
switch ttype := p.Source.(type) {
|
||||||
|
case *Interface:
|
||||||
|
return p.Info.Schema.PossibleTypes(ttype), nil
|
||||||
|
case *Union:
|
||||||
|
return p.Info.Schema.PossibleTypes(ttype), nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
TypeType.AddFieldConfig("enumValues", &Field{
|
||||||
|
Type: NewList(NewNonNull(EnumValueType)),
|
||||||
|
Args: FieldConfigArgument{
|
||||||
|
"includeDeprecated": &ArgumentConfig{
|
||||||
|
Type: Boolean,
|
||||||
|
DefaultValue: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Resolve: func(p ResolveParams) (interface{}, error) {
|
||||||
|
includeDeprecated, _ := p.Args["includeDeprecated"].(bool)
|
||||||
|
switch ttype := p.Source.(type) {
|
||||||
|
case *Enum:
|
||||||
|
if includeDeprecated {
|
||||||
|
return ttype.Values(), nil
|
||||||
|
}
|
||||||
|
values := []*EnumValueDefinition{}
|
||||||
|
for _, value := range ttype.Values() {
|
||||||
|
if value.DeprecationReason != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
values = append(values, value)
|
||||||
|
}
|
||||||
|
return values, nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
TypeType.AddFieldConfig("inputFields", &Field{
|
||||||
|
Type: NewList(NewNonNull(InputValueType)),
|
||||||
|
Resolve: func(p ResolveParams) (interface{}, error) {
|
||||||
|
switch ttype := p.Source.(type) {
|
||||||
|
case *InputObject:
|
||||||
|
fields := []*InputObjectField{}
|
||||||
|
for _, field := range ttype.Fields() {
|
||||||
|
fields = append(fields, field)
|
||||||
|
}
|
||||||
|
return fields, nil
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
TypeType.AddFieldConfig("ofType", &Field{
|
||||||
|
Type: TypeType,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Note that these are FieldDefinition and not FieldConfig,
|
||||||
|
// so the format for args is different.
|
||||||
|
SchemaMetaFieldDef = &FieldDefinition{
|
||||||
|
Name: "__schema",
|
||||||
|
Type: NewNonNull(SchemaType),
|
||||||
|
Description: "Access the current type schema of this server.",
|
||||||
|
Args: []*Argument{},
|
||||||
|
Resolve: func(p ResolveParams) (interface{}, error) {
|
||||||
|
return p.Info.Schema, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
TypeMetaFieldDef = &FieldDefinition{
|
||||||
|
Name: "__type",
|
||||||
|
Type: TypeType,
|
||||||
|
Description: "Request the type information of a single type.",
|
||||||
|
Args: []*Argument{
|
||||||
|
{
|
||||||
|
PrivateName: "name",
|
||||||
|
Type: NewNonNull(String),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Resolve: func(p ResolveParams) (interface{}, error) {
|
||||||
|
name, ok := p.Args["name"].(string)
|
||||||
|
if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return p.Info.Schema.Type(name), nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeNameMetaFieldDef = &FieldDefinition{
|
||||||
|
Name: "__typename",
|
||||||
|
Type: NewNonNull(String),
|
||||||
|
Description: "The name of the current Object type at runtime.",
|
||||||
|
Args: []*Argument{},
|
||||||
|
Resolve: func(p ResolveParams) (interface{}, error) {
|
||||||
|
return p.Info.ParentType.Name(), nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Produces a GraphQL Value AST given a Golang value.
|
||||||
|
//
|
||||||
|
// Optionally, a GraphQL type may be provided, which will be used to
|
||||||
|
// disambiguate between value primitives.
|
||||||
|
//
|
||||||
|
// | JSON Value | GraphQL Value |
|
||||||
|
// | ------------- | -------------------- |
|
||||||
|
// | Object | Input Object |
|
||||||
|
// | Array | List |
|
||||||
|
// | Boolean | Boolean |
|
||||||
|
// | String | String / Enum Value |
|
||||||
|
// | Number | Int / Float |
|
||||||
|
|
||||||
|
func astFromValue(value interface{}, ttype Type) ast.Value {
|
||||||
|
|
||||||
|
if ttype, ok := ttype.(*NonNull); ok {
|
||||||
|
// Note: we're not checking that the result is non-null.
|
||||||
|
// This function is not responsible for validating the input value.
|
||||||
|
val := astFromValue(value, ttype.OfType)
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
if isNullish(value) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
valueVal := reflect.ValueOf(value)
|
||||||
|
if !valueVal.IsValid() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if valueVal.Type().Kind() == reflect.Ptr {
|
||||||
|
valueVal = valueVal.Elem()
|
||||||
|
}
|
||||||
|
if !valueVal.IsValid() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert Golang slice to GraphQL list. If the Type is a list, but
|
||||||
|
// the value is not an array, convert the value using the list's item type.
|
||||||
|
if ttype, ok := ttype.(*List); ok {
|
||||||
|
if valueVal.Type().Kind() == reflect.Slice {
|
||||||
|
itemType := ttype.OfType
|
||||||
|
values := []ast.Value{}
|
||||||
|
for i := 0; i < valueVal.Len(); i++ {
|
||||||
|
item := valueVal.Index(i).Interface()
|
||||||
|
itemAST := astFromValue(item, itemType)
|
||||||
|
if itemAST != nil {
|
||||||
|
values = append(values, itemAST)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ast.NewListValue(&ast.ListValue{
|
||||||
|
Values: values,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// Because GraphQL will accept single values as a "list of one" when
|
||||||
|
// expecting a list, if there's a non-array value and an expected list type,
|
||||||
|
// create an AST using the list's item type.
|
||||||
|
val := astFromValue(value, ttype.OfType)
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
if valueVal.Type().Kind() == reflect.Map {
|
||||||
|
// TODO: implement astFromValue from Map to Value
|
||||||
|
}
|
||||||
|
|
||||||
|
if value, ok := value.(bool); ok {
|
||||||
|
return ast.NewBooleanValue(&ast.BooleanValue{
|
||||||
|
Value: value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if value, ok := value.(int); ok {
|
||||||
|
if ttype == Float {
|
||||||
|
return ast.NewIntValue(&ast.IntValue{
|
||||||
|
Value: fmt.Sprintf("%v.0", value),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return ast.NewIntValue(&ast.IntValue{
|
||||||
|
Value: fmt.Sprintf("%v", value),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if value, ok := value.(float32); ok {
|
||||||
|
return ast.NewFloatValue(&ast.FloatValue{
|
||||||
|
Value: fmt.Sprintf("%v", value),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if value, ok := value.(float64); ok {
|
||||||
|
return ast.NewFloatValue(&ast.FloatValue{
|
||||||
|
Value: fmt.Sprintf("%v", value),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if value, ok := value.(string); ok {
|
||||||
|
if _, ok := ttype.(*Enum); ok {
|
||||||
|
return ast.NewEnumValue(&ast.EnumValue{
|
||||||
|
Value: fmt.Sprintf("%v", value),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return ast.NewStringValue(&ast.StringValue{
|
||||||
|
Value: fmt.Sprintf("%v", value),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback, treat as string
|
||||||
|
return ast.NewStringValue(&ast.StringValue{
|
||||||
|
Value: fmt.Sprintf("%v", value),
|
||||||
|
})
|
||||||
|
}
|
52
vendor/github.com/graphql-go/graphql/kitchen-sink.graphql
generated
vendored
Normal file
52
vendor/github.com/graphql-go/graphql/kitchen-sink.graphql
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# Filename: kitchen-sink.graphql
|
||||||
|
|
||||||
|
query namedQuery($foo: ComplexFooType, $bar: Bar = DefaultBarValue) {
|
||||||
|
customUser: user(id: [987, 654]) {
|
||||||
|
id,
|
||||||
|
... on User @defer {
|
||||||
|
field2 {
|
||||||
|
id ,
|
||||||
|
alias: field1(first:10, after:$foo,) @include(if: $foo) {
|
||||||
|
id,
|
||||||
|
...frag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... @skip(unless: $foo) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
... {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutation favPost {
|
||||||
|
fav(post: 123) @defer {
|
||||||
|
post {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
subscription PostFavSubscription($input: StoryLikeSubscribeInput) {
|
||||||
|
postFavSubscribe(input: $input) {
|
||||||
|
post {
|
||||||
|
favers {
|
||||||
|
count
|
||||||
|
}
|
||||||
|
favSentence {
|
||||||
|
text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment frag on Follower {
|
||||||
|
foo(size: $size, bar: $b, obj: {key: "value"})
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
unnamed(truthyVal: true, falseyVal: false),
|
||||||
|
query
|
||||||
|
}
|
33
vendor/github.com/graphql-go/graphql/language/ast/arguments.go
generated
vendored
Normal file
33
vendor/github.com/graphql-go/graphql/language/ast/arguments.go
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/graphql-go/graphql/language/kinds"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Argument implements Node
|
||||||
|
type Argument struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Name *Name
|
||||||
|
Value Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewArgument(arg *Argument) *Argument {
|
||||||
|
if arg == nil {
|
||||||
|
arg = &Argument{}
|
||||||
|
}
|
||||||
|
return &Argument{
|
||||||
|
Kind: kinds.Argument,
|
||||||
|
Loc: arg.Loc,
|
||||||
|
Name: arg.Name,
|
||||||
|
Value: arg.Value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (arg *Argument) GetKind() string {
|
||||||
|
return arg.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (arg *Argument) GetLoc() *Location {
|
||||||
|
return arg.Loc
|
||||||
|
}
|
247
vendor/github.com/graphql-go/graphql/language/ast/definitions.go
generated
vendored
Normal file
247
vendor/github.com/graphql-go/graphql/language/ast/definitions.go
generated
vendored
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/graphql-go/graphql/language/kinds"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Definition interface {
|
||||||
|
GetOperation() string
|
||||||
|
GetVariableDefinitions() []*VariableDefinition
|
||||||
|
GetSelectionSet() *SelectionSet
|
||||||
|
GetKind() string
|
||||||
|
GetLoc() *Location
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that all definition types implements Definition interface
|
||||||
|
var _ Definition = (*OperationDefinition)(nil)
|
||||||
|
var _ Definition = (*FragmentDefinition)(nil)
|
||||||
|
var _ Definition = (TypeSystemDefinition)(nil) // experimental non-spec addition.
|
||||||
|
|
||||||
|
// Note: subscription is an experimental non-spec addition.
|
||||||
|
const (
|
||||||
|
OperationTypeQuery = "query"
|
||||||
|
OperationTypeMutation = "mutation"
|
||||||
|
OperationTypeSubscription = "subscription"
|
||||||
|
)
|
||||||
|
|
||||||
|
// OperationDefinition implements Node, Definition
|
||||||
|
type OperationDefinition struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Operation string
|
||||||
|
Name *Name
|
||||||
|
VariableDefinitions []*VariableDefinition
|
||||||
|
Directives []*Directive
|
||||||
|
SelectionSet *SelectionSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOperationDefinition(op *OperationDefinition) *OperationDefinition {
|
||||||
|
if op == nil {
|
||||||
|
op = &OperationDefinition{}
|
||||||
|
}
|
||||||
|
return &OperationDefinition{
|
||||||
|
Kind: kinds.OperationDefinition,
|
||||||
|
Loc: op.Loc,
|
||||||
|
Operation: op.Operation,
|
||||||
|
Name: op.Name,
|
||||||
|
VariableDefinitions: op.VariableDefinitions,
|
||||||
|
Directives: op.Directives,
|
||||||
|
SelectionSet: op.SelectionSet,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (op *OperationDefinition) GetKind() string {
|
||||||
|
return op.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (op *OperationDefinition) GetLoc() *Location {
|
||||||
|
return op.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (op *OperationDefinition) GetOperation() string {
|
||||||
|
return op.Operation
|
||||||
|
}
|
||||||
|
|
||||||
|
func (op *OperationDefinition) GetName() *Name {
|
||||||
|
return op.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (op *OperationDefinition) GetVariableDefinitions() []*VariableDefinition {
|
||||||
|
return op.VariableDefinitions
|
||||||
|
}
|
||||||
|
|
||||||
|
func (op *OperationDefinition) GetDirectives() []*Directive {
|
||||||
|
return op.Directives
|
||||||
|
}
|
||||||
|
|
||||||
|
func (op *OperationDefinition) GetSelectionSet() *SelectionSet {
|
||||||
|
return op.SelectionSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// FragmentDefinition implements Node, Definition
|
||||||
|
type FragmentDefinition struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Operation string
|
||||||
|
Name *Name
|
||||||
|
VariableDefinitions []*VariableDefinition
|
||||||
|
TypeCondition *Named
|
||||||
|
Directives []*Directive
|
||||||
|
SelectionSet *SelectionSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFragmentDefinition(fd *FragmentDefinition) *FragmentDefinition {
|
||||||
|
if fd == nil {
|
||||||
|
fd = &FragmentDefinition{}
|
||||||
|
}
|
||||||
|
return &FragmentDefinition{
|
||||||
|
Kind: kinds.FragmentDefinition,
|
||||||
|
Loc: fd.Loc,
|
||||||
|
Operation: fd.Operation,
|
||||||
|
Name: fd.Name,
|
||||||
|
VariableDefinitions: fd.VariableDefinitions,
|
||||||
|
TypeCondition: fd.TypeCondition,
|
||||||
|
Directives: fd.Directives,
|
||||||
|
SelectionSet: fd.SelectionSet,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *FragmentDefinition) GetKind() string {
|
||||||
|
return fd.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *FragmentDefinition) GetLoc() *Location {
|
||||||
|
return fd.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *FragmentDefinition) GetOperation() string {
|
||||||
|
return fd.Operation
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *FragmentDefinition) GetName() *Name {
|
||||||
|
return fd.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *FragmentDefinition) GetVariableDefinitions() []*VariableDefinition {
|
||||||
|
return fd.VariableDefinitions
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd *FragmentDefinition) GetSelectionSet() *SelectionSet {
|
||||||
|
return fd.SelectionSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// VariableDefinition implements Node
|
||||||
|
type VariableDefinition struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Variable *Variable
|
||||||
|
Type Type
|
||||||
|
DefaultValue Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewVariableDefinition(vd *VariableDefinition) *VariableDefinition {
|
||||||
|
if vd == nil {
|
||||||
|
vd = &VariableDefinition{}
|
||||||
|
}
|
||||||
|
return &VariableDefinition{
|
||||||
|
Kind: kinds.VariableDefinition,
|
||||||
|
Loc: vd.Loc,
|
||||||
|
Variable: vd.Variable,
|
||||||
|
Type: vd.Type,
|
||||||
|
DefaultValue: vd.DefaultValue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vd *VariableDefinition) GetKind() string {
|
||||||
|
return vd.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vd *VariableDefinition) GetLoc() *Location {
|
||||||
|
return vd.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypeExtensionDefinition implements Node, Definition
|
||||||
|
type TypeExtensionDefinition struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Definition *ObjectDefinition
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTypeExtensionDefinition(def *TypeExtensionDefinition) *TypeExtensionDefinition {
|
||||||
|
if def == nil {
|
||||||
|
def = &TypeExtensionDefinition{}
|
||||||
|
}
|
||||||
|
return &TypeExtensionDefinition{
|
||||||
|
Kind: kinds.TypeExtensionDefinition,
|
||||||
|
Loc: def.Loc,
|
||||||
|
Definition: def.Definition,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *TypeExtensionDefinition) GetKind() string {
|
||||||
|
return def.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *TypeExtensionDefinition) GetLoc() *Location {
|
||||||
|
return def.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *TypeExtensionDefinition) GetVariableDefinitions() []*VariableDefinition {
|
||||||
|
return []*VariableDefinition{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *TypeExtensionDefinition) GetSelectionSet() *SelectionSet {
|
||||||
|
return &SelectionSet{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *TypeExtensionDefinition) GetOperation() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// DirectiveDefinition implements Node, Definition
|
||||||
|
type DirectiveDefinition struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Name *Name
|
||||||
|
Description *StringValue
|
||||||
|
Arguments []*InputValueDefinition
|
||||||
|
Locations []*Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDirectiveDefinition(def *DirectiveDefinition) *DirectiveDefinition {
|
||||||
|
if def == nil {
|
||||||
|
def = &DirectiveDefinition{}
|
||||||
|
}
|
||||||
|
return &DirectiveDefinition{
|
||||||
|
Kind: kinds.DirectiveDefinition,
|
||||||
|
Loc: def.Loc,
|
||||||
|
Name: def.Name,
|
||||||
|
Description: def.Description,
|
||||||
|
Arguments: def.Arguments,
|
||||||
|
Locations: def.Locations,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *DirectiveDefinition) GetKind() string {
|
||||||
|
return def.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *DirectiveDefinition) GetLoc() *Location {
|
||||||
|
return def.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *DirectiveDefinition) GetVariableDefinitions() []*VariableDefinition {
|
||||||
|
return []*VariableDefinition{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *DirectiveDefinition) GetSelectionSet() *SelectionSet {
|
||||||
|
return &SelectionSet{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *DirectiveDefinition) GetOperation() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *DirectiveDefinition) GetDescription() *StringValue {
|
||||||
|
return def.Description
|
||||||
|
}
|
33
vendor/github.com/graphql-go/graphql/language/ast/directives.go
generated
vendored
Normal file
33
vendor/github.com/graphql-go/graphql/language/ast/directives.go
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/graphql-go/graphql/language/kinds"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Directive implements Node
|
||||||
|
type Directive struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Name *Name
|
||||||
|
Arguments []*Argument
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDirective(dir *Directive) *Directive {
|
||||||
|
if dir == nil {
|
||||||
|
dir = &Directive{}
|
||||||
|
}
|
||||||
|
return &Directive{
|
||||||
|
Kind: kinds.Directive,
|
||||||
|
Loc: dir.Loc,
|
||||||
|
Name: dir.Name,
|
||||||
|
Arguments: dir.Arguments,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dir *Directive) GetKind() string {
|
||||||
|
return dir.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dir *Directive) GetLoc() *Location {
|
||||||
|
return dir.Loc
|
||||||
|
}
|
31
vendor/github.com/graphql-go/graphql/language/ast/document.go
generated
vendored
Normal file
31
vendor/github.com/graphql-go/graphql/language/ast/document.go
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/graphql-go/graphql/language/kinds"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Document implements Node
|
||||||
|
type Document struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Definitions []Node
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDocument(d *Document) *Document {
|
||||||
|
if d == nil {
|
||||||
|
d = &Document{}
|
||||||
|
}
|
||||||
|
return &Document{
|
||||||
|
Kind: kinds.Document,
|
||||||
|
Loc: d.Loc,
|
||||||
|
Definitions: d.Definitions,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (node *Document) GetKind() string {
|
||||||
|
return node.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (node *Document) GetLoc() *Location {
|
||||||
|
return node.Loc
|
||||||
|
}
|
22
vendor/github.com/graphql-go/graphql/language/ast/location.go
generated
vendored
Normal file
22
vendor/github.com/graphql-go/graphql/language/ast/location.go
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/graphql-go/graphql/language/source"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Location struct {
|
||||||
|
Start int
|
||||||
|
End int
|
||||||
|
Source *source.Source
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLocation(loc *Location) *Location {
|
||||||
|
if loc == nil {
|
||||||
|
loc = &Location{}
|
||||||
|
}
|
||||||
|
return &Location{
|
||||||
|
Start: loc.Start,
|
||||||
|
End: loc.End,
|
||||||
|
Source: loc.Source,
|
||||||
|
}
|
||||||
|
}
|
31
vendor/github.com/graphql-go/graphql/language/ast/name.go
generated
vendored
Normal file
31
vendor/github.com/graphql-go/graphql/language/ast/name.go
generated
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/graphql-go/graphql/language/kinds"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Name implements Node
|
||||||
|
type Name struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewName(node *Name) *Name {
|
||||||
|
if node == nil {
|
||||||
|
node = &Name{}
|
||||||
|
}
|
||||||
|
return &Name{
|
||||||
|
Kind: kinds.Name,
|
||||||
|
Value: node.Value,
|
||||||
|
Loc: node.Loc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (node *Name) GetKind() string {
|
||||||
|
return node.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (node *Name) GetLoc() *Location {
|
||||||
|
return node.Loc
|
||||||
|
}
|
45
vendor/github.com/graphql-go/graphql/language/ast/node.go
generated
vendored
Normal file
45
vendor/github.com/graphql-go/graphql/language/ast/node.go
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
type Node interface {
|
||||||
|
GetKind() string
|
||||||
|
GetLoc() *Location
|
||||||
|
}
|
||||||
|
|
||||||
|
// The list of all possible AST node graphql.
|
||||||
|
// Ensure that all node types implements Node interface
|
||||||
|
var _ Node = (*Name)(nil)
|
||||||
|
var _ Node = (*Document)(nil)
|
||||||
|
var _ Node = (*OperationDefinition)(nil)
|
||||||
|
var _ Node = (*VariableDefinition)(nil)
|
||||||
|
var _ Node = (*Variable)(nil)
|
||||||
|
var _ Node = (*SelectionSet)(nil)
|
||||||
|
var _ Node = (*Field)(nil)
|
||||||
|
var _ Node = (*Argument)(nil)
|
||||||
|
var _ Node = (*FragmentSpread)(nil)
|
||||||
|
var _ Node = (*InlineFragment)(nil)
|
||||||
|
var _ Node = (*FragmentDefinition)(nil)
|
||||||
|
var _ Node = (*IntValue)(nil)
|
||||||
|
var _ Node = (*FloatValue)(nil)
|
||||||
|
var _ Node = (*StringValue)(nil)
|
||||||
|
var _ Node = (*BooleanValue)(nil)
|
||||||
|
var _ Node = (*EnumValue)(nil)
|
||||||
|
var _ Node = (*ListValue)(nil)
|
||||||
|
var _ Node = (*ObjectValue)(nil)
|
||||||
|
var _ Node = (*ObjectField)(nil)
|
||||||
|
var _ Node = (*Directive)(nil)
|
||||||
|
var _ Node = (*Named)(nil)
|
||||||
|
var _ Node = (*List)(nil)
|
||||||
|
var _ Node = (*NonNull)(nil)
|
||||||
|
var _ Node = (*SchemaDefinition)(nil)
|
||||||
|
var _ Node = (*OperationTypeDefinition)(nil)
|
||||||
|
var _ Node = (*ScalarDefinition)(nil)
|
||||||
|
var _ Node = (*ObjectDefinition)(nil)
|
||||||
|
var _ Node = (*FieldDefinition)(nil)
|
||||||
|
var _ Node = (*InputValueDefinition)(nil)
|
||||||
|
var _ Node = (*InterfaceDefinition)(nil)
|
||||||
|
var _ Node = (*UnionDefinition)(nil)
|
||||||
|
var _ Node = (*EnumDefinition)(nil)
|
||||||
|
var _ Node = (*EnumValueDefinition)(nil)
|
||||||
|
var _ Node = (*InputObjectDefinition)(nil)
|
||||||
|
var _ Node = (*TypeExtensionDefinition)(nil)
|
||||||
|
var _ Node = (*DirectiveDefinition)(nil)
|
144
vendor/github.com/graphql-go/graphql/language/ast/selections.go
generated
vendored
Normal file
144
vendor/github.com/graphql-go/graphql/language/ast/selections.go
generated
vendored
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/graphql-go/graphql/language/kinds"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Selection interface {
|
||||||
|
GetSelectionSet() *SelectionSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that all definition types implements Selection interface
|
||||||
|
var _ Selection = (*Field)(nil)
|
||||||
|
var _ Selection = (*FragmentSpread)(nil)
|
||||||
|
var _ Selection = (*InlineFragment)(nil)
|
||||||
|
|
||||||
|
// Field implements Node, Selection
|
||||||
|
type Field struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Alias *Name
|
||||||
|
Name *Name
|
||||||
|
Arguments []*Argument
|
||||||
|
Directives []*Directive
|
||||||
|
SelectionSet *SelectionSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewField(f *Field) *Field {
|
||||||
|
if f == nil {
|
||||||
|
f = &Field{}
|
||||||
|
}
|
||||||
|
return &Field{
|
||||||
|
Kind: kinds.Field,
|
||||||
|
Loc: f.Loc,
|
||||||
|
Alias: f.Alias,
|
||||||
|
Name: f.Name,
|
||||||
|
Arguments: f.Arguments,
|
||||||
|
Directives: f.Directives,
|
||||||
|
SelectionSet: f.SelectionSet,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Field) GetKind() string {
|
||||||
|
return f.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Field) GetLoc() *Location {
|
||||||
|
return f.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Field) GetSelectionSet() *SelectionSet {
|
||||||
|
return f.SelectionSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// FragmentSpread implements Node, Selection
|
||||||
|
type FragmentSpread struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Name *Name
|
||||||
|
Directives []*Directive
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFragmentSpread(fs *FragmentSpread) *FragmentSpread {
|
||||||
|
if fs == nil {
|
||||||
|
fs = &FragmentSpread{}
|
||||||
|
}
|
||||||
|
return &FragmentSpread{
|
||||||
|
Kind: kinds.FragmentSpread,
|
||||||
|
Loc: fs.Loc,
|
||||||
|
Name: fs.Name,
|
||||||
|
Directives: fs.Directives,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *FragmentSpread) GetKind() string {
|
||||||
|
return fs.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *FragmentSpread) GetLoc() *Location {
|
||||||
|
return fs.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *FragmentSpread) GetSelectionSet() *SelectionSet {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InlineFragment implements Node, Selection
|
||||||
|
type InlineFragment struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
TypeCondition *Named
|
||||||
|
Directives []*Directive
|
||||||
|
SelectionSet *SelectionSet
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInlineFragment(f *InlineFragment) *InlineFragment {
|
||||||
|
if f == nil {
|
||||||
|
f = &InlineFragment{}
|
||||||
|
}
|
||||||
|
return &InlineFragment{
|
||||||
|
Kind: kinds.InlineFragment,
|
||||||
|
Loc: f.Loc,
|
||||||
|
TypeCondition: f.TypeCondition,
|
||||||
|
Directives: f.Directives,
|
||||||
|
SelectionSet: f.SelectionSet,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *InlineFragment) GetKind() string {
|
||||||
|
return f.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *InlineFragment) GetLoc() *Location {
|
||||||
|
return f.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *InlineFragment) GetSelectionSet() *SelectionSet {
|
||||||
|
return f.SelectionSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectionSet implements Node
|
||||||
|
type SelectionSet struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Selections []Selection
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSelectionSet(ss *SelectionSet) *SelectionSet {
|
||||||
|
if ss == nil {
|
||||||
|
ss = &SelectionSet{}
|
||||||
|
}
|
||||||
|
return &SelectionSet{
|
||||||
|
Kind: kinds.SelectionSet,
|
||||||
|
Loc: ss.Loc,
|
||||||
|
Selections: ss.Selections,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ss *SelectionSet) GetKind() string {
|
||||||
|
return ss.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ss *SelectionSet) GetLoc() *Location {
|
||||||
|
return ss.Loc
|
||||||
|
}
|
529
vendor/github.com/graphql-go/graphql/language/ast/type_definitions.go
generated
vendored
Normal file
529
vendor/github.com/graphql-go/graphql/language/ast/type_definitions.go
generated
vendored
Normal file
@ -0,0 +1,529 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/graphql-go/graphql/language/kinds"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DescribableNode are nodes that have descriptions associated with them.
|
||||||
|
type DescribableNode interface {
|
||||||
|
GetDescription() *StringValue
|
||||||
|
}
|
||||||
|
|
||||||
|
type TypeDefinition interface {
|
||||||
|
DescribableNode
|
||||||
|
GetOperation() string
|
||||||
|
GetVariableDefinitions() []*VariableDefinition
|
||||||
|
GetSelectionSet() *SelectionSet
|
||||||
|
GetKind() string
|
||||||
|
GetLoc() *Location
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ TypeDefinition = (*ScalarDefinition)(nil)
|
||||||
|
var _ TypeDefinition = (*ObjectDefinition)(nil)
|
||||||
|
var _ TypeDefinition = (*InterfaceDefinition)(nil)
|
||||||
|
var _ TypeDefinition = (*UnionDefinition)(nil)
|
||||||
|
var _ TypeDefinition = (*EnumDefinition)(nil)
|
||||||
|
var _ TypeDefinition = (*InputObjectDefinition)(nil)
|
||||||
|
|
||||||
|
type TypeSystemDefinition interface {
|
||||||
|
GetOperation() string
|
||||||
|
GetVariableDefinitions() []*VariableDefinition
|
||||||
|
GetSelectionSet() *SelectionSet
|
||||||
|
GetKind() string
|
||||||
|
GetLoc() *Location
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ TypeSystemDefinition = (*SchemaDefinition)(nil)
|
||||||
|
var _ TypeSystemDefinition = (TypeDefinition)(nil)
|
||||||
|
var _ TypeSystemDefinition = (*TypeExtensionDefinition)(nil)
|
||||||
|
var _ TypeSystemDefinition = (*DirectiveDefinition)(nil)
|
||||||
|
|
||||||
|
// SchemaDefinition implements Node, Definition
|
||||||
|
type SchemaDefinition struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Directives []*Directive
|
||||||
|
OperationTypes []*OperationTypeDefinition
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSchemaDefinition(def *SchemaDefinition) *SchemaDefinition {
|
||||||
|
if def == nil {
|
||||||
|
def = &SchemaDefinition{}
|
||||||
|
}
|
||||||
|
return &SchemaDefinition{
|
||||||
|
Kind: kinds.SchemaDefinition,
|
||||||
|
Loc: def.Loc,
|
||||||
|
Directives: def.Directives,
|
||||||
|
OperationTypes: def.OperationTypes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *SchemaDefinition) GetKind() string {
|
||||||
|
return def.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *SchemaDefinition) GetLoc() *Location {
|
||||||
|
return def.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *SchemaDefinition) GetVariableDefinitions() []*VariableDefinition {
|
||||||
|
return []*VariableDefinition{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *SchemaDefinition) GetSelectionSet() *SelectionSet {
|
||||||
|
return &SelectionSet{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *SchemaDefinition) GetOperation() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// OperationTypeDefinition implements Node, Definition
|
||||||
|
type OperationTypeDefinition struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Operation string
|
||||||
|
Type *Named
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOperationTypeDefinition(def *OperationTypeDefinition) *OperationTypeDefinition {
|
||||||
|
if def == nil {
|
||||||
|
def = &OperationTypeDefinition{}
|
||||||
|
}
|
||||||
|
return &OperationTypeDefinition{
|
||||||
|
Kind: kinds.OperationTypeDefinition,
|
||||||
|
Loc: def.Loc,
|
||||||
|
Operation: def.Operation,
|
||||||
|
Type: def.Type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *OperationTypeDefinition) GetKind() string {
|
||||||
|
return def.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *OperationTypeDefinition) GetLoc() *Location {
|
||||||
|
return def.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScalarDefinition implements Node, Definition
|
||||||
|
type ScalarDefinition struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Description *StringValue
|
||||||
|
Name *Name
|
||||||
|
Directives []*Directive
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewScalarDefinition(def *ScalarDefinition) *ScalarDefinition {
|
||||||
|
if def == nil {
|
||||||
|
def = &ScalarDefinition{}
|
||||||
|
}
|
||||||
|
return &ScalarDefinition{
|
||||||
|
Kind: kinds.ScalarDefinition,
|
||||||
|
Loc: def.Loc,
|
||||||
|
Description: def.Description,
|
||||||
|
Name: def.Name,
|
||||||
|
Directives: def.Directives,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *ScalarDefinition) GetKind() string {
|
||||||
|
return def.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *ScalarDefinition) GetLoc() *Location {
|
||||||
|
return def.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *ScalarDefinition) GetName() *Name {
|
||||||
|
return def.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *ScalarDefinition) GetVariableDefinitions() []*VariableDefinition {
|
||||||
|
return []*VariableDefinition{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *ScalarDefinition) GetSelectionSet() *SelectionSet {
|
||||||
|
return &SelectionSet{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *ScalarDefinition) GetOperation() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *ScalarDefinition) GetDescription() *StringValue {
|
||||||
|
return def.Description
|
||||||
|
}
|
||||||
|
|
||||||
|
// ObjectDefinition implements Node, Definition
|
||||||
|
type ObjectDefinition struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Name *Name
|
||||||
|
Description *StringValue
|
||||||
|
Interfaces []*Named
|
||||||
|
Directives []*Directive
|
||||||
|
Fields []*FieldDefinition
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewObjectDefinition(def *ObjectDefinition) *ObjectDefinition {
|
||||||
|
if def == nil {
|
||||||
|
def = &ObjectDefinition{}
|
||||||
|
}
|
||||||
|
return &ObjectDefinition{
|
||||||
|
Kind: kinds.ObjectDefinition,
|
||||||
|
Loc: def.Loc,
|
||||||
|
Name: def.Name,
|
||||||
|
Description: def.Description,
|
||||||
|
Interfaces: def.Interfaces,
|
||||||
|
Directives: def.Directives,
|
||||||
|
Fields: def.Fields,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *ObjectDefinition) GetKind() string {
|
||||||
|
return def.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *ObjectDefinition) GetLoc() *Location {
|
||||||
|
return def.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *ObjectDefinition) GetName() *Name {
|
||||||
|
return def.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *ObjectDefinition) GetVariableDefinitions() []*VariableDefinition {
|
||||||
|
return []*VariableDefinition{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *ObjectDefinition) GetSelectionSet() *SelectionSet {
|
||||||
|
return &SelectionSet{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *ObjectDefinition) GetOperation() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *ObjectDefinition) GetDescription() *StringValue {
|
||||||
|
return def.Description
|
||||||
|
}
|
||||||
|
|
||||||
|
// FieldDefinition implements Node
|
||||||
|
type FieldDefinition struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Name *Name
|
||||||
|
Description *StringValue
|
||||||
|
Arguments []*InputValueDefinition
|
||||||
|
Type Type
|
||||||
|
Directives []*Directive
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFieldDefinition(def *FieldDefinition) *FieldDefinition {
|
||||||
|
if def == nil {
|
||||||
|
def = &FieldDefinition{}
|
||||||
|
}
|
||||||
|
return &FieldDefinition{
|
||||||
|
Kind: kinds.FieldDefinition,
|
||||||
|
Loc: def.Loc,
|
||||||
|
Name: def.Name,
|
||||||
|
Description: def.Description,
|
||||||
|
Arguments: def.Arguments,
|
||||||
|
Type: def.Type,
|
||||||
|
Directives: def.Directives,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *FieldDefinition) GetKind() string {
|
||||||
|
return def.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *FieldDefinition) GetLoc() *Location {
|
||||||
|
return def.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *FieldDefinition) GetDescription() *StringValue {
|
||||||
|
return def.Description
|
||||||
|
}
|
||||||
|
|
||||||
|
// InputValueDefinition implements Node
|
||||||
|
type InputValueDefinition struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Name *Name
|
||||||
|
Description *StringValue
|
||||||
|
Type Type
|
||||||
|
DefaultValue Value
|
||||||
|
Directives []*Directive
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInputValueDefinition(def *InputValueDefinition) *InputValueDefinition {
|
||||||
|
if def == nil {
|
||||||
|
def = &InputValueDefinition{}
|
||||||
|
}
|
||||||
|
return &InputValueDefinition{
|
||||||
|
Kind: kinds.InputValueDefinition,
|
||||||
|
Loc: def.Loc,
|
||||||
|
Name: def.Name,
|
||||||
|
Description: def.Description,
|
||||||
|
Type: def.Type,
|
||||||
|
DefaultValue: def.DefaultValue,
|
||||||
|
Directives: def.Directives,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *InputValueDefinition) GetKind() string {
|
||||||
|
return def.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *InputValueDefinition) GetLoc() *Location {
|
||||||
|
return def.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *InputValueDefinition) GetDescription() *StringValue {
|
||||||
|
return def.Description
|
||||||
|
}
|
||||||
|
|
||||||
|
// InterfaceDefinition implements Node, Definition
|
||||||
|
type InterfaceDefinition struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Name *Name
|
||||||
|
Description *StringValue
|
||||||
|
Directives []*Directive
|
||||||
|
Fields []*FieldDefinition
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInterfaceDefinition(def *InterfaceDefinition) *InterfaceDefinition {
|
||||||
|
if def == nil {
|
||||||
|
def = &InterfaceDefinition{}
|
||||||
|
}
|
||||||
|
return &InterfaceDefinition{
|
||||||
|
Kind: kinds.InterfaceDefinition,
|
||||||
|
Loc: def.Loc,
|
||||||
|
Name: def.Name,
|
||||||
|
Description: def.Description,
|
||||||
|
Directives: def.Directives,
|
||||||
|
Fields: def.Fields,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *InterfaceDefinition) GetKind() string {
|
||||||
|
return def.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *InterfaceDefinition) GetLoc() *Location {
|
||||||
|
return def.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *InterfaceDefinition) GetName() *Name {
|
||||||
|
return def.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *InterfaceDefinition) GetVariableDefinitions() []*VariableDefinition {
|
||||||
|
return []*VariableDefinition{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *InterfaceDefinition) GetSelectionSet() *SelectionSet {
|
||||||
|
return &SelectionSet{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *InterfaceDefinition) GetOperation() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *InterfaceDefinition) GetDescription() *StringValue {
|
||||||
|
return def.Description
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnionDefinition implements Node, Definition
|
||||||
|
type UnionDefinition struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Name *Name
|
||||||
|
Description *StringValue
|
||||||
|
Directives []*Directive
|
||||||
|
Types []*Named
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUnionDefinition(def *UnionDefinition) *UnionDefinition {
|
||||||
|
if def == nil {
|
||||||
|
def = &UnionDefinition{}
|
||||||
|
}
|
||||||
|
return &UnionDefinition{
|
||||||
|
Kind: kinds.UnionDefinition,
|
||||||
|
Loc: def.Loc,
|
||||||
|
Name: def.Name,
|
||||||
|
Description: def.Description,
|
||||||
|
Directives: def.Directives,
|
||||||
|
Types: def.Types,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *UnionDefinition) GetKind() string {
|
||||||
|
return def.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *UnionDefinition) GetLoc() *Location {
|
||||||
|
return def.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *UnionDefinition) GetName() *Name {
|
||||||
|
return def.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *UnionDefinition) GetVariableDefinitions() []*VariableDefinition {
|
||||||
|
return []*VariableDefinition{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *UnionDefinition) GetSelectionSet() *SelectionSet {
|
||||||
|
return &SelectionSet{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *UnionDefinition) GetOperation() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *UnionDefinition) GetDescription() *StringValue {
|
||||||
|
return def.Description
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnumDefinition implements Node, Definition
|
||||||
|
type EnumDefinition struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Name *Name
|
||||||
|
Description *StringValue
|
||||||
|
Directives []*Directive
|
||||||
|
Values []*EnumValueDefinition
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEnumDefinition(def *EnumDefinition) *EnumDefinition {
|
||||||
|
if def == nil {
|
||||||
|
def = &EnumDefinition{}
|
||||||
|
}
|
||||||
|
return &EnumDefinition{
|
||||||
|
Kind: kinds.EnumDefinition,
|
||||||
|
Loc: def.Loc,
|
||||||
|
Name: def.Name,
|
||||||
|
Description: def.Description,
|
||||||
|
Directives: def.Directives,
|
||||||
|
Values: def.Values,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *EnumDefinition) GetKind() string {
|
||||||
|
return def.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *EnumDefinition) GetLoc() *Location {
|
||||||
|
return def.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *EnumDefinition) GetName() *Name {
|
||||||
|
return def.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *EnumDefinition) GetVariableDefinitions() []*VariableDefinition {
|
||||||
|
return []*VariableDefinition{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *EnumDefinition) GetSelectionSet() *SelectionSet {
|
||||||
|
return &SelectionSet{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *EnumDefinition) GetOperation() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *EnumDefinition) GetDescription() *StringValue {
|
||||||
|
return def.Description
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnumValueDefinition implements Node, Definition
|
||||||
|
type EnumValueDefinition struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Name *Name
|
||||||
|
Description *StringValue
|
||||||
|
Directives []*Directive
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEnumValueDefinition(def *EnumValueDefinition) *EnumValueDefinition {
|
||||||
|
if def == nil {
|
||||||
|
def = &EnumValueDefinition{}
|
||||||
|
}
|
||||||
|
return &EnumValueDefinition{
|
||||||
|
Kind: kinds.EnumValueDefinition,
|
||||||
|
Loc: def.Loc,
|
||||||
|
Name: def.Name,
|
||||||
|
Description: def.Description,
|
||||||
|
Directives: def.Directives,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *EnumValueDefinition) GetKind() string {
|
||||||
|
return def.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *EnumValueDefinition) GetLoc() *Location {
|
||||||
|
return def.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *EnumValueDefinition) GetDescription() *StringValue {
|
||||||
|
return def.Description
|
||||||
|
}
|
||||||
|
|
||||||
|
// InputObjectDefinition implements Node, Definition
|
||||||
|
type InputObjectDefinition struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Name *Name
|
||||||
|
Description *StringValue
|
||||||
|
Directives []*Directive
|
||||||
|
Fields []*InputValueDefinition
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInputObjectDefinition(def *InputObjectDefinition) *InputObjectDefinition {
|
||||||
|
if def == nil {
|
||||||
|
def = &InputObjectDefinition{}
|
||||||
|
}
|
||||||
|
return &InputObjectDefinition{
|
||||||
|
Kind: kinds.InputObjectDefinition,
|
||||||
|
Loc: def.Loc,
|
||||||
|
Name: def.Name,
|
||||||
|
Description: def.Description,
|
||||||
|
Directives: def.Directives,
|
||||||
|
Fields: def.Fields,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *InputObjectDefinition) GetKind() string {
|
||||||
|
return def.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *InputObjectDefinition) GetLoc() *Location {
|
||||||
|
return def.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *InputObjectDefinition) GetName() *Name {
|
||||||
|
return def.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *InputObjectDefinition) GetVariableDefinitions() []*VariableDefinition {
|
||||||
|
return []*VariableDefinition{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *InputObjectDefinition) GetSelectionSet() *SelectionSet {
|
||||||
|
return &SelectionSet{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *InputObjectDefinition) GetOperation() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (def *InputObjectDefinition) GetDescription() *StringValue {
|
||||||
|
return def.Description
|
||||||
|
}
|
106
vendor/github.com/graphql-go/graphql/language/ast/types.go
generated
vendored
Normal file
106
vendor/github.com/graphql-go/graphql/language/ast/types.go
generated
vendored
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/graphql-go/graphql/language/kinds"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Type interface {
|
||||||
|
GetKind() string
|
||||||
|
GetLoc() *Location
|
||||||
|
String() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that all value types implements Value interface
|
||||||
|
var _ Type = (*Named)(nil)
|
||||||
|
var _ Type = (*List)(nil)
|
||||||
|
var _ Type = (*NonNull)(nil)
|
||||||
|
|
||||||
|
// Named implements Node, Type
|
||||||
|
type Named struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Name *Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNamed(t *Named) *Named {
|
||||||
|
if t == nil {
|
||||||
|
t = &Named{}
|
||||||
|
}
|
||||||
|
return &Named{
|
||||||
|
Kind: kinds.Named,
|
||||||
|
Loc: t.Loc,
|
||||||
|
Name: t.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Named) GetKind() string {
|
||||||
|
return t.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Named) GetLoc() *Location {
|
||||||
|
return t.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Named) String() string {
|
||||||
|
return t.GetKind()
|
||||||
|
}
|
||||||
|
|
||||||
|
// List implements Node, Type
|
||||||
|
type List struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Type Type
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewList(t *List) *List {
|
||||||
|
if t == nil {
|
||||||
|
t = &List{}
|
||||||
|
}
|
||||||
|
return &List{
|
||||||
|
Kind: kinds.List,
|
||||||
|
Loc: t.Loc,
|
||||||
|
Type: t.Type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *List) GetKind() string {
|
||||||
|
return t.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *List) GetLoc() *Location {
|
||||||
|
return t.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *List) String() string {
|
||||||
|
return t.GetKind()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NonNull implements Node, Type
|
||||||
|
type NonNull struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Type Type
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNonNull(t *NonNull) *NonNull {
|
||||||
|
if t == nil {
|
||||||
|
t = &NonNull{}
|
||||||
|
}
|
||||||
|
return &NonNull{
|
||||||
|
Kind: kinds.NonNull,
|
||||||
|
Loc: t.Loc,
|
||||||
|
Type: t.Type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *NonNull) GetKind() string {
|
||||||
|
return t.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *NonNull) GetLoc() *Location {
|
||||||
|
return t.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *NonNull) String() string {
|
||||||
|
return t.GetKind()
|
||||||
|
}
|
305
vendor/github.com/graphql-go/graphql/language/ast/values.go
generated
vendored
Normal file
305
vendor/github.com/graphql-go/graphql/language/ast/values.go
generated
vendored
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/graphql-go/graphql/language/kinds"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Value interface {
|
||||||
|
GetValue() interface{}
|
||||||
|
GetKind() string
|
||||||
|
GetLoc() *Location
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that all value types implements Value interface
|
||||||
|
var _ Value = (*Variable)(nil)
|
||||||
|
var _ Value = (*IntValue)(nil)
|
||||||
|
var _ Value = (*FloatValue)(nil)
|
||||||
|
var _ Value = (*StringValue)(nil)
|
||||||
|
var _ Value = (*BooleanValue)(nil)
|
||||||
|
var _ Value = (*EnumValue)(nil)
|
||||||
|
var _ Value = (*ListValue)(nil)
|
||||||
|
var _ Value = (*ObjectValue)(nil)
|
||||||
|
|
||||||
|
// Variable implements Node, Value
|
||||||
|
type Variable struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Name *Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewVariable(v *Variable) *Variable {
|
||||||
|
if v == nil {
|
||||||
|
v = &Variable{}
|
||||||
|
}
|
||||||
|
return &Variable{
|
||||||
|
Kind: kinds.Variable,
|
||||||
|
Loc: v.Loc,
|
||||||
|
Name: v.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Variable) GetKind() string {
|
||||||
|
return v.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Variable) GetLoc() *Location {
|
||||||
|
return v.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetValue alias to Variable.GetName()
|
||||||
|
func (v *Variable) GetValue() interface{} {
|
||||||
|
return v.GetName()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Variable) GetName() interface{} {
|
||||||
|
return v.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntValue implements Node, Value
|
||||||
|
type IntValue struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIntValue(v *IntValue) *IntValue {
|
||||||
|
if v == nil {
|
||||||
|
v = &IntValue{}
|
||||||
|
}
|
||||||
|
return &IntValue{
|
||||||
|
Kind: kinds.IntValue,
|
||||||
|
Loc: v.Loc,
|
||||||
|
Value: v.Value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *IntValue) GetKind() string {
|
||||||
|
return v.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *IntValue) GetLoc() *Location {
|
||||||
|
return v.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *IntValue) GetValue() interface{} {
|
||||||
|
return v.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// FloatValue implements Node, Value
|
||||||
|
type FloatValue struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFloatValue(v *FloatValue) *FloatValue {
|
||||||
|
if v == nil {
|
||||||
|
v = &FloatValue{}
|
||||||
|
}
|
||||||
|
return &FloatValue{
|
||||||
|
Kind: kinds.FloatValue,
|
||||||
|
Loc: v.Loc,
|
||||||
|
Value: v.Value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *FloatValue) GetKind() string {
|
||||||
|
return v.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *FloatValue) GetLoc() *Location {
|
||||||
|
return v.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *FloatValue) GetValue() interface{} {
|
||||||
|
return v.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// StringValue implements Node, Value
|
||||||
|
type StringValue struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStringValue(v *StringValue) *StringValue {
|
||||||
|
if v == nil {
|
||||||
|
v = &StringValue{}
|
||||||
|
}
|
||||||
|
return &StringValue{
|
||||||
|
Kind: kinds.StringValue,
|
||||||
|
Loc: v.Loc,
|
||||||
|
Value: v.Value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *StringValue) GetKind() string {
|
||||||
|
return v.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *StringValue) GetLoc() *Location {
|
||||||
|
return v.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *StringValue) GetValue() interface{} {
|
||||||
|
return v.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// BooleanValue implements Node, Value
|
||||||
|
type BooleanValue struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Value bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBooleanValue(v *BooleanValue) *BooleanValue {
|
||||||
|
if v == nil {
|
||||||
|
v = &BooleanValue{}
|
||||||
|
}
|
||||||
|
return &BooleanValue{
|
||||||
|
Kind: kinds.BooleanValue,
|
||||||
|
Loc: v.Loc,
|
||||||
|
Value: v.Value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *BooleanValue) GetKind() string {
|
||||||
|
return v.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *BooleanValue) GetLoc() *Location {
|
||||||
|
return v.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *BooleanValue) GetValue() interface{} {
|
||||||
|
return v.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnumValue implements Node, Value
|
||||||
|
type EnumValue struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEnumValue(v *EnumValue) *EnumValue {
|
||||||
|
if v == nil {
|
||||||
|
v = &EnumValue{}
|
||||||
|
}
|
||||||
|
return &EnumValue{
|
||||||
|
Kind: kinds.EnumValue,
|
||||||
|
Loc: v.Loc,
|
||||||
|
Value: v.Value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *EnumValue) GetKind() string {
|
||||||
|
return v.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *EnumValue) GetLoc() *Location {
|
||||||
|
return v.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *EnumValue) GetValue() interface{} {
|
||||||
|
return v.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListValue implements Node, Value
|
||||||
|
type ListValue struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Values []Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewListValue(v *ListValue) *ListValue {
|
||||||
|
if v == nil {
|
||||||
|
v = &ListValue{}
|
||||||
|
}
|
||||||
|
return &ListValue{
|
||||||
|
Kind: kinds.ListValue,
|
||||||
|
Loc: v.Loc,
|
||||||
|
Values: v.Values,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *ListValue) GetKind() string {
|
||||||
|
return v.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *ListValue) GetLoc() *Location {
|
||||||
|
return v.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetValue alias to ListValue.GetValues()
|
||||||
|
func (v *ListValue) GetValue() interface{} {
|
||||||
|
return v.GetValues()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *ListValue) GetValues() interface{} {
|
||||||
|
// TODO: verify ObjectValue.GetValue()
|
||||||
|
return v.Values
|
||||||
|
}
|
||||||
|
|
||||||
|
// ObjectValue implements Node, Value
|
||||||
|
type ObjectValue struct {
|
||||||
|
Kind string
|
||||||
|
Loc *Location
|
||||||
|
Fields []*ObjectField
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewObjectValue(v *ObjectValue) *ObjectValue {
|
||||||
|
if v == nil {
|
||||||
|
v = &ObjectValue{}
|
||||||
|
}
|
||||||
|
return &ObjectValue{
|
||||||
|
Kind: kinds.ObjectValue,
|
||||||
|
Loc: v.Loc,
|
||||||
|
Fields: v.Fields,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *ObjectValue) GetKind() string {
|
||||||
|
return v.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *ObjectValue) GetLoc() *Location {
|
||||||
|
return v.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *ObjectValue) GetValue() interface{} {
|
||||||
|
// TODO: verify ObjectValue.GetValue()
|
||||||
|
return v.Fields
|
||||||
|
}
|
||||||
|
|
||||||
|
// ObjectField implements Node, Value
|
||||||
|
type ObjectField struct {
|
||||||
|
Kind string
|
||||||
|
Name *Name
|
||||||
|
Loc *Location
|
||||||
|
Value Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewObjectField(f *ObjectField) *ObjectField {
|
||||||
|
if f == nil {
|
||||||
|
f = &ObjectField{}
|
||||||
|
}
|
||||||
|
return &ObjectField{
|
||||||
|
Kind: kinds.ObjectField,
|
||||||
|
Loc: f.Loc,
|
||||||
|
Name: f.Name,
|
||||||
|
Value: f.Value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ObjectField) GetKind() string {
|
||||||
|
return f.Kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ObjectField) GetLoc() *Location {
|
||||||
|
return f.Loc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *ObjectField) GetValue() interface{} {
|
||||||
|
return f.Value
|
||||||
|
}
|
59
vendor/github.com/graphql-go/graphql/language/kinds/kinds.go
generated
vendored
Normal file
59
vendor/github.com/graphql-go/graphql/language/kinds/kinds.go
generated
vendored
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package kinds
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Name
|
||||||
|
Name = "Name"
|
||||||
|
|
||||||
|
// Document
|
||||||
|
Document = "Document"
|
||||||
|
OperationDefinition = "OperationDefinition"
|
||||||
|
VariableDefinition = "VariableDefinition"
|
||||||
|
Variable = "Variable"
|
||||||
|
SelectionSet = "SelectionSet"
|
||||||
|
Field = "Field"
|
||||||
|
Argument = "Argument"
|
||||||
|
|
||||||
|
// Fragments
|
||||||
|
FragmentSpread = "FragmentSpread"
|
||||||
|
InlineFragment = "InlineFragment"
|
||||||
|
FragmentDefinition = "FragmentDefinition"
|
||||||
|
|
||||||
|
// Values
|
||||||
|
IntValue = "IntValue"
|
||||||
|
FloatValue = "FloatValue"
|
||||||
|
StringValue = "StringValue"
|
||||||
|
BooleanValue = "BooleanValue"
|
||||||
|
EnumValue = "EnumValue"
|
||||||
|
ListValue = "ListValue"
|
||||||
|
ObjectValue = "ObjectValue"
|
||||||
|
ObjectField = "ObjectField"
|
||||||
|
|
||||||
|
// Directives
|
||||||
|
Directive = "Directive"
|
||||||
|
|
||||||
|
// Types
|
||||||
|
Named = "Named" // previously NamedType
|
||||||
|
List = "List" // previously ListType
|
||||||
|
NonNull = "NonNull" // previously NonNull
|
||||||
|
|
||||||
|
// Type System Definitions
|
||||||
|
SchemaDefinition = "SchemaDefinition"
|
||||||
|
OperationTypeDefinition = "OperationTypeDefinition"
|
||||||
|
|
||||||
|
// Types Definitions
|
||||||
|
ScalarDefinition = "ScalarDefinition" // previously ScalarTypeDefinition
|
||||||
|
ObjectDefinition = "ObjectDefinition" // previously ObjectTypeDefinition
|
||||||
|
FieldDefinition = "FieldDefinition"
|
||||||
|
InputValueDefinition = "InputValueDefinition"
|
||||||
|
InterfaceDefinition = "InterfaceDefinition" // previously InterfaceTypeDefinition
|
||||||
|
UnionDefinition = "UnionDefinition" // previously UnionTypeDefinition
|
||||||
|
EnumDefinition = "EnumDefinition" // previously EnumTypeDefinition
|
||||||
|
EnumValueDefinition = "EnumValueDefinition"
|
||||||
|
InputObjectDefinition = "InputObjectDefinition" // previously InputObjectTypeDefinition
|
||||||
|
|
||||||
|
// Types Extensions
|
||||||
|
TypeExtensionDefinition = "TypeExtensionDefinition"
|
||||||
|
|
||||||
|
// Directive Definitions
|
||||||
|
DirectiveDefinition = "DirectiveDefinition"
|
||||||
|
)
|
656
vendor/github.com/graphql-go/graphql/language/lexer/lexer.go
generated
vendored
Normal file
656
vendor/github.com/graphql-go/graphql/language/lexer/lexer.go
generated
vendored
Normal file
@ -0,0 +1,656 @@
|
|||||||
|
package lexer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/graphql-go/graphql/gqlerrors"
|
||||||
|
"github.com/graphql-go/graphql/language/source"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
EOF = iota + 1
|
||||||
|
BANG
|
||||||
|
DOLLAR
|
||||||
|
PAREN_L
|
||||||
|
PAREN_R
|
||||||
|
SPREAD
|
||||||
|
COLON
|
||||||
|
EQUALS
|
||||||
|
AT
|
||||||
|
BRACKET_L
|
||||||
|
BRACKET_R
|
||||||
|
BRACE_L
|
||||||
|
PIPE
|
||||||
|
BRACE_R
|
||||||
|
NAME
|
||||||
|
INT
|
||||||
|
FLOAT
|
||||||
|
STRING
|
||||||
|
BLOCK_STRING
|
||||||
|
)
|
||||||
|
|
||||||
|
var TokenKind map[int]int
|
||||||
|
var tokenDescription map[int]string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
TokenKind = make(map[int]int)
|
||||||
|
tokenDescription = make(map[int]string)
|
||||||
|
TokenKind[EOF] = EOF
|
||||||
|
TokenKind[BANG] = BANG
|
||||||
|
TokenKind[DOLLAR] = DOLLAR
|
||||||
|
TokenKind[PAREN_L] = PAREN_L
|
||||||
|
TokenKind[PAREN_R] = PAREN_R
|
||||||
|
TokenKind[SPREAD] = SPREAD
|
||||||
|
TokenKind[COLON] = COLON
|
||||||
|
TokenKind[EQUALS] = EQUALS
|
||||||
|
TokenKind[AT] = AT
|
||||||
|
TokenKind[BRACKET_L] = BRACKET_L
|
||||||
|
TokenKind[BRACKET_R] = BRACKET_R
|
||||||
|
TokenKind[BRACE_L] = BRACE_L
|
||||||
|
TokenKind[PIPE] = PIPE
|
||||||
|
TokenKind[BRACE_R] = BRACE_R
|
||||||
|
TokenKind[NAME] = NAME
|
||||||
|
TokenKind[INT] = INT
|
||||||
|
TokenKind[FLOAT] = FLOAT
|
||||||
|
TokenKind[STRING] = STRING
|
||||||
|
TokenKind[BLOCK_STRING] = BLOCK_STRING
|
||||||
|
tokenDescription[TokenKind[EOF]] = "EOF"
|
||||||
|
tokenDescription[TokenKind[BANG]] = "!"
|
||||||
|
tokenDescription[TokenKind[DOLLAR]] = "$"
|
||||||
|
tokenDescription[TokenKind[PAREN_L]] = "("
|
||||||
|
tokenDescription[TokenKind[PAREN_R]] = ")"
|
||||||
|
tokenDescription[TokenKind[SPREAD]] = "..."
|
||||||
|
tokenDescription[TokenKind[COLON]] = ":"
|
||||||
|
tokenDescription[TokenKind[EQUALS]] = "="
|
||||||
|
tokenDescription[TokenKind[AT]] = "@"
|
||||||
|
tokenDescription[TokenKind[BRACKET_L]] = "["
|
||||||
|
tokenDescription[TokenKind[BRACKET_R]] = "]"
|
||||||
|
tokenDescription[TokenKind[BRACE_L]] = "{"
|
||||||
|
tokenDescription[TokenKind[PIPE]] = "|"
|
||||||
|
tokenDescription[TokenKind[BRACE_R]] = "}"
|
||||||
|
tokenDescription[TokenKind[NAME]] = "Name"
|
||||||
|
tokenDescription[TokenKind[INT]] = "Int"
|
||||||
|
tokenDescription[TokenKind[FLOAT]] = "Float"
|
||||||
|
tokenDescription[TokenKind[STRING]] = "String"
|
||||||
|
tokenDescription[TokenKind[BLOCK_STRING]] = "BlockString"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token is a representation of a lexed Token. Value only appears for non-punctuation
|
||||||
|
// tokens: NAME, INT, FLOAT, and STRING.
|
||||||
|
type Token struct {
|
||||||
|
Kind int
|
||||||
|
Start int
|
||||||
|
End int
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Lexer func(resetPosition int) (Token, error)
|
||||||
|
|
||||||
|
func Lex(s *source.Source) Lexer {
|
||||||
|
var prevPosition int
|
||||||
|
return func(resetPosition int) (Token, error) {
|
||||||
|
if resetPosition == 0 {
|
||||||
|
resetPosition = prevPosition
|
||||||
|
}
|
||||||
|
token, err := readToken(s, resetPosition)
|
||||||
|
if err != nil {
|
||||||
|
return token, err
|
||||||
|
}
|
||||||
|
prevPosition = token.End
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reads an alphanumeric + underscore name from the source.
|
||||||
|
// [_A-Za-z][_0-9A-Za-z]*
|
||||||
|
// position: Points to the byte position in the byte array
|
||||||
|
// runePosition: Points to the rune position in the byte array
|
||||||
|
func readName(source *source.Source, position, runePosition int) Token {
|
||||||
|
body := source.Body
|
||||||
|
bodyLength := len(body)
|
||||||
|
endByte := position + 1
|
||||||
|
endRune := runePosition + 1
|
||||||
|
for {
|
||||||
|
code, _ := runeAt(body, endByte)
|
||||||
|
if (endByte != bodyLength) &&
|
||||||
|
(code == '_' || // _
|
||||||
|
code >= '0' && code <= '9' || // 0-9
|
||||||
|
code >= 'A' && code <= 'Z' || // A-Z
|
||||||
|
code >= 'a' && code <= 'z') { // a-z
|
||||||
|
endByte++
|
||||||
|
endRune++
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return makeToken(TokenKind[NAME], runePosition, endRune, string(body[position:endByte]))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reads a number token from the source file, either a float
|
||||||
|
// or an int depending on whether a decimal point appears.
|
||||||
|
// Int: -?(0|[1-9][0-9]*)
|
||||||
|
// Float: -?(0|[1-9][0-9]*)(\.[0-9]+)?((E|e)(+|-)?[0-9]+)?
|
||||||
|
func readNumber(s *source.Source, start int, firstCode rune, codeLength int) (Token, error) {
|
||||||
|
code := firstCode
|
||||||
|
body := s.Body
|
||||||
|
position := start
|
||||||
|
isFloat := false
|
||||||
|
if code == '-' { // -
|
||||||
|
position += codeLength
|
||||||
|
code, codeLength = runeAt(body, position)
|
||||||
|
}
|
||||||
|
if code == '0' { // 0
|
||||||
|
position += codeLength
|
||||||
|
code, codeLength = runeAt(body, position)
|
||||||
|
if code >= '0' && code <= '9' {
|
||||||
|
description := fmt.Sprintf("Invalid number, unexpected digit after 0: %v.", printCharCode(code))
|
||||||
|
return Token{}, gqlerrors.NewSyntaxError(s, position, description)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
p, err := readDigits(s, position, code, codeLength)
|
||||||
|
if err != nil {
|
||||||
|
return Token{}, err
|
||||||
|
}
|
||||||
|
position = p
|
||||||
|
code, codeLength = runeAt(body, position)
|
||||||
|
}
|
||||||
|
if code == '.' { // .
|
||||||
|
isFloat = true
|
||||||
|
position += codeLength
|
||||||
|
code, codeLength = runeAt(body, position)
|
||||||
|
p, err := readDigits(s, position, code, codeLength)
|
||||||
|
if err != nil {
|
||||||
|
return Token{}, err
|
||||||
|
}
|
||||||
|
position = p
|
||||||
|
code, codeLength = runeAt(body, position)
|
||||||
|
}
|
||||||
|
if code == 'E' || code == 'e' { // E e
|
||||||
|
isFloat = true
|
||||||
|
position += codeLength
|
||||||
|
code, codeLength = runeAt(body, position)
|
||||||
|
if code == '+' || code == '-' { // + -
|
||||||
|
position += codeLength
|
||||||
|
code, codeLength = runeAt(body, position)
|
||||||
|
}
|
||||||
|
p, err := readDigits(s, position, code, codeLength)
|
||||||
|
if err != nil {
|
||||||
|
return Token{}, err
|
||||||
|
}
|
||||||
|
position = p
|
||||||
|
}
|
||||||
|
kind := TokenKind[INT]
|
||||||
|
if isFloat {
|
||||||
|
kind = TokenKind[FLOAT]
|
||||||
|
}
|
||||||
|
|
||||||
|
return makeToken(kind, start, position, string(body[start:position])), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the new position in the source after reading digits.
|
||||||
|
func readDigits(s *source.Source, start int, firstCode rune, codeLength int) (int, error) {
|
||||||
|
body := s.Body
|
||||||
|
position := start
|
||||||
|
code := firstCode
|
||||||
|
if code >= '0' && code <= '9' { // 0 - 9
|
||||||
|
for {
|
||||||
|
if code >= '0' && code <= '9' { // 0 - 9
|
||||||
|
position += codeLength
|
||||||
|
code, codeLength = runeAt(body, position)
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return position, nil
|
||||||
|
}
|
||||||
|
var description string
|
||||||
|
description = fmt.Sprintf("Invalid number, expected digit but got: %v.", printCharCode(code))
|
||||||
|
return position, gqlerrors.NewSyntaxError(s, position, description)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readString(s *source.Source, start int) (Token, error) {
|
||||||
|
body := s.Body
|
||||||
|
position := start + 1
|
||||||
|
runePosition := start + 1
|
||||||
|
chunkStart := position
|
||||||
|
var code rune
|
||||||
|
var n int
|
||||||
|
var valueBuffer bytes.Buffer
|
||||||
|
for {
|
||||||
|
code, n = runeAt(body, position)
|
||||||
|
if position < len(body) &&
|
||||||
|
// not LineTerminator
|
||||||
|
code != 0x000A && code != 0x000D &&
|
||||||
|
// not Quote (")
|
||||||
|
code != '"' {
|
||||||
|
|
||||||
|
// SourceCharacter
|
||||||
|
if code < 0x0020 && code != 0x0009 {
|
||||||
|
return Token{}, gqlerrors.NewSyntaxError(s, runePosition, fmt.Sprintf(`Invalid character within String: %v.`, printCharCode(code)))
|
||||||
|
}
|
||||||
|
position += n
|
||||||
|
runePosition++
|
||||||
|
if code == '\\' { // \
|
||||||
|
valueBuffer.Write(body[chunkStart : position-1])
|
||||||
|
code, n = runeAt(body, position)
|
||||||
|
switch code {
|
||||||
|
case '"':
|
||||||
|
valueBuffer.WriteRune('"')
|
||||||
|
break
|
||||||
|
case '/':
|
||||||
|
valueBuffer.WriteRune('/')
|
||||||
|
break
|
||||||
|
case '\\':
|
||||||
|
valueBuffer.WriteRune('\\')
|
||||||
|
break
|
||||||
|
case 'b':
|
||||||
|
valueBuffer.WriteRune('\b')
|
||||||
|
break
|
||||||
|
case 'f':
|
||||||
|
valueBuffer.WriteRune('\f')
|
||||||
|
break
|
||||||
|
case 'n':
|
||||||
|
valueBuffer.WriteRune('\n')
|
||||||
|
break
|
||||||
|
case 'r':
|
||||||
|
valueBuffer.WriteRune('\r')
|
||||||
|
break
|
||||||
|
case 't':
|
||||||
|
valueBuffer.WriteRune('\t')
|
||||||
|
break
|
||||||
|
case 'u':
|
||||||
|
// Check if there are at least 4 bytes available
|
||||||
|
if len(body) <= position+4 {
|
||||||
|
return Token{}, gqlerrors.NewSyntaxError(s, runePosition,
|
||||||
|
fmt.Sprintf("Invalid character escape sequence: "+
|
||||||
|
"\\u%v", string(body[position+1:])))
|
||||||
|
}
|
||||||
|
charCode := uniCharCode(
|
||||||
|
rune(body[position+1]),
|
||||||
|
rune(body[position+2]),
|
||||||
|
rune(body[position+3]),
|
||||||
|
rune(body[position+4]),
|
||||||
|
)
|
||||||
|
if charCode < 0 {
|
||||||
|
return Token{}, gqlerrors.NewSyntaxError(s, runePosition,
|
||||||
|
fmt.Sprintf("Invalid character escape sequence: "+
|
||||||
|
"\\u%v", string(body[position+1:position+5])))
|
||||||
|
}
|
||||||
|
valueBuffer.WriteRune(charCode)
|
||||||
|
position += 4
|
||||||
|
runePosition += 4
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return Token{}, gqlerrors.NewSyntaxError(s, runePosition,
|
||||||
|
fmt.Sprintf(`Invalid character escape sequence: \\%c.`, code))
|
||||||
|
}
|
||||||
|
position += n
|
||||||
|
runePosition++
|
||||||
|
chunkStart = position
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if code != '"' { // quote (")
|
||||||
|
return Token{}, gqlerrors.NewSyntaxError(s, runePosition, "Unterminated string.")
|
||||||
|
}
|
||||||
|
stringContent := body[chunkStart:position]
|
||||||
|
valueBuffer.Write(stringContent)
|
||||||
|
value := valueBuffer.String()
|
||||||
|
return makeToken(TokenKind[STRING], start, position+1, value), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// readBlockString reads a block string token from the source file.
|
||||||
|
//
|
||||||
|
// """("?"?(\\"""|\\(?!=""")|[^"\\]))*"""
|
||||||
|
func readBlockString(s *source.Source, start int) (Token, error) {
|
||||||
|
body := s.Body
|
||||||
|
position := start + 3
|
||||||
|
runePosition := start + 3
|
||||||
|
chunkStart := position
|
||||||
|
var valueBuffer bytes.Buffer
|
||||||
|
|
||||||
|
for {
|
||||||
|
// Stop if we've reached the end of the buffer
|
||||||
|
if position >= len(body) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
code, n := runeAt(body, position)
|
||||||
|
|
||||||
|
// Closing Triple-Quote (""")
|
||||||
|
if code == '"' {
|
||||||
|
x, _ := runeAt(body, position+1)
|
||||||
|
y, _ := runeAt(body, position+2)
|
||||||
|
if x == '"' && y == '"' {
|
||||||
|
stringContent := body[chunkStart:position]
|
||||||
|
valueBuffer.Write(stringContent)
|
||||||
|
value := blockStringValue(valueBuffer.String())
|
||||||
|
return makeToken(TokenKind[BLOCK_STRING], start, position+3, value), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SourceCharacter
|
||||||
|
if code < 0x0020 &&
|
||||||
|
code != 0x0009 &&
|
||||||
|
code != 0x000a &&
|
||||||
|
code != 0x000d {
|
||||||
|
return Token{}, gqlerrors.NewSyntaxError(s, runePosition, fmt.Sprintf(`Invalid character within String: %v.`, printCharCode(code)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Escape Triple-Quote (\""")
|
||||||
|
if code == '\\' { // \
|
||||||
|
x, _ := runeAt(body, position+1)
|
||||||
|
y, _ := runeAt(body, position+2)
|
||||||
|
z, _ := runeAt(body, position+3)
|
||||||
|
if x == '"' && y == '"' && z == '"' {
|
||||||
|
stringContent := append(body[chunkStart:position], []byte(`"""`)...)
|
||||||
|
valueBuffer.Write(stringContent)
|
||||||
|
position += 4 // account for `"""` characters
|
||||||
|
runePosition += 4 // " " " "
|
||||||
|
chunkStart = position
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
position += n
|
||||||
|
runePosition++
|
||||||
|
}
|
||||||
|
|
||||||
|
return Token{}, gqlerrors.NewSyntaxError(s, runePosition, "Unterminated string.")
|
||||||
|
}
|
||||||
|
|
||||||
|
var splitLinesRegex = regexp.MustCompile("\r\n|[\n\r]")
|
||||||
|
|
||||||
|
// This implements the GraphQL spec's BlockStringValue() static algorithm.
|
||||||
|
//
|
||||||
|
// Produces the value of a block string from its parsed raw value, similar to
|
||||||
|
// Coffeescript's block string, Python's docstring trim or Ruby's strip_heredoc.
|
||||||
|
//
|
||||||
|
// Spec: http://facebook.github.io/graphql/draft/#BlockStringValue()
|
||||||
|
// Heavily borrows from: https://github.com/graphql/graphql-js/blob/8e0c599ceccfa8c40d6edf3b72ee2a71490b10e0/src/language/blockStringValue.js
|
||||||
|
func blockStringValue(in string) string {
|
||||||
|
// Expand a block string's raw value into independent lines.
|
||||||
|
lines := splitLinesRegex.Split(in, -1)
|
||||||
|
|
||||||
|
// Remove common indentation from all lines but first
|
||||||
|
commonIndent := -1
|
||||||
|
for i := 1; i < len(lines); i++ {
|
||||||
|
line := lines[i]
|
||||||
|
indent := leadingWhitespaceLen(line)
|
||||||
|
if indent < len(line) && (commonIndent == -1 || indent < commonIndent) {
|
||||||
|
commonIndent = indent
|
||||||
|
if commonIndent == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if commonIndent > 0 {
|
||||||
|
for i, line := range lines {
|
||||||
|
if commonIndent > len(line) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
lines[i] = line[commonIndent:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove leading blank lines.
|
||||||
|
for {
|
||||||
|
if isBlank := lineIsBlank(lines[0]); !isBlank {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
lines = lines[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove trailing blank lines.
|
||||||
|
for {
|
||||||
|
i := len(lines) - 1
|
||||||
|
if isBlank := lineIsBlank(lines[i]); !isBlank {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
lines = append(lines[:i], lines[i+1:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a string of the lines joined with U+000A.
|
||||||
|
return strings.Join(lines, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
// leadingWhitespaceLen returns count of whitespace characters on given line.
|
||||||
|
func leadingWhitespaceLen(in string) (n int) {
|
||||||
|
for _, ch := range in {
|
||||||
|
if ch == ' ' || ch == '\t' {
|
||||||
|
n++
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// lineIsBlank returns true when given line has no content.
|
||||||
|
func lineIsBlank(in string) bool {
|
||||||
|
return leadingWhitespaceLen(in) == len(in)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts four hexidecimal chars to the integer that the
|
||||||
|
// string represents. For example, uniCharCode('0','0','0','f')
|
||||||
|
// will return 15, and uniCharCode('0','0','f','f') returns 255.
|
||||||
|
// Returns a negative number on error, if a char was invalid.
|
||||||
|
// This is implemented by noting that char2hex() returns -1 on error,
|
||||||
|
// which means the result of ORing the char2hex() will also be negative.
|
||||||
|
func uniCharCode(a, b, c, d rune) rune {
|
||||||
|
return rune(char2hex(a)<<12 | char2hex(b)<<8 | char2hex(c)<<4 | char2hex(d))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts a hex character to its integer value.
|
||||||
|
// '0' becomes 0, '9' becomes 9
|
||||||
|
// 'A' becomes 10, 'F' becomes 15
|
||||||
|
// 'a' becomes 10, 'f' becomes 15
|
||||||
|
// Returns -1 on error.
|
||||||
|
func char2hex(a rune) int {
|
||||||
|
if a >= 48 && a <= 57 { // 0-9
|
||||||
|
return int(a) - 48
|
||||||
|
} else if a >= 65 && a <= 70 { // A-F
|
||||||
|
return int(a) - 55
|
||||||
|
} else if a >= 97 && a <= 102 {
|
||||||
|
// a-f
|
||||||
|
return int(a) - 87
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeToken(kind int, start int, end int, value string) Token {
|
||||||
|
return Token{Kind: kind, Start: start, End: end, Value: value}
|
||||||
|
}
|
||||||
|
|
||||||
|
func printCharCode(code rune) string {
|
||||||
|
// NaN/undefined represents access beyond the end of the file.
|
||||||
|
if code < 0 {
|
||||||
|
return "<EOF>"
|
||||||
|
}
|
||||||
|
// print as ASCII for printable range
|
||||||
|
if code >= 0x0020 && code < 0x007F {
|
||||||
|
return fmt.Sprintf(`"%c"`, code)
|
||||||
|
}
|
||||||
|
// Otherwise print the escaped form. e.g. `"\\u0007"`
|
||||||
|
return fmt.Sprintf(`"\\u%04X"`, code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readToken(s *source.Source, fromPosition int) (Token, error) {
|
||||||
|
body := s.Body
|
||||||
|
bodyLength := len(body)
|
||||||
|
position, runePosition := positionAfterWhitespace(body, fromPosition)
|
||||||
|
if position >= bodyLength {
|
||||||
|
return makeToken(TokenKind[EOF], position, position, ""), nil
|
||||||
|
}
|
||||||
|
code, codeLength := runeAt(body, position)
|
||||||
|
|
||||||
|
// SourceCharacter
|
||||||
|
if code < 0x0020 && code != 0x0009 && code != 0x000A && code != 0x000D {
|
||||||
|
return Token{}, gqlerrors.NewSyntaxError(s, runePosition, fmt.Sprintf(`Invalid character %v`, printCharCode(code)))
|
||||||
|
}
|
||||||
|
|
||||||
|
switch code {
|
||||||
|
// !
|
||||||
|
case '!':
|
||||||
|
return makeToken(TokenKind[BANG], position, position+1, ""), nil
|
||||||
|
// $
|
||||||
|
case '$':
|
||||||
|
return makeToken(TokenKind[DOLLAR], position, position+1, ""), nil
|
||||||
|
// (
|
||||||
|
case '(':
|
||||||
|
return makeToken(TokenKind[PAREN_L], position, position+1, ""), nil
|
||||||
|
// )
|
||||||
|
case ')':
|
||||||
|
return makeToken(TokenKind[PAREN_R], position, position+1, ""), nil
|
||||||
|
// .
|
||||||
|
case '.':
|
||||||
|
next1, _ := runeAt(body, position+1)
|
||||||
|
next2, _ := runeAt(body, position+2)
|
||||||
|
if next1 == '.' && next2 == '.' {
|
||||||
|
return makeToken(TokenKind[SPREAD], position, position+3, ""), nil
|
||||||
|
}
|
||||||
|
break
|
||||||
|
// :
|
||||||
|
case ':':
|
||||||
|
return makeToken(TokenKind[COLON], position, position+1, ""), nil
|
||||||
|
// =
|
||||||
|
case '=':
|
||||||
|
return makeToken(TokenKind[EQUALS], position, position+1, ""), nil
|
||||||
|
// @
|
||||||
|
case '@':
|
||||||
|
return makeToken(TokenKind[AT], position, position+1, ""), nil
|
||||||
|
// [
|
||||||
|
case '[':
|
||||||
|
return makeToken(TokenKind[BRACKET_L], position, position+1, ""), nil
|
||||||
|
// ]
|
||||||
|
case ']':
|
||||||
|
return makeToken(TokenKind[BRACKET_R], position, position+1, ""), nil
|
||||||
|
// {
|
||||||
|
case '{':
|
||||||
|
return makeToken(TokenKind[BRACE_L], position, position+1, ""), nil
|
||||||
|
// |
|
||||||
|
case '|':
|
||||||
|
return makeToken(TokenKind[PIPE], position, position+1, ""), nil
|
||||||
|
// }
|
||||||
|
case '}':
|
||||||
|
return makeToken(TokenKind[BRACE_R], position, position+1, ""), nil
|
||||||
|
// A-Z
|
||||||
|
case 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
|
||||||
|
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z':
|
||||||
|
return readName(s, position, runePosition), nil
|
||||||
|
// _
|
||||||
|
// a-z
|
||||||
|
case '_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||||
|
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z':
|
||||||
|
return readName(s, position, runePosition), nil
|
||||||
|
// -
|
||||||
|
// 0-9
|
||||||
|
case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||||
|
token, err := readNumber(s, position, code, codeLength)
|
||||||
|
if err != nil {
|
||||||
|
return token, err
|
||||||
|
}
|
||||||
|
return token, nil
|
||||||
|
// "
|
||||||
|
case '"':
|
||||||
|
var token Token
|
||||||
|
var err error
|
||||||
|
x, _ := runeAt(body, position+1)
|
||||||
|
y, _ := runeAt(body, position+2)
|
||||||
|
if x == '"' && y == '"' {
|
||||||
|
token, err = readBlockString(s, position)
|
||||||
|
} else {
|
||||||
|
token, err = readString(s, position)
|
||||||
|
}
|
||||||
|
return token, err
|
||||||
|
}
|
||||||
|
description := fmt.Sprintf("Unexpected character %v.", printCharCode(code))
|
||||||
|
return Token{}, gqlerrors.NewSyntaxError(s, runePosition, description)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets the rune from the byte array at given byte position and it's width in bytes
|
||||||
|
func runeAt(body []byte, position int) (code rune, charWidth int) {
|
||||||
|
if len(body) <= position {
|
||||||
|
// <EOF>
|
||||||
|
return -1, utf8.RuneError
|
||||||
|
}
|
||||||
|
|
||||||
|
c := body[position]
|
||||||
|
if c < utf8.RuneSelf {
|
||||||
|
return rune(c), 1
|
||||||
|
}
|
||||||
|
|
||||||
|
r, n := utf8.DecodeRune(body[position:])
|
||||||
|
return r, n
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reads from body starting at startPosition until it finds a non-whitespace
|
||||||
|
// or commented character, then returns the position of that character for lexing.
|
||||||
|
// lexing.
|
||||||
|
// Returns both byte positions and rune position
|
||||||
|
func positionAfterWhitespace(body []byte, startPosition int) (position int, runePosition int) {
|
||||||
|
bodyLength := len(body)
|
||||||
|
position = startPosition
|
||||||
|
runePosition = startPosition
|
||||||
|
for {
|
||||||
|
if position < bodyLength {
|
||||||
|
code, n := runeAt(body, position)
|
||||||
|
|
||||||
|
// Skip Ignored
|
||||||
|
if code == 0xFEFF || // BOM
|
||||||
|
// White Space
|
||||||
|
code == 0x0009 || // tab
|
||||||
|
code == 0x0020 || // space
|
||||||
|
// Line Terminator
|
||||||
|
code == 0x000A || // new line
|
||||||
|
code == 0x000D || // carriage return
|
||||||
|
// Comma
|
||||||
|
code == 0x002C {
|
||||||
|
position += n
|
||||||
|
runePosition++
|
||||||
|
} else if code == 35 { // #
|
||||||
|
position += n
|
||||||
|
runePosition++
|
||||||
|
for {
|
||||||
|
code, n := runeAt(body, position)
|
||||||
|
if position < bodyLength &&
|
||||||
|
code != 0 &&
|
||||||
|
// SourceCharacter but not LineTerminator
|
||||||
|
(code > 0x001F || code == 0x0009) && code != 0x000A && code != 0x000D {
|
||||||
|
position += n
|
||||||
|
runePosition++
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return position, runePosition
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetTokenDesc(token Token) string {
|
||||||
|
if token.Value == "" {
|
||||||
|
return GetTokenKindDesc(token.Kind)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s \"%s\"", GetTokenKindDesc(token.Kind), token.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetTokenKindDesc(kind int) string {
|
||||||
|
return tokenDescription[kind]
|
||||||
|
}
|
35
vendor/github.com/graphql-go/graphql/language/location/location.go
generated
vendored
Normal file
35
vendor/github.com/graphql-go/graphql/language/location/location.go
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package location
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
|
||||||
|
"github.com/graphql-go/graphql/language/source"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SourceLocation struct {
|
||||||
|
Line int `json:"line"`
|
||||||
|
Column int `json:"column"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetLocation(s *source.Source, position int) SourceLocation {
|
||||||
|
body := []byte{}
|
||||||
|
if s != nil {
|
||||||
|
body = s.Body
|
||||||
|
}
|
||||||
|
line := 1
|
||||||
|
column := position + 1
|
||||||
|
lineRegexp := regexp.MustCompile("\r\n|[\n\r]")
|
||||||
|
matches := lineRegexp.FindAllIndex(body, -1)
|
||||||
|
for _, match := range matches {
|
||||||
|
matchIndex := match[0]
|
||||||
|
if matchIndex < position {
|
||||||
|
line++
|
||||||
|
l := len(s.Body[match[0]:match[1]])
|
||||||
|
column = position + 1 - (matchIndex + l)
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SourceLocation{Line: line, Column: column}
|
||||||
|
}
|
1636
vendor/github.com/graphql-go/graphql/language/parser/parser.go
generated
vendored
Normal file
1636
vendor/github.com/graphql-go/graphql/language/parser/parser.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
821
vendor/github.com/graphql-go/graphql/language/printer/printer.go
generated
vendored
Normal file
821
vendor/github.com/graphql-go/graphql/language/printer/printer.go
generated
vendored
Normal file
@ -0,0 +1,821 @@
|
|||||||
|
package printer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/graphql-go/graphql/language/ast"
|
||||||
|
"github.com/graphql-go/graphql/language/visitor"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getMapValue(m map[string]interface{}, key string) interface{} {
|
||||||
|
tokens := strings.Split(key, ".")
|
||||||
|
valMap := m
|
||||||
|
for _, token := range tokens {
|
||||||
|
v, ok := valMap[token]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
switch v := v.(type) {
|
||||||
|
case []interface{}:
|
||||||
|
return v
|
||||||
|
case map[string]interface{}:
|
||||||
|
valMap = v
|
||||||
|
continue
|
||||||
|
default:
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return valMap
|
||||||
|
}
|
||||||
|
func getMapSliceValue(m map[string]interface{}, key string) []interface{} {
|
||||||
|
tokens := strings.Split(key, ".")
|
||||||
|
valMap := m
|
||||||
|
for _, token := range tokens {
|
||||||
|
v, ok := valMap[token]
|
||||||
|
if !ok {
|
||||||
|
return []interface{}{}
|
||||||
|
}
|
||||||
|
switch v := v.(type) {
|
||||||
|
case []interface{}:
|
||||||
|
return v
|
||||||
|
default:
|
||||||
|
return []interface{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return []interface{}{}
|
||||||
|
}
|
||||||
|
func getMapValueString(m map[string]interface{}, key string) string {
|
||||||
|
tokens := strings.Split(key, ".")
|
||||||
|
valMap := m
|
||||||
|
for _, token := range tokens {
|
||||||
|
v, ok := valMap[token]
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if v == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
switch v := v.(type) {
|
||||||
|
case map[string]interface{}:
|
||||||
|
valMap = v
|
||||||
|
continue
|
||||||
|
case string:
|
||||||
|
return v
|
||||||
|
default:
|
||||||
|
return fmt.Sprintf("%v", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func toSliceString(slice interface{}) []string {
|
||||||
|
if slice == nil {
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
res := []string{}
|
||||||
|
switch reflect.TypeOf(slice).Kind() {
|
||||||
|
case reflect.Slice:
|
||||||
|
s := reflect.ValueOf(slice)
|
||||||
|
for i := 0; i < s.Len(); i++ {
|
||||||
|
elem := s.Index(i)
|
||||||
|
elemInterface := elem.Interface()
|
||||||
|
if elem, ok := elemInterface.(string); ok {
|
||||||
|
res = append(res, elem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
default:
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func join(str []string, sep string) string {
|
||||||
|
ss := []string{}
|
||||||
|
// filter out empty strings
|
||||||
|
for _, s := range str {
|
||||||
|
if s == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ss = append(ss, s)
|
||||||
|
}
|
||||||
|
return strings.Join(ss, sep)
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrap(start, maybeString, end string) string {
|
||||||
|
if maybeString == "" {
|
||||||
|
return maybeString
|
||||||
|
}
|
||||||
|
return start + maybeString + end
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given array, print each item on its own line, wrapped in an indented "{ }" block.
|
||||||
|
func block(maybeArray interface{}) string {
|
||||||
|
s := toSliceString(maybeArray)
|
||||||
|
if len(s) == 0 {
|
||||||
|
return "{}"
|
||||||
|
}
|
||||||
|
return indent("{\n"+join(s, "\n")) + "\n}"
|
||||||
|
}
|
||||||
|
|
||||||
|
func indent(maybeString interface{}) string {
|
||||||
|
if maybeString == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
switch str := maybeString.(type) {
|
||||||
|
case string:
|
||||||
|
return strings.Replace(str, "\n", "\n ", -1)
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var printDocASTReducer = map[string]visitor.VisitFunc{
|
||||||
|
"Name": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.Name:
|
||||||
|
return visitor.ActionUpdate, node.Value
|
||||||
|
case map[string]interface{}:
|
||||||
|
return visitor.ActionUpdate, getMapValue(node, "Value")
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"Variable": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.Variable:
|
||||||
|
return visitor.ActionUpdate, fmt.Sprintf("$%v", node.Name)
|
||||||
|
case map[string]interface{}:
|
||||||
|
return visitor.ActionUpdate, "$" + getMapValueString(node, "Name")
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
|
||||||
|
// Document
|
||||||
|
"Document": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.Document:
|
||||||
|
definitions := toSliceString(node.Definitions)
|
||||||
|
return visitor.ActionUpdate, join(definitions, "\n\n") + "\n"
|
||||||
|
case map[string]interface{}:
|
||||||
|
definitions := toSliceString(getMapValue(node, "Definitions"))
|
||||||
|
return visitor.ActionUpdate, join(definitions, "\n\n") + "\n"
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"OperationDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.OperationDefinition:
|
||||||
|
op := string(node.Operation)
|
||||||
|
name := fmt.Sprintf("%v", node.Name)
|
||||||
|
|
||||||
|
varDefs := wrap("(", join(toSliceString(node.VariableDefinitions), ", "), ")")
|
||||||
|
directives := join(toSliceString(node.Directives), " ")
|
||||||
|
selectionSet := fmt.Sprintf("%v", node.SelectionSet)
|
||||||
|
// Anonymous queries with no directives or variable definitions can use
|
||||||
|
// the query short form.
|
||||||
|
str := ""
|
||||||
|
if name == "" && directives == "" && varDefs == "" && op == ast.OperationTypeQuery {
|
||||||
|
str = selectionSet
|
||||||
|
} else {
|
||||||
|
str = join([]string{
|
||||||
|
op,
|
||||||
|
join([]string{name, varDefs}, ""),
|
||||||
|
directives,
|
||||||
|
selectionSet,
|
||||||
|
}, " ")
|
||||||
|
}
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
case map[string]interface{}:
|
||||||
|
|
||||||
|
op := getMapValueString(node, "Operation")
|
||||||
|
name := getMapValueString(node, "Name")
|
||||||
|
|
||||||
|
varDefs := wrap("(", join(toSliceString(getMapValue(node, "VariableDefinitions")), ", "), ")")
|
||||||
|
directives := join(toSliceString(getMapValue(node, "Directives")), " ")
|
||||||
|
selectionSet := getMapValueString(node, "SelectionSet")
|
||||||
|
str := ""
|
||||||
|
if name == "" && directives == "" && varDefs == "" && op == ast.OperationTypeQuery {
|
||||||
|
str = selectionSet
|
||||||
|
} else {
|
||||||
|
str = join([]string{
|
||||||
|
op,
|
||||||
|
join([]string{name, varDefs}, ""),
|
||||||
|
directives,
|
||||||
|
selectionSet,
|
||||||
|
}, " ")
|
||||||
|
}
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"VariableDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.VariableDefinition:
|
||||||
|
variable := fmt.Sprintf("%v", node.Variable)
|
||||||
|
ttype := fmt.Sprintf("%v", node.Type)
|
||||||
|
defaultValue := fmt.Sprintf("%v", node.DefaultValue)
|
||||||
|
|
||||||
|
return visitor.ActionUpdate, variable + ": " + ttype + wrap(" = ", defaultValue, "")
|
||||||
|
case map[string]interface{}:
|
||||||
|
|
||||||
|
variable := getMapValueString(node, "Variable")
|
||||||
|
ttype := getMapValueString(node, "Type")
|
||||||
|
defaultValue := getMapValueString(node, "DefaultValue")
|
||||||
|
|
||||||
|
return visitor.ActionUpdate, variable + ": " + ttype + wrap(" = ", defaultValue, "")
|
||||||
|
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"SelectionSet": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.SelectionSet:
|
||||||
|
str := block(node.Selections)
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
case map[string]interface{}:
|
||||||
|
selections := getMapValue(node, "Selections")
|
||||||
|
str := block(selections)
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"Field": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.Argument:
|
||||||
|
name := fmt.Sprintf("%v", node.Name)
|
||||||
|
value := fmt.Sprintf("%v", node.Value)
|
||||||
|
return visitor.ActionUpdate, name + ": " + value
|
||||||
|
case map[string]interface{}:
|
||||||
|
|
||||||
|
alias := getMapValueString(node, "Alias")
|
||||||
|
name := getMapValueString(node, "Name")
|
||||||
|
args := toSliceString(getMapValue(node, "Arguments"))
|
||||||
|
directives := toSliceString(getMapValue(node, "Directives"))
|
||||||
|
selectionSet := getMapValueString(node, "SelectionSet")
|
||||||
|
|
||||||
|
str := join(
|
||||||
|
[]string{
|
||||||
|
wrap("", alias, ": ") + name + wrap("(", join(args, ", "), ")"),
|
||||||
|
join(directives, " "),
|
||||||
|
selectionSet,
|
||||||
|
},
|
||||||
|
" ",
|
||||||
|
)
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"Argument": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.FragmentSpread:
|
||||||
|
name := fmt.Sprintf("%v", node.Name)
|
||||||
|
directives := toSliceString(node.Directives)
|
||||||
|
return visitor.ActionUpdate, "..." + name + wrap(" ", join(directives, " "), "")
|
||||||
|
case map[string]interface{}:
|
||||||
|
name := getMapValueString(node, "Name")
|
||||||
|
value := getMapValueString(node, "Value")
|
||||||
|
return visitor.ActionUpdate, name + ": " + value
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
|
||||||
|
// Fragments
|
||||||
|
"FragmentSpread": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.InlineFragment:
|
||||||
|
typeCondition := fmt.Sprintf("%v", node.TypeCondition)
|
||||||
|
directives := toSliceString(node.Directives)
|
||||||
|
selectionSet := fmt.Sprintf("%v", node.SelectionSet)
|
||||||
|
return visitor.ActionUpdate, "... on " + typeCondition + " " + wrap("", join(directives, " "), " ") + selectionSet
|
||||||
|
case map[string]interface{}:
|
||||||
|
name := getMapValueString(node, "Name")
|
||||||
|
directives := toSliceString(getMapValue(node, "Directives"))
|
||||||
|
return visitor.ActionUpdate, "..." + name + wrap(" ", join(directives, " "), "")
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"InlineFragment": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case map[string]interface{}:
|
||||||
|
typeCondition := getMapValueString(node, "TypeCondition")
|
||||||
|
directives := toSliceString(getMapValue(node, "Directives"))
|
||||||
|
selectionSet := getMapValueString(node, "SelectionSet")
|
||||||
|
return visitor.ActionUpdate,
|
||||||
|
join([]string{
|
||||||
|
"...",
|
||||||
|
wrap("on ", typeCondition, ""),
|
||||||
|
join(directives, " "),
|
||||||
|
selectionSet,
|
||||||
|
}, " ")
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"FragmentDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.FragmentDefinition:
|
||||||
|
name := fmt.Sprintf("%v", node.Name)
|
||||||
|
typeCondition := fmt.Sprintf("%v", node.TypeCondition)
|
||||||
|
directives := toSliceString(node.Directives)
|
||||||
|
selectionSet := fmt.Sprintf("%v", node.SelectionSet)
|
||||||
|
return visitor.ActionUpdate, "fragment " + name + " on " + typeCondition + " " + wrap("", join(directives, " "), " ") + selectionSet
|
||||||
|
case map[string]interface{}:
|
||||||
|
name := getMapValueString(node, "Name")
|
||||||
|
typeCondition := getMapValueString(node, "TypeCondition")
|
||||||
|
directives := toSliceString(getMapValue(node, "Directives"))
|
||||||
|
selectionSet := getMapValueString(node, "SelectionSet")
|
||||||
|
return visitor.ActionUpdate, "fragment " + name + " on " + typeCondition + " " + wrap("", join(directives, " "), " ") + selectionSet
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
|
||||||
|
// Value
|
||||||
|
"IntValue": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.IntValue:
|
||||||
|
return visitor.ActionUpdate, fmt.Sprintf("%v", node.Value)
|
||||||
|
case map[string]interface{}:
|
||||||
|
return visitor.ActionUpdate, getMapValueString(node, "Value")
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"FloatValue": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.FloatValue:
|
||||||
|
return visitor.ActionUpdate, fmt.Sprintf("%v", node.Value)
|
||||||
|
case map[string]interface{}:
|
||||||
|
return visitor.ActionUpdate, getMapValueString(node, "Value")
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"StringValue": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.StringValue:
|
||||||
|
return visitor.ActionUpdate, `"` + fmt.Sprintf("%v", node.Value) + `"`
|
||||||
|
case map[string]interface{}:
|
||||||
|
return visitor.ActionUpdate, `"` + getMapValueString(node, "Value") + `"`
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"BooleanValue": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.BooleanValue:
|
||||||
|
return visitor.ActionUpdate, fmt.Sprintf("%v", node.Value)
|
||||||
|
case map[string]interface{}:
|
||||||
|
return visitor.ActionUpdate, getMapValueString(node, "Value")
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"EnumValue": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.EnumValue:
|
||||||
|
return visitor.ActionUpdate, fmt.Sprintf("%v", node.Value)
|
||||||
|
case map[string]interface{}:
|
||||||
|
return visitor.ActionUpdate, getMapValueString(node, "Value")
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"ListValue": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.ListValue:
|
||||||
|
return visitor.ActionUpdate, "[" + join(toSliceString(node.Values), ", ") + "]"
|
||||||
|
case map[string]interface{}:
|
||||||
|
return visitor.ActionUpdate, "[" + join(toSliceString(getMapValue(node, "Values")), ", ") + "]"
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"ObjectValue": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.ObjectValue:
|
||||||
|
return visitor.ActionUpdate, "{" + join(toSliceString(node.Fields), ", ") + "}"
|
||||||
|
case map[string]interface{}:
|
||||||
|
return visitor.ActionUpdate, "{" + join(toSliceString(getMapValue(node, "Fields")), ", ") + "}"
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"ObjectField": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.ObjectField:
|
||||||
|
name := fmt.Sprintf("%v", node.Name)
|
||||||
|
value := fmt.Sprintf("%v", node.Value)
|
||||||
|
return visitor.ActionUpdate, name + ": " + value
|
||||||
|
case map[string]interface{}:
|
||||||
|
name := getMapValueString(node, "Name")
|
||||||
|
value := getMapValueString(node, "Value")
|
||||||
|
return visitor.ActionUpdate, name + ": " + value
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
|
||||||
|
// Directive
|
||||||
|
"Directive": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.Directive:
|
||||||
|
name := fmt.Sprintf("%v", node.Name)
|
||||||
|
args := toSliceString(node.Arguments)
|
||||||
|
return visitor.ActionUpdate, "@" + name + wrap("(", join(args, ", "), ")")
|
||||||
|
case map[string]interface{}:
|
||||||
|
name := getMapValueString(node, "Name")
|
||||||
|
args := toSliceString(getMapValue(node, "Arguments"))
|
||||||
|
return visitor.ActionUpdate, "@" + name + wrap("(", join(args, ", "), ")")
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
|
||||||
|
// Type
|
||||||
|
"Named": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.Named:
|
||||||
|
return visitor.ActionUpdate, fmt.Sprintf("%v", node.Name)
|
||||||
|
case map[string]interface{}:
|
||||||
|
return visitor.ActionUpdate, getMapValueString(node, "Name")
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"List": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.List:
|
||||||
|
return visitor.ActionUpdate, "[" + fmt.Sprintf("%v", node.Type) + "]"
|
||||||
|
case map[string]interface{}:
|
||||||
|
return visitor.ActionUpdate, "[" + getMapValueString(node, "Type") + "]"
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"NonNull": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.NonNull:
|
||||||
|
return visitor.ActionUpdate, fmt.Sprintf("%v", node.Type) + "!"
|
||||||
|
case map[string]interface{}:
|
||||||
|
return visitor.ActionUpdate, getMapValueString(node, "Type") + "!"
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
|
||||||
|
// Type System Definitions
|
||||||
|
"SchemaDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.SchemaDefinition:
|
||||||
|
directives := []string{}
|
||||||
|
for _, directive := range node.Directives {
|
||||||
|
directives = append(directives, fmt.Sprintf("%v", directive.Name))
|
||||||
|
}
|
||||||
|
str := join([]string{
|
||||||
|
"schema",
|
||||||
|
join(directives, " "),
|
||||||
|
block(node.OperationTypes),
|
||||||
|
}, " ")
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
case map[string]interface{}:
|
||||||
|
operationTypes := toSliceString(getMapValue(node, "OperationTypes"))
|
||||||
|
directives := []string{}
|
||||||
|
for _, directive := range getMapSliceValue(node, "Directives") {
|
||||||
|
directives = append(directives, fmt.Sprintf("%v", directive))
|
||||||
|
}
|
||||||
|
str := join([]string{
|
||||||
|
"schema",
|
||||||
|
join(directives, " "),
|
||||||
|
block(operationTypes),
|
||||||
|
}, " ")
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"OperationTypeDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.OperationTypeDefinition:
|
||||||
|
str := fmt.Sprintf("%v: %v", node.Operation, node.Type)
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
case map[string]interface{}:
|
||||||
|
operation := getMapValueString(node, "Operation")
|
||||||
|
ttype := getMapValueString(node, "Type")
|
||||||
|
str := fmt.Sprintf("%v: %v", operation, ttype)
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"ScalarDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.ScalarDefinition:
|
||||||
|
directives := []string{}
|
||||||
|
for _, directive := range node.Directives {
|
||||||
|
directives = append(directives, fmt.Sprintf("%v", directive.Name))
|
||||||
|
}
|
||||||
|
str := join([]string{
|
||||||
|
"scalar",
|
||||||
|
fmt.Sprintf("%v", node.Name),
|
||||||
|
join(directives, " "),
|
||||||
|
}, " ")
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
case map[string]interface{}:
|
||||||
|
name := getMapValueString(node, "Name")
|
||||||
|
directives := []string{}
|
||||||
|
for _, directive := range getMapSliceValue(node, "Directives") {
|
||||||
|
directives = append(directives, fmt.Sprintf("%v", directive))
|
||||||
|
}
|
||||||
|
str := join([]string{
|
||||||
|
"scalar",
|
||||||
|
name,
|
||||||
|
join(directives, " "),
|
||||||
|
}, " ")
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"ObjectDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.ObjectDefinition:
|
||||||
|
name := fmt.Sprintf("%v", node.Name)
|
||||||
|
interfaces := toSliceString(node.Interfaces)
|
||||||
|
fields := node.Fields
|
||||||
|
directives := []string{}
|
||||||
|
for _, directive := range node.Directives {
|
||||||
|
directives = append(directives, fmt.Sprintf("%v", directive.Name))
|
||||||
|
}
|
||||||
|
str := join([]string{
|
||||||
|
"type",
|
||||||
|
name,
|
||||||
|
wrap("implements ", join(interfaces, ", "), ""),
|
||||||
|
join(directives, " "),
|
||||||
|
block(fields),
|
||||||
|
}, " ")
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
case map[string]interface{}:
|
||||||
|
name := getMapValueString(node, "Name")
|
||||||
|
interfaces := toSliceString(getMapValue(node, "Interfaces"))
|
||||||
|
fields := getMapValue(node, "Fields")
|
||||||
|
directives := []string{}
|
||||||
|
for _, directive := range getMapSliceValue(node, "Directives") {
|
||||||
|
directives = append(directives, fmt.Sprintf("%v", directive))
|
||||||
|
}
|
||||||
|
str := join([]string{
|
||||||
|
"type",
|
||||||
|
name,
|
||||||
|
wrap("implements ", join(interfaces, ", "), ""),
|
||||||
|
join(directives, " "),
|
||||||
|
block(fields),
|
||||||
|
}, " ")
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"FieldDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.FieldDefinition:
|
||||||
|
name := fmt.Sprintf("%v", node.Name)
|
||||||
|
ttype := fmt.Sprintf("%v", node.Type)
|
||||||
|
args := toSliceString(node.Arguments)
|
||||||
|
directives := []string{}
|
||||||
|
for _, directive := range node.Directives {
|
||||||
|
directives = append(directives, fmt.Sprintf("%v", directive.Name))
|
||||||
|
}
|
||||||
|
str := name + wrap("(", join(args, ", "), ")") + ": " + ttype + wrap(" ", join(directives, " "), "")
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
case map[string]interface{}:
|
||||||
|
name := getMapValueString(node, "Name")
|
||||||
|
ttype := getMapValueString(node, "Type")
|
||||||
|
args := toSliceString(getMapValue(node, "Arguments"))
|
||||||
|
directives := []string{}
|
||||||
|
for _, directive := range getMapSliceValue(node, "Directives") {
|
||||||
|
directives = append(directives, fmt.Sprintf("%v", directive))
|
||||||
|
}
|
||||||
|
str := name + wrap("(", join(args, ", "), ")") + ": " + ttype + wrap(" ", join(directives, " "), "")
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"InputValueDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.InputValueDefinition:
|
||||||
|
name := fmt.Sprintf("%v", node.Name)
|
||||||
|
ttype := fmt.Sprintf("%v", node.Type)
|
||||||
|
defaultValue := fmt.Sprintf("%v", node.DefaultValue)
|
||||||
|
directives := []string{}
|
||||||
|
for _, directive := range node.Directives {
|
||||||
|
directives = append(directives, fmt.Sprintf("%v", directive.Name))
|
||||||
|
}
|
||||||
|
str := join([]string{
|
||||||
|
name + ": " + ttype,
|
||||||
|
wrap("= ", defaultValue, ""),
|
||||||
|
join(directives, " "),
|
||||||
|
}, " ")
|
||||||
|
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
case map[string]interface{}:
|
||||||
|
name := getMapValueString(node, "Name")
|
||||||
|
ttype := getMapValueString(node, "Type")
|
||||||
|
defaultValue := getMapValueString(node, "DefaultValue")
|
||||||
|
directives := []string{}
|
||||||
|
for _, directive := range getMapSliceValue(node, "Directives") {
|
||||||
|
directives = append(directives, fmt.Sprintf("%v", directive))
|
||||||
|
}
|
||||||
|
str := join([]string{
|
||||||
|
name + ": " + ttype,
|
||||||
|
wrap("= ", defaultValue, ""),
|
||||||
|
join(directives, " "),
|
||||||
|
}, " ")
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"InterfaceDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.InterfaceDefinition:
|
||||||
|
name := fmt.Sprintf("%v", node.Name)
|
||||||
|
fields := node.Fields
|
||||||
|
directives := []string{}
|
||||||
|
for _, directive := range node.Directives {
|
||||||
|
directives = append(directives, fmt.Sprintf("%v", directive.Name))
|
||||||
|
}
|
||||||
|
str := join([]string{
|
||||||
|
"interface",
|
||||||
|
name,
|
||||||
|
join(directives, " "),
|
||||||
|
block(fields),
|
||||||
|
}, " ")
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
case map[string]interface{}:
|
||||||
|
name := getMapValueString(node, "Name")
|
||||||
|
fields := getMapValue(node, "Fields")
|
||||||
|
directives := []string{}
|
||||||
|
for _, directive := range getMapSliceValue(node, "Directives") {
|
||||||
|
directives = append(directives, fmt.Sprintf("%v", directive))
|
||||||
|
}
|
||||||
|
str := join([]string{
|
||||||
|
"interface",
|
||||||
|
name,
|
||||||
|
join(directives, " "),
|
||||||
|
block(fields),
|
||||||
|
}, " ")
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"UnionDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.UnionDefinition:
|
||||||
|
name := fmt.Sprintf("%v", node.Name)
|
||||||
|
types := toSliceString(node.Types)
|
||||||
|
directives := []string{}
|
||||||
|
for _, directive := range node.Directives {
|
||||||
|
directives = append(directives, fmt.Sprintf("%v", directive.Name))
|
||||||
|
}
|
||||||
|
str := join([]string{
|
||||||
|
"union",
|
||||||
|
name,
|
||||||
|
join(directives, " "),
|
||||||
|
"= " + join(types, " | "),
|
||||||
|
}, " ")
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
case map[string]interface{}:
|
||||||
|
name := getMapValueString(node, "Name")
|
||||||
|
types := toSliceString(getMapValue(node, "Types"))
|
||||||
|
directives := []string{}
|
||||||
|
for _, directive := range getMapSliceValue(node, "Directives") {
|
||||||
|
directives = append(directives, fmt.Sprintf("%v", directive))
|
||||||
|
}
|
||||||
|
str := join([]string{
|
||||||
|
"union",
|
||||||
|
name,
|
||||||
|
join(directives, " "),
|
||||||
|
"= " + join(types, " | "),
|
||||||
|
}, " ")
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"EnumDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.EnumDefinition:
|
||||||
|
name := fmt.Sprintf("%v", node.Name)
|
||||||
|
values := node.Values
|
||||||
|
directives := []string{}
|
||||||
|
for _, directive := range node.Directives {
|
||||||
|
directives = append(directives, fmt.Sprintf("%v", directive.Name))
|
||||||
|
}
|
||||||
|
str := join([]string{
|
||||||
|
"enum",
|
||||||
|
name,
|
||||||
|
join(directives, " "),
|
||||||
|
block(values),
|
||||||
|
}, " ")
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
case map[string]interface{}:
|
||||||
|
name := getMapValueString(node, "Name")
|
||||||
|
values := getMapValue(node, "Values")
|
||||||
|
directives := []string{}
|
||||||
|
for _, directive := range getMapSliceValue(node, "Directives") {
|
||||||
|
directives = append(directives, fmt.Sprintf("%v", directive))
|
||||||
|
}
|
||||||
|
str := join([]string{
|
||||||
|
"enum",
|
||||||
|
name,
|
||||||
|
join(directives, " "),
|
||||||
|
block(values),
|
||||||
|
}, " ")
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"EnumValueDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.EnumValueDefinition:
|
||||||
|
name := fmt.Sprintf("%v", node.Name)
|
||||||
|
directives := []string{}
|
||||||
|
for _, directive := range node.Directives {
|
||||||
|
directives = append(directives, fmt.Sprintf("%v", directive.Name))
|
||||||
|
}
|
||||||
|
str := join([]string{
|
||||||
|
name,
|
||||||
|
join(directives, " "),
|
||||||
|
}, " ")
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
case map[string]interface{}:
|
||||||
|
name := getMapValueString(node, "Name")
|
||||||
|
directives := []string{}
|
||||||
|
for _, directive := range getMapSliceValue(node, "Directives") {
|
||||||
|
directives = append(directives, fmt.Sprintf("%v", directive))
|
||||||
|
}
|
||||||
|
str := join([]string{
|
||||||
|
name,
|
||||||
|
join(directives, " "),
|
||||||
|
}, " ")
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"InputObjectDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.InputObjectDefinition:
|
||||||
|
name := fmt.Sprintf("%v", node.Name)
|
||||||
|
fields := node.Fields
|
||||||
|
directives := []string{}
|
||||||
|
for _, directive := range node.Directives {
|
||||||
|
directives = append(directives, fmt.Sprintf("%v", directive.Name))
|
||||||
|
}
|
||||||
|
str := join([]string{
|
||||||
|
"input",
|
||||||
|
name,
|
||||||
|
join(directives, " "),
|
||||||
|
block(fields),
|
||||||
|
}, " ")
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
case map[string]interface{}:
|
||||||
|
name := getMapValueString(node, "Name")
|
||||||
|
fields := getMapValue(node, "Fields")
|
||||||
|
directives := []string{}
|
||||||
|
for _, directive := range getMapSliceValue(node, "Directives") {
|
||||||
|
directives = append(directives, fmt.Sprintf("%v", directive))
|
||||||
|
}
|
||||||
|
str := join([]string{
|
||||||
|
"input",
|
||||||
|
name,
|
||||||
|
join(directives, " "),
|
||||||
|
block(fields),
|
||||||
|
}, " ")
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"TypeExtensionDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.TypeExtensionDefinition:
|
||||||
|
definition := fmt.Sprintf("%v", node.Definition)
|
||||||
|
str := "extend " + definition
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
case map[string]interface{}:
|
||||||
|
definition := getMapValueString(node, "Definition")
|
||||||
|
str := "extend " + definition
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
"DirectiveDefinition": func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case *ast.DirectiveDefinition:
|
||||||
|
args := wrap("(", join(toSliceString(node.Arguments), ", "), ")")
|
||||||
|
str := fmt.Sprintf("directive @%v%v on %v", node.Name, args, join(toSliceString(node.Locations), " | "))
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
case map[string]interface{}:
|
||||||
|
name := getMapValueString(node, "Name")
|
||||||
|
locations := toSliceString(getMapValue(node, "Locations"))
|
||||||
|
args := toSliceString(getMapValue(node, "Arguments"))
|
||||||
|
argsStr := wrap("(", join(args, ", "), ")")
|
||||||
|
str := fmt.Sprintf("directive @%v%v on %v", name, argsStr, join(locations, " | "))
|
||||||
|
return visitor.ActionUpdate, str
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func Print(astNode ast.Node) (printed interface{}) {
|
||||||
|
defer func() interface{} {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
return fmt.Sprintf("%v", astNode)
|
||||||
|
}
|
||||||
|
return printed
|
||||||
|
}()
|
||||||
|
printed = visitor.Visit(astNode, &visitor.VisitorOptions{
|
||||||
|
LeaveKindMap: printDocASTReducer,
|
||||||
|
}, nil)
|
||||||
|
return printed
|
||||||
|
}
|
20
vendor/github.com/graphql-go/graphql/language/source/source.go
generated
vendored
Normal file
20
vendor/github.com/graphql-go/graphql/language/source/source.go
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package source
|
||||||
|
|
||||||
|
const (
|
||||||
|
name = "GraphQL"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Source struct {
|
||||||
|
Body []byte
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSource(s *Source) *Source {
|
||||||
|
if s == nil {
|
||||||
|
s = &Source{Name: name}
|
||||||
|
}
|
||||||
|
if s.Name == "" {
|
||||||
|
s.Name = name
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
11
vendor/github.com/graphql-go/graphql/language/typeInfo/type_info.go
generated
vendored
Normal file
11
vendor/github.com/graphql-go/graphql/language/typeInfo/type_info.go
generated
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package typeInfo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/graphql-go/graphql/language/ast"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TypeInfoI defines the interface for TypeInfo Implementation
|
||||||
|
type TypeInfoI interface {
|
||||||
|
Enter(node ast.Node)
|
||||||
|
Leave(node ast.Node)
|
||||||
|
}
|
873
vendor/github.com/graphql-go/graphql/language/visitor/visitor.go
generated
vendored
Normal file
873
vendor/github.com/graphql-go/graphql/language/visitor/visitor.go
generated
vendored
Normal file
@ -0,0 +1,873 @@
|
|||||||
|
package visitor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/graphql-go/graphql/language/ast"
|
||||||
|
"github.com/graphql-go/graphql/language/typeInfo"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ActionNoChange = ""
|
||||||
|
ActionBreak = "BREAK"
|
||||||
|
ActionSkip = "SKIP"
|
||||||
|
ActionUpdate = "UPDATE"
|
||||||
|
)
|
||||||
|
|
||||||
|
type KeyMap map[string][]string
|
||||||
|
|
||||||
|
// note that the keys are in Capital letters, equivalent to the ast.Node field Names
|
||||||
|
var QueryDocumentKeys = KeyMap{
|
||||||
|
"Name": []string{},
|
||||||
|
"Document": []string{"Definitions"},
|
||||||
|
"OperationDefinition": []string{
|
||||||
|
"Name",
|
||||||
|
"VariableDefinitions",
|
||||||
|
"Directives",
|
||||||
|
"SelectionSet",
|
||||||
|
},
|
||||||
|
"VariableDefinition": []string{
|
||||||
|
"Variable",
|
||||||
|
"Type",
|
||||||
|
"DefaultValue",
|
||||||
|
},
|
||||||
|
"Variable": []string{"Name"},
|
||||||
|
"SelectionSet": []string{"Selections"},
|
||||||
|
"Field": []string{
|
||||||
|
"Alias",
|
||||||
|
"Name",
|
||||||
|
"Arguments",
|
||||||
|
"Directives",
|
||||||
|
"SelectionSet",
|
||||||
|
},
|
||||||
|
"Argument": []string{
|
||||||
|
"Name",
|
||||||
|
"Value",
|
||||||
|
},
|
||||||
|
|
||||||
|
"FragmentSpread": []string{
|
||||||
|
"Name",
|
||||||
|
"Directives",
|
||||||
|
},
|
||||||
|
"InlineFragment": []string{
|
||||||
|
"TypeCondition",
|
||||||
|
"Directives",
|
||||||
|
"SelectionSet",
|
||||||
|
},
|
||||||
|
"FragmentDefinition": []string{
|
||||||
|
"Name",
|
||||||
|
"TypeCondition",
|
||||||
|
"Directives",
|
||||||
|
"SelectionSet",
|
||||||
|
},
|
||||||
|
|
||||||
|
"IntValue": []string{},
|
||||||
|
"FloatValue": []string{},
|
||||||
|
"StringValue": []string{},
|
||||||
|
"BooleanValue": []string{},
|
||||||
|
"EnumValue": []string{},
|
||||||
|
"ListValue": []string{"Values"},
|
||||||
|
"ObjectValue": []string{"Fields"},
|
||||||
|
"ObjectField": []string{
|
||||||
|
"Name",
|
||||||
|
"Value",
|
||||||
|
},
|
||||||
|
|
||||||
|
"Directive": []string{
|
||||||
|
"Name",
|
||||||
|
"Arguments",
|
||||||
|
},
|
||||||
|
|
||||||
|
"Named": []string{"Name"},
|
||||||
|
"List": []string{"Type"},
|
||||||
|
"NonNull": []string{"Type"},
|
||||||
|
|
||||||
|
"SchemaDefinition": []string{
|
||||||
|
"Directives",
|
||||||
|
"OperationTypes",
|
||||||
|
},
|
||||||
|
"OperationTypeDefinition": []string{"Type"},
|
||||||
|
|
||||||
|
"ScalarDefinition": []string{
|
||||||
|
"Name",
|
||||||
|
"Directives",
|
||||||
|
},
|
||||||
|
"ObjectDefinition": []string{
|
||||||
|
"Name",
|
||||||
|
"Interfaces",
|
||||||
|
"Directives",
|
||||||
|
"Fields",
|
||||||
|
},
|
||||||
|
"FieldDefinition": []string{
|
||||||
|
"Name",
|
||||||
|
"Arguments",
|
||||||
|
"Type",
|
||||||
|
"Directives",
|
||||||
|
},
|
||||||
|
"InputValueDefinition": []string{
|
||||||
|
"Name",
|
||||||
|
"Type",
|
||||||
|
"DefaultValue",
|
||||||
|
"Directives",
|
||||||
|
},
|
||||||
|
"InterfaceDefinition": []string{
|
||||||
|
"Name",
|
||||||
|
"Directives",
|
||||||
|
"Fields",
|
||||||
|
},
|
||||||
|
"UnionDefinition": []string{
|
||||||
|
"Name",
|
||||||
|
"Directives",
|
||||||
|
"Types",
|
||||||
|
},
|
||||||
|
"EnumDefinition": []string{
|
||||||
|
"Name",
|
||||||
|
"Directives",
|
||||||
|
"Values",
|
||||||
|
},
|
||||||
|
"EnumValueDefinition": []string{
|
||||||
|
"Name",
|
||||||
|
"Directives",
|
||||||
|
},
|
||||||
|
"InputObjectDefinition": []string{
|
||||||
|
"Name",
|
||||||
|
"Directives",
|
||||||
|
"Fields",
|
||||||
|
},
|
||||||
|
|
||||||
|
"TypeExtensionDefinition": []string{"Definition"},
|
||||||
|
|
||||||
|
"DirectiveDefinition": []string{"Name", "Arguments", "Locations"},
|
||||||
|
}
|
||||||
|
|
||||||
|
type stack struct {
|
||||||
|
Index int
|
||||||
|
Keys []interface{}
|
||||||
|
Edits []*edit
|
||||||
|
inSlice bool
|
||||||
|
Prev *stack
|
||||||
|
}
|
||||||
|
type edit struct {
|
||||||
|
Key interface{}
|
||||||
|
Value interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type VisitFuncParams struct {
|
||||||
|
Node interface{}
|
||||||
|
Key interface{}
|
||||||
|
Parent ast.Node
|
||||||
|
Path []interface{}
|
||||||
|
Ancestors []ast.Node
|
||||||
|
}
|
||||||
|
|
||||||
|
type VisitFunc func(p VisitFuncParams) (string, interface{})
|
||||||
|
|
||||||
|
type NamedVisitFuncs struct {
|
||||||
|
Kind VisitFunc // 1) Named visitors triggered when entering a node a specific kind.
|
||||||
|
Leave VisitFunc // 2) Named visitors that trigger upon entering and leaving a node of
|
||||||
|
Enter VisitFunc // 2) Named visitors that trigger upon entering and leaving a node of
|
||||||
|
}
|
||||||
|
|
||||||
|
type VisitorOptions struct {
|
||||||
|
KindFuncMap map[string]NamedVisitFuncs
|
||||||
|
Enter VisitFunc // 3) Generic visitors that trigger upon entering and leaving any node.
|
||||||
|
Leave VisitFunc // 3) Generic visitors that trigger upon entering and leaving any node.
|
||||||
|
|
||||||
|
EnterKindMap map[string]VisitFunc // 4) Parallel visitors for entering and leaving nodes of a specific kind
|
||||||
|
LeaveKindMap map[string]VisitFunc // 4) Parallel visitors for entering and leaving nodes of a specific kind
|
||||||
|
}
|
||||||
|
|
||||||
|
func Visit(root ast.Node, visitorOpts *VisitorOptions, keyMap KeyMap) interface{} {
|
||||||
|
visitorKeys := keyMap
|
||||||
|
if visitorKeys == nil {
|
||||||
|
visitorKeys = QueryDocumentKeys
|
||||||
|
}
|
||||||
|
|
||||||
|
var result interface{}
|
||||||
|
var newRoot = root
|
||||||
|
var sstack *stack
|
||||||
|
var parent interface{}
|
||||||
|
var parentSlice []interface{}
|
||||||
|
inSlice := false
|
||||||
|
prevInSlice := false
|
||||||
|
keys := []interface{}{newRoot}
|
||||||
|
index := -1
|
||||||
|
edits := []*edit{}
|
||||||
|
path := []interface{}{}
|
||||||
|
ancestors := []interface{}{}
|
||||||
|
ancestorsSlice := [][]interface{}{}
|
||||||
|
Loop:
|
||||||
|
for {
|
||||||
|
index = index + 1
|
||||||
|
|
||||||
|
isLeaving := (len(keys) == index)
|
||||||
|
var key interface{} // string for structs or int for slices
|
||||||
|
var node interface{} // ast.Node or can be anything
|
||||||
|
var nodeSlice []interface{}
|
||||||
|
isEdited := (isLeaving && len(edits) != 0)
|
||||||
|
|
||||||
|
if isLeaving {
|
||||||
|
if !inSlice {
|
||||||
|
if len(ancestors) == 0 {
|
||||||
|
key = nil
|
||||||
|
} else {
|
||||||
|
key, path = pop(path)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if len(ancestorsSlice) == 0 {
|
||||||
|
key = nil
|
||||||
|
} else {
|
||||||
|
key, path = pop(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
node = parent
|
||||||
|
parent, ancestors = pop(ancestors)
|
||||||
|
nodeSlice = parentSlice
|
||||||
|
parentSlice, ancestorsSlice = popNodeSlice(ancestorsSlice)
|
||||||
|
|
||||||
|
if isEdited {
|
||||||
|
prevInSlice = inSlice
|
||||||
|
editOffset := 0
|
||||||
|
for _, edit := range edits {
|
||||||
|
arrayEditKey := 0
|
||||||
|
if inSlice {
|
||||||
|
keyInt := edit.Key.(int)
|
||||||
|
edit.Key = keyInt - editOffset
|
||||||
|
arrayEditKey = edit.Key.(int)
|
||||||
|
}
|
||||||
|
if inSlice && isNilNode(edit.Value) {
|
||||||
|
nodeSlice = spliceNode(nodeSlice, arrayEditKey)
|
||||||
|
editOffset = editOffset + 1
|
||||||
|
} else {
|
||||||
|
if inSlice {
|
||||||
|
nodeSlice[arrayEditKey] = edit.Value
|
||||||
|
} else {
|
||||||
|
key, _ := edit.Key.(string)
|
||||||
|
|
||||||
|
var updatedNode interface{}
|
||||||
|
if !isSlice(edit.Value) {
|
||||||
|
if isStructNode(edit.Value) {
|
||||||
|
updatedNode = updateNodeField(node, key, edit.Value)
|
||||||
|
} else {
|
||||||
|
var todoNode map[string]interface{}
|
||||||
|
b, err := json.Marshal(node)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("Invalid root AST Node: %v", root))
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(b, &todoNode)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("Invalid root AST Node (2): %v", root))
|
||||||
|
}
|
||||||
|
todoNode[key] = edit.Value
|
||||||
|
updatedNode = todoNode
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
isSliceOfNodes := true
|
||||||
|
|
||||||
|
// check if edit.value slice is ast.nodes
|
||||||
|
switch reflect.TypeOf(edit.Value).Kind() {
|
||||||
|
case reflect.Slice:
|
||||||
|
s := reflect.ValueOf(edit.Value)
|
||||||
|
for i := 0; i < s.Len(); i++ {
|
||||||
|
elem := s.Index(i)
|
||||||
|
if !isStructNode(elem.Interface()) {
|
||||||
|
isSliceOfNodes = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// is a slice of real nodes
|
||||||
|
if isSliceOfNodes {
|
||||||
|
// the node we are writing to is an ast.Node
|
||||||
|
updatedNode = updateNodeField(node, key, edit.Value)
|
||||||
|
} else {
|
||||||
|
var todoNode map[string]interface{}
|
||||||
|
b, err := json.Marshal(node)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("Invalid root AST Node: %v", root))
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(b, &todoNode)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("Invalid root AST Node (2): %v", root))
|
||||||
|
}
|
||||||
|
todoNode[key] = edit.Value
|
||||||
|
updatedNode = todoNode
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
node = updatedNode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index = sstack.Index
|
||||||
|
keys = sstack.Keys
|
||||||
|
edits = sstack.Edits
|
||||||
|
inSlice = sstack.inSlice
|
||||||
|
sstack = sstack.Prev
|
||||||
|
} else {
|
||||||
|
// get key
|
||||||
|
if !inSlice {
|
||||||
|
if !isNilNode(parent) {
|
||||||
|
key = getFieldValue(keys, index)
|
||||||
|
} else {
|
||||||
|
// initial conditions
|
||||||
|
key = nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
key = index
|
||||||
|
}
|
||||||
|
// get node
|
||||||
|
if !inSlice {
|
||||||
|
if !isNilNode(parent) {
|
||||||
|
fieldValue := getFieldValue(parent, key)
|
||||||
|
if isNode(fieldValue) {
|
||||||
|
node = fieldValue.(ast.Node)
|
||||||
|
}
|
||||||
|
if isSlice(fieldValue) {
|
||||||
|
nodeSlice = toSliceInterfaces(fieldValue)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// initial conditions
|
||||||
|
node = newRoot
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if len(parentSlice) != 0 {
|
||||||
|
fieldValue := getFieldValue(parentSlice, key)
|
||||||
|
if isNode(fieldValue) {
|
||||||
|
node = fieldValue.(ast.Node)
|
||||||
|
}
|
||||||
|
if isSlice(fieldValue) {
|
||||||
|
nodeSlice = toSliceInterfaces(fieldValue)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// initial conditions
|
||||||
|
nodeSlice = []interface{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if isNilNode(node) && len(nodeSlice) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !inSlice {
|
||||||
|
if !isNilNode(parent) {
|
||||||
|
path = append(path, key)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if len(parentSlice) != 0 {
|
||||||
|
path = append(path, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get result from visitFn for a node if set
|
||||||
|
var result interface{}
|
||||||
|
resultIsUndefined := true
|
||||||
|
if !isNilNode(node) {
|
||||||
|
if !isNode(node) { // is node-ish.
|
||||||
|
panic(fmt.Sprintf("Invalid AST Node (4): %v", node))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to pass in current node as ast.Node
|
||||||
|
// Note that since user can potentially return a non-ast.Node from visit functions.
|
||||||
|
// In that case, we try to unmarshal map[string]interface{} into ast.Node
|
||||||
|
var nodeIn interface{}
|
||||||
|
if _, ok := node.(map[string]interface{}); ok {
|
||||||
|
b, err := json.Marshal(node)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("Invalid root AST Node: %v", root))
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(b, &nodeIn)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("Invalid root AST Node (2a): %v", root))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nodeIn = node
|
||||||
|
}
|
||||||
|
parentConcrete, _ := parent.(ast.Node)
|
||||||
|
// ancestorsConcrete slice may contain nil values
|
||||||
|
ancestorsConcrete := []ast.Node{}
|
||||||
|
for _, ancestor := range ancestors {
|
||||||
|
if ancestorConcrete, ok := ancestor.(ast.Node); ok {
|
||||||
|
ancestorsConcrete = append(ancestorsConcrete, ancestorConcrete)
|
||||||
|
} else {
|
||||||
|
ancestorsConcrete = append(ancestorsConcrete, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kind := ""
|
||||||
|
if node, ok := node.(map[string]interface{}); ok {
|
||||||
|
kind, _ = node["Kind"].(string)
|
||||||
|
}
|
||||||
|
if node, ok := node.(ast.Node); ok {
|
||||||
|
kind = node.GetKind()
|
||||||
|
}
|
||||||
|
|
||||||
|
visitFn := GetVisitFn(visitorOpts, kind, isLeaving)
|
||||||
|
if visitFn != nil {
|
||||||
|
p := VisitFuncParams{
|
||||||
|
Node: nodeIn,
|
||||||
|
Key: key,
|
||||||
|
Parent: parentConcrete,
|
||||||
|
Path: path,
|
||||||
|
Ancestors: ancestorsConcrete,
|
||||||
|
}
|
||||||
|
action := ActionUpdate
|
||||||
|
action, result = visitFn(p)
|
||||||
|
if action == ActionBreak {
|
||||||
|
break Loop
|
||||||
|
}
|
||||||
|
if action == ActionSkip {
|
||||||
|
if !isLeaving {
|
||||||
|
_, path = pop(path)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if action != ActionNoChange {
|
||||||
|
resultIsUndefined = false
|
||||||
|
edits = append(edits, &edit{
|
||||||
|
Key: key,
|
||||||
|
Value: result,
|
||||||
|
})
|
||||||
|
if !isLeaving {
|
||||||
|
if isNode(result) {
|
||||||
|
node = result
|
||||||
|
} else {
|
||||||
|
_, path = pop(path)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resultIsUndefined = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// collect back edits on the way out
|
||||||
|
if resultIsUndefined && isEdited {
|
||||||
|
if !prevInSlice {
|
||||||
|
edits = append(edits, &edit{
|
||||||
|
Key: key,
|
||||||
|
Value: node,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
edits = append(edits, &edit{
|
||||||
|
Key: key,
|
||||||
|
Value: nodeSlice,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !isLeaving {
|
||||||
|
|
||||||
|
// add to stack
|
||||||
|
prevStack := sstack
|
||||||
|
sstack = &stack{
|
||||||
|
inSlice: inSlice,
|
||||||
|
Index: index,
|
||||||
|
Keys: keys,
|
||||||
|
Edits: edits,
|
||||||
|
Prev: prevStack,
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace keys
|
||||||
|
inSlice = false
|
||||||
|
if len(nodeSlice) > 0 {
|
||||||
|
inSlice = true
|
||||||
|
}
|
||||||
|
keys = []interface{}{}
|
||||||
|
|
||||||
|
if inSlice {
|
||||||
|
// get keys
|
||||||
|
for _, m := range nodeSlice {
|
||||||
|
keys = append(keys, m)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !isNilNode(node) {
|
||||||
|
if node, ok := node.(ast.Node); ok {
|
||||||
|
kind := node.GetKind()
|
||||||
|
if n, ok := visitorKeys[kind]; ok {
|
||||||
|
for _, m := range n {
|
||||||
|
keys = append(keys, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
index = -1
|
||||||
|
edits = []*edit{}
|
||||||
|
|
||||||
|
ancestors = append(ancestors, parent)
|
||||||
|
parent = node
|
||||||
|
ancestorsSlice = append(ancestorsSlice, parentSlice)
|
||||||
|
parentSlice = nodeSlice
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop guard
|
||||||
|
if sstack == nil {
|
||||||
|
break Loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(edits) != 0 {
|
||||||
|
result = edits[len(edits)-1].Value
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func pop(a []interface{}) (x interface{}, aa []interface{}) {
|
||||||
|
if len(a) == 0 {
|
||||||
|
return x, aa
|
||||||
|
}
|
||||||
|
x, aa = a[len(a)-1], a[:len(a)-1]
|
||||||
|
return x, aa
|
||||||
|
}
|
||||||
|
func popNodeSlice(a [][]interface{}) (x []interface{}, aa [][]interface{}) {
|
||||||
|
if len(a) == 0 {
|
||||||
|
return x, aa
|
||||||
|
}
|
||||||
|
x, aa = a[len(a)-1], a[:len(a)-1]
|
||||||
|
return x, aa
|
||||||
|
}
|
||||||
|
func spliceNode(a interface{}, i int) (result []interface{}) {
|
||||||
|
if i < 0 {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
typeOf := reflect.TypeOf(a)
|
||||||
|
if typeOf == nil {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
switch typeOf.Kind() {
|
||||||
|
case reflect.Slice:
|
||||||
|
s := reflect.ValueOf(a)
|
||||||
|
for i := 0; i < s.Len(); i++ {
|
||||||
|
elem := s.Index(i)
|
||||||
|
elemInterface := elem.Interface()
|
||||||
|
result = append(result, elemInterface)
|
||||||
|
}
|
||||||
|
if i >= s.Len() {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
return append(result[:i], result[i+1:]...)
|
||||||
|
default:
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getFieldValue(obj interface{}, key interface{}) interface{} {
|
||||||
|
val := reflect.ValueOf(obj)
|
||||||
|
if val.Type().Kind() == reflect.Ptr {
|
||||||
|
val = val.Elem()
|
||||||
|
}
|
||||||
|
if val.Type().Kind() == reflect.Struct {
|
||||||
|
key, ok := key.(string)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
valField := val.FieldByName(key)
|
||||||
|
if valField.IsValid() {
|
||||||
|
return valField.Interface()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if val.Type().Kind() == reflect.Slice {
|
||||||
|
key, ok := key.(int)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if key >= val.Len() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
valField := val.Index(key)
|
||||||
|
if valField.IsValid() {
|
||||||
|
return valField.Interface()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if val.Type().Kind() == reflect.Map {
|
||||||
|
keyVal := reflect.ValueOf(key)
|
||||||
|
valField := val.MapIndex(keyVal)
|
||||||
|
if valField.IsValid() {
|
||||||
|
return valField.Interface()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateNodeField(value interface{}, fieldName string, fieldValue interface{}) (retVal interface{}) {
|
||||||
|
retVal = value
|
||||||
|
val := reflect.ValueOf(value)
|
||||||
|
|
||||||
|
isPtr := false
|
||||||
|
if val.IsValid() && val.Type().Kind() == reflect.Ptr {
|
||||||
|
val = val.Elem()
|
||||||
|
isPtr = true
|
||||||
|
}
|
||||||
|
if !val.IsValid() {
|
||||||
|
return retVal
|
||||||
|
}
|
||||||
|
if val.Type().Kind() == reflect.Struct {
|
||||||
|
for i := 0; i < val.NumField(); i++ {
|
||||||
|
valueField := val.Field(i)
|
||||||
|
typeField := val.Type().Field(i)
|
||||||
|
|
||||||
|
// try matching the field name
|
||||||
|
if typeField.Name == fieldName {
|
||||||
|
fieldValueVal := reflect.ValueOf(fieldValue)
|
||||||
|
if valueField.CanSet() {
|
||||||
|
|
||||||
|
if fieldValueVal.IsValid() {
|
||||||
|
if valueField.Type().Kind() == fieldValueVal.Type().Kind() {
|
||||||
|
if fieldValueVal.Type().Kind() == reflect.Slice {
|
||||||
|
newSliceValue := reflect.MakeSlice(reflect.TypeOf(valueField.Interface()), fieldValueVal.Len(), fieldValueVal.Len())
|
||||||
|
for i := 0; i < newSliceValue.Len(); i++ {
|
||||||
|
dst := newSliceValue.Index(i)
|
||||||
|
src := fieldValueVal.Index(i)
|
||||||
|
srcValue := reflect.ValueOf(src.Interface())
|
||||||
|
if dst.CanSet() {
|
||||||
|
dst.Set(srcValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
valueField.Set(newSliceValue)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
valueField.Set(fieldValueVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
valueField.Set(reflect.New(valueField.Type()).Elem())
|
||||||
|
}
|
||||||
|
if isPtr == true {
|
||||||
|
retVal = val.Addr().Interface()
|
||||||
|
return retVal
|
||||||
|
}
|
||||||
|
retVal = val.Interface()
|
||||||
|
return retVal
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retVal
|
||||||
|
}
|
||||||
|
func toSliceInterfaces(slice interface{}) (result []interface{}) {
|
||||||
|
switch reflect.TypeOf(slice).Kind() {
|
||||||
|
case reflect.Slice:
|
||||||
|
s := reflect.ValueOf(slice)
|
||||||
|
for i := 0; i < s.Len(); i++ {
|
||||||
|
elem := s.Index(i)
|
||||||
|
elemInterface := elem.Interface()
|
||||||
|
if elem, ok := elemInterface.(ast.Node); ok {
|
||||||
|
result = append(result, elem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
default:
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSlice(value interface{}) bool {
|
||||||
|
val := reflect.ValueOf(value)
|
||||||
|
if val.IsValid() && val.Type().Kind() == reflect.Slice {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
func isNode(node interface{}) bool {
|
||||||
|
val := reflect.ValueOf(node)
|
||||||
|
if val.IsValid() && val.Type().Kind() == reflect.Ptr {
|
||||||
|
val = val.Elem()
|
||||||
|
}
|
||||||
|
if !val.IsValid() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if val.Type().Kind() == reflect.Map {
|
||||||
|
keyVal := reflect.ValueOf("Kind")
|
||||||
|
valField := val.MapIndex(keyVal)
|
||||||
|
return valField.IsValid()
|
||||||
|
}
|
||||||
|
if val.Type().Kind() == reflect.Struct {
|
||||||
|
valField := val.FieldByName("Kind")
|
||||||
|
return valField.IsValid()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
func isStructNode(node interface{}) bool {
|
||||||
|
val := reflect.ValueOf(node)
|
||||||
|
if val.IsValid() && val.Type().Kind() == reflect.Ptr {
|
||||||
|
val = val.Elem()
|
||||||
|
}
|
||||||
|
if !val.IsValid() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if val.Type().Kind() == reflect.Struct {
|
||||||
|
valField := val.FieldByName("Kind")
|
||||||
|
return valField.IsValid()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNilNode(node interface{}) bool {
|
||||||
|
val := reflect.ValueOf(node)
|
||||||
|
if !val.IsValid() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if val.Type().Kind() == reflect.Ptr {
|
||||||
|
return val.IsNil()
|
||||||
|
}
|
||||||
|
if val.Type().Kind() == reflect.Slice {
|
||||||
|
return val.Len() == 0
|
||||||
|
}
|
||||||
|
if val.Type().Kind() == reflect.Map {
|
||||||
|
return val.Len() == 0
|
||||||
|
}
|
||||||
|
if val.Type().Kind() == reflect.Bool {
|
||||||
|
return val.Interface().(bool)
|
||||||
|
}
|
||||||
|
return val.Interface() == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VisitInParallel Creates a new visitor instance which delegates to many visitors to run in
|
||||||
|
// parallel. Each visitor will be visited for each node before moving on.
|
||||||
|
//
|
||||||
|
// If a prior visitor edits a node, no following visitors will see that node.
|
||||||
|
func VisitInParallel(visitorOptsSlice ...*VisitorOptions) *VisitorOptions {
|
||||||
|
skipping := map[int]interface{}{}
|
||||||
|
|
||||||
|
return &VisitorOptions{
|
||||||
|
Enter: func(p VisitFuncParams) (string, interface{}) {
|
||||||
|
for i, visitorOpts := range visitorOptsSlice {
|
||||||
|
if _, ok := skipping[i]; !ok {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case ast.Node:
|
||||||
|
kind := node.GetKind()
|
||||||
|
fn := GetVisitFn(visitorOpts, kind, false)
|
||||||
|
if fn != nil {
|
||||||
|
action, result := fn(p)
|
||||||
|
if action == ActionSkip {
|
||||||
|
skipping[i] = node
|
||||||
|
} else if action == ActionBreak {
|
||||||
|
skipping[i] = ActionBreak
|
||||||
|
} else if action == ActionUpdate {
|
||||||
|
return ActionUpdate, result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ActionNoChange, nil
|
||||||
|
},
|
||||||
|
Leave: func(p VisitFuncParams) (string, interface{}) {
|
||||||
|
for i, visitorOpts := range visitorOptsSlice {
|
||||||
|
skippedNode, ok := skipping[i]
|
||||||
|
if !ok {
|
||||||
|
switch node := p.Node.(type) {
|
||||||
|
case ast.Node:
|
||||||
|
kind := node.GetKind()
|
||||||
|
fn := GetVisitFn(visitorOpts, kind, true)
|
||||||
|
if fn != nil {
|
||||||
|
action, result := fn(p)
|
||||||
|
if action == ActionBreak {
|
||||||
|
skipping[i] = ActionBreak
|
||||||
|
} else if action == ActionUpdate {
|
||||||
|
return ActionUpdate, result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if skippedNode == p.Node {
|
||||||
|
delete(skipping, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ActionNoChange, nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// VisitWithTypeInfo Creates a new visitor instance which maintains a provided TypeInfo instance
|
||||||
|
// along with visiting visitor.
|
||||||
|
func VisitWithTypeInfo(ttypeInfo typeInfo.TypeInfoI, visitorOpts *VisitorOptions) *VisitorOptions {
|
||||||
|
return &VisitorOptions{
|
||||||
|
Enter: func(p VisitFuncParams) (string, interface{}) {
|
||||||
|
if node, ok := p.Node.(ast.Node); ok {
|
||||||
|
ttypeInfo.Enter(node)
|
||||||
|
fn := GetVisitFn(visitorOpts, node.GetKind(), false)
|
||||||
|
if fn != nil {
|
||||||
|
action, result := fn(p)
|
||||||
|
if action == ActionUpdate {
|
||||||
|
ttypeInfo.Leave(node)
|
||||||
|
if isNode(result) {
|
||||||
|
if result, ok := result.(ast.Node); ok {
|
||||||
|
ttypeInfo.Enter(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return action, result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ActionNoChange, nil
|
||||||
|
},
|
||||||
|
Leave: func(p VisitFuncParams) (string, interface{}) {
|
||||||
|
action := ActionNoChange
|
||||||
|
var result interface{}
|
||||||
|
if node, ok := p.Node.(ast.Node); ok {
|
||||||
|
fn := GetVisitFn(visitorOpts, node.GetKind(), true)
|
||||||
|
if fn != nil {
|
||||||
|
action, result = fn(p)
|
||||||
|
}
|
||||||
|
ttypeInfo.Leave(node)
|
||||||
|
}
|
||||||
|
return action, result
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetVisitFn Given a visitor instance, if it is leaving or not, and a node kind, return
|
||||||
|
// the function the visitor runtime should call.
|
||||||
|
func GetVisitFn(visitorOpts *VisitorOptions, kind string, isLeaving bool) VisitFunc {
|
||||||
|
if visitorOpts == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
kindVisitor, ok := visitorOpts.KindFuncMap[kind]
|
||||||
|
if ok {
|
||||||
|
if !isLeaving && kindVisitor.Kind != nil {
|
||||||
|
// { Kind() {} }
|
||||||
|
return kindVisitor.Kind
|
||||||
|
}
|
||||||
|
if isLeaving {
|
||||||
|
// { Kind: { leave() {} } }
|
||||||
|
return kindVisitor.Leave
|
||||||
|
}
|
||||||
|
// { Kind: { enter() {} } }
|
||||||
|
return kindVisitor.Enter
|
||||||
|
|
||||||
|
}
|
||||||
|
if isLeaving {
|
||||||
|
// { enter() {} }
|
||||||
|
specificVisitor := visitorOpts.Leave
|
||||||
|
if specificVisitor != nil {
|
||||||
|
return specificVisitor
|
||||||
|
}
|
||||||
|
if specificKindVisitor, ok := visitorOpts.LeaveKindMap[kind]; ok {
|
||||||
|
// { leave: { Kind() {} } }
|
||||||
|
return specificKindVisitor
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// { leave() {} }
|
||||||
|
specificVisitor := visitorOpts.Enter
|
||||||
|
if specificVisitor != nil {
|
||||||
|
return specificVisitor
|
||||||
|
}
|
||||||
|
if specificKindVisitor, ok := visitorOpts.EnterKindMap[kind]; ok {
|
||||||
|
// { enter: { Kind() {} } }
|
||||||
|
return specificKindVisitor
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
37
vendor/github.com/graphql-go/graphql/located.go
generated
vendored
Normal file
37
vendor/github.com/graphql-go/graphql/located.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package graphql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/graphql-go/graphql/gqlerrors"
|
||||||
|
"github.com/graphql-go/graphql/language/ast"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewLocatedError(err interface{}, nodes []ast.Node) *gqlerrors.Error {
|
||||||
|
var origError error
|
||||||
|
message := "An unknown error occurred."
|
||||||
|
if err, ok := err.(error); ok {
|
||||||
|
message = err.Error()
|
||||||
|
origError = err
|
||||||
|
}
|
||||||
|
if err, ok := err.(string); ok {
|
||||||
|
message = err
|
||||||
|
origError = errors.New(err)
|
||||||
|
}
|
||||||
|
stack := message
|
||||||
|
return gqlerrors.NewError(
|
||||||
|
message,
|
||||||
|
nodes,
|
||||||
|
stack,
|
||||||
|
nil,
|
||||||
|
[]int{},
|
||||||
|
origError,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FieldASTsToNodeASTs(fieldASTs []*ast.Field) []ast.Node {
|
||||||
|
nodes := []ast.Node{}
|
||||||
|
for _, fieldAST := range fieldASTs {
|
||||||
|
nodes = append(nodes, fieldAST)
|
||||||
|
}
|
||||||
|
return nodes
|
||||||
|
}
|
1907
vendor/github.com/graphql-go/graphql/rules.go
generated
vendored
Normal file
1907
vendor/github.com/graphql-go/graphql/rules.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
706
vendor/github.com/graphql-go/graphql/rules_overlapping_fields_can_be_merged.go
generated
vendored
Normal file
706
vendor/github.com/graphql-go/graphql/rules_overlapping_fields_can_be_merged.go
generated
vendored
Normal file
@ -0,0 +1,706 @@
|
|||||||
|
package graphql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/graphql-go/graphql/language/ast"
|
||||||
|
"github.com/graphql-go/graphql/language/kinds"
|
||||||
|
"github.com/graphql-go/graphql/language/printer"
|
||||||
|
"github.com/graphql-go/graphql/language/visitor"
|
||||||
|
)
|
||||||
|
|
||||||
|
func fieldsConflictMessage(responseName string, reason conflictReason) string {
|
||||||
|
return fmt.Sprintf(`Fields "%v" conflict because %v. `+
|
||||||
|
`Use different aliases on the fields to fetch both if this was intentional.`,
|
||||||
|
responseName,
|
||||||
|
fieldsConflictReasonMessage(reason),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fieldsConflictReasonMessage(message interface{}) string {
|
||||||
|
switch reason := message.(type) {
|
||||||
|
case string:
|
||||||
|
return reason
|
||||||
|
case conflictReason:
|
||||||
|
return fieldsConflictReasonMessage(reason.Message)
|
||||||
|
case []conflictReason:
|
||||||
|
messages := []string{}
|
||||||
|
for _, r := range reason {
|
||||||
|
messages = append(messages, fmt.Sprintf(
|
||||||
|
`subfields "%v" conflict because %v`,
|
||||||
|
r.Name,
|
||||||
|
fieldsConflictReasonMessage(r.Message),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
return strings.Join(messages, " and ")
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// OverlappingFieldsCanBeMergedRule Overlapping fields can be merged
|
||||||
|
//
|
||||||
|
// A selection set is only valid if all fields (including spreading any
|
||||||
|
// fragments) either correspond to distinct response names or can be merged
|
||||||
|
// without ambiguity.
|
||||||
|
func OverlappingFieldsCanBeMergedRule(context *ValidationContext) *ValidationRuleInstance {
|
||||||
|
|
||||||
|
// A memoization for when two fragments are compared "between" each other for
|
||||||
|
// conflicts. Two fragments may be compared many times, so memoizing this can
|
||||||
|
// dramatically improve the performance of this validator.
|
||||||
|
comparedSet := newPairSet()
|
||||||
|
|
||||||
|
// A cache for the "field map" and list of fragment names found in any given
|
||||||
|
// selection set. Selection sets may be asked for this information multiple
|
||||||
|
// times, so this improves the performance of this validator.
|
||||||
|
cacheMap := map[*ast.SelectionSet]*fieldsAndFragmentNames{}
|
||||||
|
|
||||||
|
visitorOpts := &visitor.VisitorOptions{
|
||||||
|
KindFuncMap: map[string]visitor.NamedVisitFuncs{
|
||||||
|
kinds.SelectionSet: {
|
||||||
|
Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
if selectionSet, ok := p.Node.(*ast.SelectionSet); ok && selectionSet != nil {
|
||||||
|
parentType, _ := context.ParentType().(Named)
|
||||||
|
|
||||||
|
rule := &overlappingFieldsCanBeMergedRule{
|
||||||
|
context: context,
|
||||||
|
comparedSet: comparedSet,
|
||||||
|
cacheMap: cacheMap,
|
||||||
|
}
|
||||||
|
conflicts := rule.findConflictsWithinSelectionSet(parentType, selectionSet)
|
||||||
|
if len(conflicts) > 0 {
|
||||||
|
for _, c := range conflicts {
|
||||||
|
responseName := c.Reason.Name
|
||||||
|
reason := c.Reason
|
||||||
|
reportError(
|
||||||
|
context,
|
||||||
|
fieldsConflictMessage(responseName, reason),
|
||||||
|
append(c.FieldsLeft, c.FieldsRight...),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return &ValidationRuleInstance{
|
||||||
|
VisitorOpts: visitorOpts,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Algorithm:
|
||||||
|
*
|
||||||
|
* Conflicts occur when two fields exist in a query which will produce the same
|
||||||
|
* response name, but represent differing values, thus creating a conflict.
|
||||||
|
* The algorithm below finds all conflicts via making a series of comparisons
|
||||||
|
* between fields. In order to compare as few fields as possible, this makes
|
||||||
|
* a series of comparisons "within" sets of fields and "between" sets of fields.
|
||||||
|
*
|
||||||
|
* Given any selection set, a collection produces both a set of fields by
|
||||||
|
* also including all inline fragments, as well as a list of fragments
|
||||||
|
* referenced by fragment spreads.
|
||||||
|
*
|
||||||
|
* A) Each selection set represented in the document first compares "within" its
|
||||||
|
* collected set of fields, finding any conflicts between every pair of
|
||||||
|
* overlapping fields.
|
||||||
|
* Note: This is the *only time* that a the fields "within" a set are compared
|
||||||
|
* to each other. After this only fields "between" sets are compared.
|
||||||
|
*
|
||||||
|
* B) Also, if any fragment is referenced in a selection set, then a
|
||||||
|
* comparison is made "between" the original set of fields and the
|
||||||
|
* referenced fragment.
|
||||||
|
*
|
||||||
|
* C) Also, if multiple fragments are referenced, then comparisons
|
||||||
|
* are made "between" each referenced fragment.
|
||||||
|
*
|
||||||
|
* D) When comparing "between" a set of fields and a referenced fragment, first
|
||||||
|
* a comparison is made between each field in the original set of fields and
|
||||||
|
* each field in the the referenced set of fields.
|
||||||
|
*
|
||||||
|
* E) Also, if any fragment is referenced in the referenced selection set,
|
||||||
|
* then a comparison is made "between" the original set of fields and the
|
||||||
|
* referenced fragment (recursively referring to step D).
|
||||||
|
*
|
||||||
|
* F) When comparing "between" two fragments, first a comparison is made between
|
||||||
|
* each field in the first referenced set of fields and each field in the the
|
||||||
|
* second referenced set of fields.
|
||||||
|
*
|
||||||
|
* G) Also, any fragments referenced by the first must be compared to the
|
||||||
|
* second, and any fragments referenced by the second must be compared to the
|
||||||
|
* first (recursively referring to step F).
|
||||||
|
*
|
||||||
|
* H) When comparing two fields, if both have selection sets, then a comparison
|
||||||
|
* is made "between" both selection sets, first comparing the set of fields in
|
||||||
|
* the first selection set with the set of fields in the second.
|
||||||
|
*
|
||||||
|
* I) Also, if any fragment is referenced in either selection set, then a
|
||||||
|
* comparison is made "between" the other set of fields and the
|
||||||
|
* referenced fragment.
|
||||||
|
*
|
||||||
|
* J) Also, if two fragments are referenced in both selection sets, then a
|
||||||
|
* comparison is made "between" the two fragments.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
type overlappingFieldsCanBeMergedRule struct {
|
||||||
|
context *ValidationContext
|
||||||
|
|
||||||
|
// A memoization for when two fragments are compared "between" each other for
|
||||||
|
// conflicts. Two fragments may be compared many times, so memoizing this can
|
||||||
|
// dramatically improve the performance of this validator.
|
||||||
|
comparedSet *pairSet
|
||||||
|
|
||||||
|
// A cache for the "field map" and list of fragment names found in any given
|
||||||
|
// selection set. Selection sets may be asked for this information multiple
|
||||||
|
// times, so this improves the performance of this validator.
|
||||||
|
cacheMap map[*ast.SelectionSet]*fieldsAndFragmentNames
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find all conflicts found "within" a selection set, including those found
|
||||||
|
// via spreading in fragments. Called when visiting each SelectionSet in the
|
||||||
|
// GraphQL Document.
|
||||||
|
func (rule *overlappingFieldsCanBeMergedRule) findConflictsWithinSelectionSet(parentType Named, selectionSet *ast.SelectionSet) []conflict {
|
||||||
|
conflicts := []conflict{}
|
||||||
|
|
||||||
|
fieldsInfo := rule.getFieldsAndFragmentNames(parentType, selectionSet)
|
||||||
|
|
||||||
|
// (A) Find find all conflicts "within" the fields of this selection set.
|
||||||
|
// Note: this is the *only place* `collectConflictsWithin` is called.
|
||||||
|
conflicts = rule.collectConflictsWithin(conflicts, fieldsInfo)
|
||||||
|
|
||||||
|
// (B) Then collect conflicts between these fields and those represented by
|
||||||
|
// each spread fragment name found.
|
||||||
|
for i := 0; i < len(fieldsInfo.fragmentNames); i++ {
|
||||||
|
|
||||||
|
conflicts = rule.collectConflictsBetweenFieldsAndFragment(conflicts, false, fieldsInfo, fieldsInfo.fragmentNames[i])
|
||||||
|
|
||||||
|
// (C) Then compare this fragment with all other fragments found in this
|
||||||
|
// selection set to collect conflicts between fragments spread together.
|
||||||
|
// This compares each item in the list of fragment names to every other item
|
||||||
|
// in that same list (except for itself).
|
||||||
|
for k := i + 1; k < len(fieldsInfo.fragmentNames); k++ {
|
||||||
|
conflicts = rule.collectConflictsBetweenFragments(conflicts, false, fieldsInfo.fragmentNames[i], fieldsInfo.fragmentNames[k])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return conflicts
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect all conflicts found between a set of fields and a fragment reference
|
||||||
|
// including via spreading in any nested fragments.
|
||||||
|
func (rule *overlappingFieldsCanBeMergedRule) collectConflictsBetweenFieldsAndFragment(conflicts []conflict, areMutuallyExclusive bool, fieldsInfo *fieldsAndFragmentNames, fragmentName string) []conflict {
|
||||||
|
fragment := rule.context.Fragment(fragmentName)
|
||||||
|
if fragment == nil {
|
||||||
|
return conflicts
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldsInfo2 := rule.getReferencedFieldsAndFragmentNames(fragment)
|
||||||
|
|
||||||
|
// (D) First collect any conflicts between the provided collection of fields
|
||||||
|
// and the collection of fields represented by the given fragment.
|
||||||
|
conflicts = rule.collectConflictsBetween(conflicts, areMutuallyExclusive, fieldsInfo, fieldsInfo2)
|
||||||
|
|
||||||
|
// (E) Then collect any conflicts between the provided collection of fields
|
||||||
|
// and any fragment names found in the given fragment.
|
||||||
|
for _, fragmentName2 := range fieldsInfo2.fragmentNames {
|
||||||
|
conflicts = rule.collectConflictsBetweenFieldsAndFragment(conflicts, areMutuallyExclusive, fieldsInfo2, fragmentName2)
|
||||||
|
}
|
||||||
|
|
||||||
|
return conflicts
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect all conflicts found between two fragments, including via spreading in
|
||||||
|
// any nested fragments.
|
||||||
|
func (rule *overlappingFieldsCanBeMergedRule) collectConflictsBetweenFragments(conflicts []conflict, areMutuallyExclusive bool, fragmentName1 string, fragmentName2 string) []conflict {
|
||||||
|
fragment1 := rule.context.Fragment(fragmentName1)
|
||||||
|
fragment2 := rule.context.Fragment(fragmentName2)
|
||||||
|
|
||||||
|
if fragment1 == nil || fragment2 == nil {
|
||||||
|
return conflicts
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need to compare a fragment to itself.
|
||||||
|
if fragment1 == fragment2 {
|
||||||
|
return conflicts
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memoize so two fragments are not compared for conflicts more than once.
|
||||||
|
if rule.comparedSet.Has(fragmentName1, fragmentName2, areMutuallyExclusive) {
|
||||||
|
return conflicts
|
||||||
|
}
|
||||||
|
rule.comparedSet.Add(fragmentName1, fragmentName2, areMutuallyExclusive)
|
||||||
|
|
||||||
|
fieldsInfo1 := rule.getReferencedFieldsAndFragmentNames(fragment1)
|
||||||
|
fieldsInfo2 := rule.getReferencedFieldsAndFragmentNames(fragment2)
|
||||||
|
|
||||||
|
// (F) First, collect all conflicts between these two collections of fields
|
||||||
|
// (not including any nested fragments).
|
||||||
|
conflicts = rule.collectConflictsBetween(conflicts, areMutuallyExclusive, fieldsInfo1, fieldsInfo2)
|
||||||
|
|
||||||
|
// (G) Then collect conflicts between the first fragment and any nested
|
||||||
|
// fragments spread in the second fragment.
|
||||||
|
for _, innerFragmentName2 := range fieldsInfo2.fragmentNames {
|
||||||
|
conflicts = rule.collectConflictsBetweenFragments(conflicts, areMutuallyExclusive, fragmentName1, innerFragmentName2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// (G) Then collect conflicts between the second fragment and any nested
|
||||||
|
// fragments spread in the first fragment.
|
||||||
|
for _, innerFragmentName1 := range fieldsInfo1.fragmentNames {
|
||||||
|
conflicts = rule.collectConflictsBetweenFragments(conflicts, areMutuallyExclusive, innerFragmentName1, fragmentName2)
|
||||||
|
}
|
||||||
|
|
||||||
|
return conflicts
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find all conflicts found between two selection sets, including those found
|
||||||
|
// via spreading in fragments. Called when determining if conflicts exist
|
||||||
|
// between the sub-fields of two overlapping fields.
|
||||||
|
func (rule *overlappingFieldsCanBeMergedRule) findConflictsBetweenSubSelectionSets(areMutuallyExclusive bool, parentType1 Named, selectionSet1 *ast.SelectionSet, parentType2 Named, selectionSet2 *ast.SelectionSet) []conflict {
|
||||||
|
conflicts := []conflict{}
|
||||||
|
|
||||||
|
fieldsInfo1 := rule.getFieldsAndFragmentNames(parentType1, selectionSet1)
|
||||||
|
fieldsInfo2 := rule.getFieldsAndFragmentNames(parentType2, selectionSet2)
|
||||||
|
|
||||||
|
// (H) First, collect all conflicts between these two collections of field.
|
||||||
|
conflicts = rule.collectConflictsBetween(conflicts, areMutuallyExclusive, fieldsInfo1, fieldsInfo2)
|
||||||
|
|
||||||
|
// (I) Then collect conflicts between the first collection of fields and
|
||||||
|
// those referenced by each fragment name associated with the second.
|
||||||
|
for _, fragmentName2 := range fieldsInfo2.fragmentNames {
|
||||||
|
conflicts = rule.collectConflictsBetweenFieldsAndFragment(conflicts, areMutuallyExclusive, fieldsInfo1, fragmentName2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// (I) Then collect conflicts between the second collection of fields and
|
||||||
|
// those referenced by each fragment name associated with the first.
|
||||||
|
for _, fragmentName1 := range fieldsInfo1.fragmentNames {
|
||||||
|
conflicts = rule.collectConflictsBetweenFieldsAndFragment(conflicts, areMutuallyExclusive, fieldsInfo2, fragmentName1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// (J) Also collect conflicts between any fragment names by the first and
|
||||||
|
// fragment names by the second. This compares each item in the first set of
|
||||||
|
// names to each item in the second set of names.
|
||||||
|
for _, fragmentName1 := range fieldsInfo1.fragmentNames {
|
||||||
|
for _, fragmentName2 := range fieldsInfo2.fragmentNames {
|
||||||
|
conflicts = rule.collectConflictsBetweenFragments(conflicts, areMutuallyExclusive, fragmentName1, fragmentName2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return conflicts
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect all Conflicts "within" one collection of fields.
|
||||||
|
func (rule *overlappingFieldsCanBeMergedRule) collectConflictsWithin(conflicts []conflict, fieldsInfo *fieldsAndFragmentNames) []conflict {
|
||||||
|
// A field map is a keyed collection, where each key represents a response
|
||||||
|
// name and the value at that key is a list of all fields which provide that
|
||||||
|
// response name. For every response name, if there are multiple fields, they
|
||||||
|
// must be compared to find a potential conflict.
|
||||||
|
for _, responseName := range fieldsInfo.fieldsOrder {
|
||||||
|
fields, ok := fieldsInfo.fieldMap[responseName]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// This compares every field in the list to every other field in this list
|
||||||
|
// (except to itself). If the list only has one item, nothing needs to
|
||||||
|
// be compared.
|
||||||
|
if len(fields) <= 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for i := 0; i < len(fields); i++ {
|
||||||
|
for k := i + 1; k < len(fields); k++ {
|
||||||
|
// within one collection is never mutually exclusive
|
||||||
|
isMutuallyExclusive := false
|
||||||
|
conflict := rule.findConflict(isMutuallyExclusive, responseName, fields[i], fields[k])
|
||||||
|
if conflict != nil {
|
||||||
|
conflicts = append(conflicts, *conflict)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return conflicts
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect all Conflicts between two collections of fields. This is similar to,
|
||||||
|
// but different from the `collectConflictsWithin` function above. This check
|
||||||
|
// assumes that `collectConflictsWithin` has already been called on each
|
||||||
|
// provided collection of fields. This is true because this validator traverses
|
||||||
|
// each individual selection set.
|
||||||
|
func (rule *overlappingFieldsCanBeMergedRule) collectConflictsBetween(conflicts []conflict, parentFieldsAreMutuallyExclusive bool,
|
||||||
|
fieldsInfo1 *fieldsAndFragmentNames,
|
||||||
|
fieldsInfo2 *fieldsAndFragmentNames) []conflict {
|
||||||
|
// A field map is a keyed collection, where each key represents a response
|
||||||
|
// name and the value at that key is a list of all fields which provide that
|
||||||
|
// response name. For any response name which appears in both provided field
|
||||||
|
// maps, each field from the first field map must be compared to every field
|
||||||
|
// in the second field map to find potential conflicts.
|
||||||
|
for _, responseName := range fieldsInfo1.fieldsOrder {
|
||||||
|
fields1, ok1 := fieldsInfo1.fieldMap[responseName]
|
||||||
|
fields2, ok2 := fieldsInfo2.fieldMap[responseName]
|
||||||
|
if !ok1 || !ok2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for i := 0; i < len(fields1); i++ {
|
||||||
|
for k := 0; k < len(fields2); k++ {
|
||||||
|
conflict := rule.findConflict(parentFieldsAreMutuallyExclusive, responseName, fields1[i], fields2[k])
|
||||||
|
if conflict != nil {
|
||||||
|
conflicts = append(conflicts, *conflict)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return conflicts
|
||||||
|
}
|
||||||
|
|
||||||
|
// findConflict Determines if there is a conflict between two particular fields.
|
||||||
|
func (rule *overlappingFieldsCanBeMergedRule) findConflict(parentFieldsAreMutuallyExclusive bool, responseName string, field *fieldDefPair, field2 *fieldDefPair) *conflict {
|
||||||
|
|
||||||
|
parentType1 := field.ParentType
|
||||||
|
ast1 := field.Field
|
||||||
|
def1 := field.FieldDef
|
||||||
|
|
||||||
|
parentType2 := field2.ParentType
|
||||||
|
ast2 := field2.Field
|
||||||
|
def2 := field2.FieldDef
|
||||||
|
|
||||||
|
// If it is known that two fields could not possibly apply at the same
|
||||||
|
// time, due to the parent types, then it is safe to permit them to diverge
|
||||||
|
// in aliased field or arguments used as they will not present any ambiguity
|
||||||
|
// by differing.
|
||||||
|
// It is known that two parent types could never overlap if they are
|
||||||
|
// different Object types. Interface or Union types might overlap - if not
|
||||||
|
// in the current state of the schema, then perhaps in some future version,
|
||||||
|
// thus may not safely diverge.
|
||||||
|
_, isParentType1Object := parentType1.(*Object)
|
||||||
|
_, isParentType2Object := parentType2.(*Object)
|
||||||
|
areMutuallyExclusive := parentFieldsAreMutuallyExclusive || parentType1 != parentType2 && isParentType1Object && isParentType2Object
|
||||||
|
|
||||||
|
// The return type for each field.
|
||||||
|
var type1 Type
|
||||||
|
var type2 Type
|
||||||
|
if def1 != nil {
|
||||||
|
type1 = def1.Type
|
||||||
|
}
|
||||||
|
if def2 != nil {
|
||||||
|
type2 = def2.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
if !areMutuallyExclusive {
|
||||||
|
// Two aliases must refer to the same field.
|
||||||
|
name1 := ""
|
||||||
|
name2 := ""
|
||||||
|
|
||||||
|
if ast1.Name != nil {
|
||||||
|
name1 = ast1.Name.Value
|
||||||
|
}
|
||||||
|
if ast2.Name != nil {
|
||||||
|
name2 = ast2.Name.Value
|
||||||
|
}
|
||||||
|
if name1 != name2 {
|
||||||
|
return &conflict{
|
||||||
|
Reason: conflictReason{
|
||||||
|
Name: responseName,
|
||||||
|
Message: fmt.Sprintf(`%v and %v are different fields`, name1, name2),
|
||||||
|
},
|
||||||
|
FieldsLeft: []ast.Node{ast1},
|
||||||
|
FieldsRight: []ast.Node{ast2},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Two field calls must have the same arguments.
|
||||||
|
if !sameArguments(ast1.Arguments, ast2.Arguments) {
|
||||||
|
return &conflict{
|
||||||
|
Reason: conflictReason{
|
||||||
|
Name: responseName,
|
||||||
|
Message: `they have differing arguments`,
|
||||||
|
},
|
||||||
|
FieldsLeft: []ast.Node{ast1},
|
||||||
|
FieldsRight: []ast.Node{ast2},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if type1 != nil && type2 != nil && doTypesConflict(type1, type2) {
|
||||||
|
return &conflict{
|
||||||
|
Reason: conflictReason{
|
||||||
|
Name: responseName,
|
||||||
|
Message: fmt.Sprintf(`they return conflicting types %v and %v`, type1, type2),
|
||||||
|
},
|
||||||
|
FieldsLeft: []ast.Node{ast1},
|
||||||
|
FieldsRight: []ast.Node{ast2},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect and compare sub-fields. Use the same "visited fragment names" list
|
||||||
|
// for both collections so fields in a fragment reference are never
|
||||||
|
// compared to themselves.
|
||||||
|
selectionSet1 := ast1.SelectionSet
|
||||||
|
selectionSet2 := ast2.SelectionSet
|
||||||
|
if selectionSet1 != nil && selectionSet2 != nil {
|
||||||
|
conflicts := rule.findConflictsBetweenSubSelectionSets(areMutuallyExclusive, GetNamed(type1), selectionSet1, GetNamed(type2), selectionSet2)
|
||||||
|
return subfieldConflicts(conflicts, responseName, ast1, ast2)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given a selection set, return the collection of fields (a mapping of response
|
||||||
|
// name to field ASTs and definitions) as well as a list of fragment names
|
||||||
|
// referenced via fragment spreads.
|
||||||
|
func (rule *overlappingFieldsCanBeMergedRule) getFieldsAndFragmentNames(parentType Named, selectionSet *ast.SelectionSet) *fieldsAndFragmentNames {
|
||||||
|
if cached, ok := rule.cacheMap[selectionSet]; ok && cached != nil {
|
||||||
|
return cached
|
||||||
|
}
|
||||||
|
|
||||||
|
astAndDefs := astAndDefCollection{}
|
||||||
|
fieldsOrder := []string{}
|
||||||
|
fragmentNames := []string{}
|
||||||
|
fragmentNamesMap := map[string]bool{}
|
||||||
|
|
||||||
|
var collectFieldsAndFragmentNames func(parentType Named, selectionSet *ast.SelectionSet)
|
||||||
|
collectFieldsAndFragmentNames = func(parentType Named, selectionSet *ast.SelectionSet) {
|
||||||
|
for _, selection := range selectionSet.Selections {
|
||||||
|
switch selection := selection.(type) {
|
||||||
|
case *ast.Field:
|
||||||
|
fieldName := ""
|
||||||
|
if selection.Name != nil {
|
||||||
|
fieldName = selection.Name.Value
|
||||||
|
}
|
||||||
|
var fieldDef *FieldDefinition
|
||||||
|
if parentType, ok := parentType.(*Object); ok && parentType != nil {
|
||||||
|
fieldDef, _ = parentType.Fields()[fieldName]
|
||||||
|
}
|
||||||
|
if parentType, ok := parentType.(*Interface); ok && parentType != nil {
|
||||||
|
fieldDef, _ = parentType.Fields()[fieldName]
|
||||||
|
}
|
||||||
|
|
||||||
|
responseName := fieldName
|
||||||
|
if selection.Alias != nil {
|
||||||
|
responseName = selection.Alias.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldDefPairs, ok := astAndDefs[responseName]
|
||||||
|
if !ok || fieldDefPairs == nil {
|
||||||
|
fieldDefPairs = []*fieldDefPair{}
|
||||||
|
fieldsOrder = append(fieldsOrder, responseName)
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldDefPairs = append(fieldDefPairs, &fieldDefPair{
|
||||||
|
ParentType: parentType,
|
||||||
|
Field: selection,
|
||||||
|
FieldDef: fieldDef,
|
||||||
|
})
|
||||||
|
astAndDefs[responseName] = fieldDefPairs
|
||||||
|
case *ast.FragmentSpread:
|
||||||
|
fieldName := ""
|
||||||
|
if selection.Name != nil {
|
||||||
|
fieldName = selection.Name.Value
|
||||||
|
}
|
||||||
|
if val, ok := fragmentNamesMap[fieldName]; !ok || !val {
|
||||||
|
fragmentNamesMap[fieldName] = true
|
||||||
|
fragmentNames = append(fragmentNames, fieldName)
|
||||||
|
}
|
||||||
|
case *ast.InlineFragment:
|
||||||
|
typeCondition := selection.TypeCondition
|
||||||
|
inlineFragmentType := parentType
|
||||||
|
if typeCondition != nil {
|
||||||
|
ttype, err := typeFromAST(*(rule.context.Schema()), typeCondition)
|
||||||
|
if err == nil {
|
||||||
|
inlineFragmentType, _ = ttype.(Named)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
collectFieldsAndFragmentNames(inlineFragmentType, selection.SelectionSet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
collectFieldsAndFragmentNames(parentType, selectionSet)
|
||||||
|
|
||||||
|
cached := &fieldsAndFragmentNames{
|
||||||
|
fieldMap: astAndDefs,
|
||||||
|
fieldsOrder: fieldsOrder,
|
||||||
|
fragmentNames: fragmentNames,
|
||||||
|
}
|
||||||
|
|
||||||
|
rule.cacheMap[selectionSet] = cached
|
||||||
|
return cached
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rule *overlappingFieldsCanBeMergedRule) getReferencedFieldsAndFragmentNames(fragment *ast.FragmentDefinition) *fieldsAndFragmentNames {
|
||||||
|
// Short-circuit building a type from the AST if possible.
|
||||||
|
if cached, ok := rule.cacheMap[fragment.SelectionSet]; ok && cached != nil {
|
||||||
|
return cached
|
||||||
|
}
|
||||||
|
fragmentType, err := typeFromAST(*(rule.context.Schema()), fragment.TypeCondition)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return rule.getFieldsAndFragmentNames(fragmentType, fragment.SelectionSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
type conflictReason struct {
|
||||||
|
Name string
|
||||||
|
Message interface{} // conflictReason || []conflictReason
|
||||||
|
}
|
||||||
|
type conflict struct {
|
||||||
|
Reason conflictReason
|
||||||
|
FieldsLeft []ast.Node
|
||||||
|
FieldsRight []ast.Node
|
||||||
|
}
|
||||||
|
|
||||||
|
// a.k.a AstAndDef
|
||||||
|
type fieldDefPair struct {
|
||||||
|
ParentType Named
|
||||||
|
Field *ast.Field
|
||||||
|
FieldDef *FieldDefinition
|
||||||
|
}
|
||||||
|
type astAndDefCollection map[string][]*fieldDefPair
|
||||||
|
|
||||||
|
// cache struct for fields, its order and fragments names
|
||||||
|
type fieldsAndFragmentNames struct {
|
||||||
|
fieldMap astAndDefCollection
|
||||||
|
fieldsOrder []string // stores the order of field names in fieldMap
|
||||||
|
fragmentNames []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// pairSet A way to keep track of pairs of things when the ordering of the pair does
|
||||||
|
// not matter. We do this by maintaining a sort of double adjacency sets.
|
||||||
|
type pairSet struct {
|
||||||
|
data map[string]map[string]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPairSet() *pairSet {
|
||||||
|
return &pairSet{
|
||||||
|
data: map[string]map[string]bool{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (pair *pairSet) Has(a string, b string, areMutuallyExclusive bool) bool {
|
||||||
|
first, ok := pair.data[a]
|
||||||
|
if !ok || first == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
res, ok := first[b]
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// areMutuallyExclusive being false is a superset of being true,
|
||||||
|
// hence if we want to know if this PairSet "has" these two with no
|
||||||
|
// exclusivity, we have to ensure it was added as such.
|
||||||
|
if !areMutuallyExclusive {
|
||||||
|
return res == false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
func (pair *pairSet) Add(a string, b string, areMutuallyExclusive bool) {
|
||||||
|
pair.data = pairSetAdd(pair.data, a, b, areMutuallyExclusive)
|
||||||
|
pair.data = pairSetAdd(pair.data, b, a, areMutuallyExclusive)
|
||||||
|
}
|
||||||
|
func pairSetAdd(data map[string]map[string]bool, a, b string, areMutuallyExclusive bool) map[string]map[string]bool {
|
||||||
|
set, ok := data[a]
|
||||||
|
if !ok || set == nil {
|
||||||
|
set = map[string]bool{}
|
||||||
|
}
|
||||||
|
set[b] = areMutuallyExclusive
|
||||||
|
data[a] = set
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
func sameArguments(args1 []*ast.Argument, args2 []*ast.Argument) bool {
|
||||||
|
if len(args1) != len(args2) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, arg1 := range args1 {
|
||||||
|
arg1Name := ""
|
||||||
|
if arg1.Name != nil {
|
||||||
|
arg1Name = arg1.Name.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
var foundArgs2 *ast.Argument
|
||||||
|
for _, arg2 := range args2 {
|
||||||
|
arg2Name := ""
|
||||||
|
if arg2.Name != nil {
|
||||||
|
arg2Name = arg2.Name.Value
|
||||||
|
}
|
||||||
|
if arg1Name == arg2Name {
|
||||||
|
foundArgs2 = arg2
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if foundArgs2 == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if sameValue(arg1.Value, foundArgs2.Value) == false {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func sameValue(value1 ast.Value, value2 ast.Value) bool {
|
||||||
|
if value1 == nil && value2 == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
val1 := printer.Print(value1)
|
||||||
|
val2 := printer.Print(value2)
|
||||||
|
|
||||||
|
return val1 == val2
|
||||||
|
}
|
||||||
|
|
||||||
|
// Two types conflict if both types could not apply to a value simultaneously.
|
||||||
|
// Composite types are ignored as their individual field types will be compared
|
||||||
|
// later recursively. However List and Non-Null types must match.
|
||||||
|
func doTypesConflict(type1 Output, type2 Output) bool {
|
||||||
|
if type1, ok := type1.(*List); ok {
|
||||||
|
if type2, ok := type2.(*List); ok {
|
||||||
|
return doTypesConflict(type1.OfType, type2.OfType)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if type2, ok := type2.(*List); ok {
|
||||||
|
if type1, ok := type1.(*List); ok {
|
||||||
|
return doTypesConflict(type1.OfType, type2.OfType)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if type1, ok := type1.(*NonNull); ok {
|
||||||
|
if type2, ok := type2.(*NonNull); ok {
|
||||||
|
return doTypesConflict(type1.OfType, type2.OfType)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if type2, ok := type2.(*NonNull); ok {
|
||||||
|
if type1, ok := type1.(*NonNull); ok {
|
||||||
|
return doTypesConflict(type1.OfType, type2.OfType)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if IsLeafType(type1) || IsLeafType(type2) {
|
||||||
|
return type1 != type2
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// subfieldConflicts Given a series of Conflicts which occurred between two sub-fields, generate a single Conflict.
|
||||||
|
func subfieldConflicts(conflicts []conflict, responseName string, ast1 *ast.Field, ast2 *ast.Field) *conflict {
|
||||||
|
if len(conflicts) > 0 {
|
||||||
|
conflictReasons := []conflictReason{}
|
||||||
|
conflictFieldsLeft := []ast.Node{ast1}
|
||||||
|
conflictFieldsRight := []ast.Node{ast2}
|
||||||
|
for _, c := range conflicts {
|
||||||
|
conflictReasons = append(conflictReasons, c.Reason)
|
||||||
|
conflictFieldsLeft = append(conflictFieldsLeft, c.FieldsLeft...)
|
||||||
|
conflictFieldsRight = append(conflictFieldsRight, c.FieldsRight...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &conflict{
|
||||||
|
Reason: conflictReason{
|
||||||
|
Name: responseName,
|
||||||
|
Message: conflictReasons,
|
||||||
|
},
|
||||||
|
FieldsLeft: conflictFieldsLeft,
|
||||||
|
FieldsRight: conflictFieldsRight,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
329
vendor/github.com/graphql-go/graphql/scalars.go
generated
vendored
Normal file
329
vendor/github.com/graphql-go/graphql/scalars.go
generated
vendored
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
package graphql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/graphql-go/graphql/language/ast"
|
||||||
|
)
|
||||||
|
|
||||||
|
// As per the GraphQL Spec, Integers are only treated as valid when a valid
|
||||||
|
// 32-bit signed integer, providing the broadest support across platforms.
|
||||||
|
//
|
||||||
|
// n.b. JavaScript's integers are safe between -(2^53 - 1) and 2^53 - 1 because
|
||||||
|
// they are internally represented as IEEE 754 doubles.
|
||||||
|
func coerceInt(value interface{}) interface{} {
|
||||||
|
switch value := value.(type) {
|
||||||
|
case bool:
|
||||||
|
if value == true {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
case int:
|
||||||
|
if value < int(math.MinInt32) || value > int(math.MaxInt32) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
case *int:
|
||||||
|
return coerceInt(*value)
|
||||||
|
case int8:
|
||||||
|
return int(value)
|
||||||
|
case *int8:
|
||||||
|
return int(*value)
|
||||||
|
case int16:
|
||||||
|
return int(value)
|
||||||
|
case *int16:
|
||||||
|
return int(*value)
|
||||||
|
case int32:
|
||||||
|
return int(value)
|
||||||
|
case *int32:
|
||||||
|
return int(*value)
|
||||||
|
case int64:
|
||||||
|
if value < int64(math.MinInt32) || value > int64(math.MaxInt32) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return int(value)
|
||||||
|
case *int64:
|
||||||
|
return coerceInt(*value)
|
||||||
|
case uint:
|
||||||
|
if value > math.MaxInt32 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return int(value)
|
||||||
|
case *uint:
|
||||||
|
return coerceInt(*value)
|
||||||
|
case uint8:
|
||||||
|
return int(value)
|
||||||
|
case *uint8:
|
||||||
|
return int(*value)
|
||||||
|
case uint16:
|
||||||
|
return int(value)
|
||||||
|
case *uint16:
|
||||||
|
return int(*value)
|
||||||
|
case uint32:
|
||||||
|
if value > uint32(math.MaxInt32) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return int(value)
|
||||||
|
case *uint32:
|
||||||
|
return coerceInt(*value)
|
||||||
|
case uint64:
|
||||||
|
if value > uint64(math.MaxInt32) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return int(value)
|
||||||
|
case *uint64:
|
||||||
|
return coerceInt(*value)
|
||||||
|
case float32:
|
||||||
|
if value < float32(math.MinInt32) || value > float32(math.MaxInt32) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return int(value)
|
||||||
|
case *float32:
|
||||||
|
return coerceInt(*value)
|
||||||
|
case float64:
|
||||||
|
if value < float64(math.MinInt32) || value > float64(math.MaxInt32) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return int(value)
|
||||||
|
case *float64:
|
||||||
|
return coerceInt(*value)
|
||||||
|
case string:
|
||||||
|
val, err := strconv.ParseFloat(value, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return coerceInt(val)
|
||||||
|
case *string:
|
||||||
|
return coerceInt(*value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the value cannot be transformed into an int, return nil instead of '0'
|
||||||
|
// to denote 'no integer found'
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int is the GraphQL Integer type definition.
|
||||||
|
var Int = NewScalar(ScalarConfig{
|
||||||
|
Name: "Int",
|
||||||
|
Description: "The `Int` scalar type represents non-fractional signed whole numeric " +
|
||||||
|
"values. Int can represent values between -(2^31) and 2^31 - 1. ",
|
||||||
|
Serialize: coerceInt,
|
||||||
|
ParseValue: coerceInt,
|
||||||
|
ParseLiteral: func(valueAST ast.Value) interface{} {
|
||||||
|
switch valueAST := valueAST.(type) {
|
||||||
|
case *ast.IntValue:
|
||||||
|
if intValue, err := strconv.Atoi(valueAST.Value); err == nil {
|
||||||
|
return intValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
func coerceFloat(value interface{}) interface{} {
|
||||||
|
switch value := value.(type) {
|
||||||
|
case bool:
|
||||||
|
if value == true {
|
||||||
|
return 1.0
|
||||||
|
}
|
||||||
|
return 0.0
|
||||||
|
case *bool:
|
||||||
|
return coerceFloat(*value)
|
||||||
|
case int:
|
||||||
|
return float64(value)
|
||||||
|
case *int32:
|
||||||
|
return coerceFloat(*value)
|
||||||
|
case float32:
|
||||||
|
return value
|
||||||
|
case *float32:
|
||||||
|
return coerceFloat(*value)
|
||||||
|
case float64:
|
||||||
|
return value
|
||||||
|
case *float64:
|
||||||
|
return coerceFloat(*value)
|
||||||
|
case string:
|
||||||
|
val, err := strconv.ParseFloat(value, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
case *string:
|
||||||
|
return coerceFloat(*value)
|
||||||
|
}
|
||||||
|
return 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float is the GraphQL float type definition.
|
||||||
|
var Float = NewScalar(ScalarConfig{
|
||||||
|
Name: "Float",
|
||||||
|
Description: "The `Float` scalar type represents signed double-precision fractional " +
|
||||||
|
"values as specified by " +
|
||||||
|
"[IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ",
|
||||||
|
Serialize: coerceFloat,
|
||||||
|
ParseValue: coerceFloat,
|
||||||
|
ParseLiteral: func(valueAST ast.Value) interface{} {
|
||||||
|
switch valueAST := valueAST.(type) {
|
||||||
|
case *ast.FloatValue:
|
||||||
|
if floatValue, err := strconv.ParseFloat(valueAST.Value, 32); err == nil {
|
||||||
|
return floatValue
|
||||||
|
}
|
||||||
|
case *ast.IntValue:
|
||||||
|
if floatValue, err := strconv.ParseFloat(valueAST.Value, 32); err == nil {
|
||||||
|
return floatValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
func coerceString(value interface{}) interface{} {
|
||||||
|
if v, ok := value.(*string); ok {
|
||||||
|
return *v
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%v", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// String is the GraphQL string type definition
|
||||||
|
var String = NewScalar(ScalarConfig{
|
||||||
|
Name: "String",
|
||||||
|
Description: "The `String` scalar type represents textual data, represented as UTF-8 " +
|
||||||
|
"character sequences. The String type is most often used by GraphQL to " +
|
||||||
|
"represent free-form human-readable text.",
|
||||||
|
Serialize: coerceString,
|
||||||
|
ParseValue: coerceString,
|
||||||
|
ParseLiteral: func(valueAST ast.Value) interface{} {
|
||||||
|
switch valueAST := valueAST.(type) {
|
||||||
|
case *ast.StringValue:
|
||||||
|
return valueAST.Value
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
func coerceBool(value interface{}) interface{} {
|
||||||
|
switch value := value.(type) {
|
||||||
|
case bool:
|
||||||
|
return value
|
||||||
|
case *bool:
|
||||||
|
return *value
|
||||||
|
case string:
|
||||||
|
switch value {
|
||||||
|
case "", "false":
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
case *string:
|
||||||
|
return coerceBool(*value)
|
||||||
|
case float64:
|
||||||
|
if value != 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
case *float64:
|
||||||
|
return coerceBool(*value)
|
||||||
|
case float32:
|
||||||
|
if value != 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
case *float32:
|
||||||
|
return coerceBool(*value)
|
||||||
|
case int:
|
||||||
|
if value != 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
case *int:
|
||||||
|
return coerceBool(*value)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Boolean is the GraphQL boolean type definition
|
||||||
|
var Boolean = NewScalar(ScalarConfig{
|
||||||
|
Name: "Boolean",
|
||||||
|
Description: "The `Boolean` scalar type represents `true` or `false`.",
|
||||||
|
Serialize: coerceBool,
|
||||||
|
ParseValue: coerceBool,
|
||||||
|
ParseLiteral: func(valueAST ast.Value) interface{} {
|
||||||
|
switch valueAST := valueAST.(type) {
|
||||||
|
case *ast.BooleanValue:
|
||||||
|
return valueAST.Value
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// ID is the GraphQL id type definition
|
||||||
|
var ID = NewScalar(ScalarConfig{
|
||||||
|
Name: "ID",
|
||||||
|
Description: "The `ID` scalar type represents a unique identifier, often used to " +
|
||||||
|
"refetch an object or as key for a cache. The ID type appears in a JSON " +
|
||||||
|
"response as a String; however, it is not intended to be human-readable. " +
|
||||||
|
"When expected as an input type, any string (such as `\"4\"`) or integer " +
|
||||||
|
"(such as `4`) input value will be accepted as an ID.",
|
||||||
|
Serialize: coerceString,
|
||||||
|
ParseValue: coerceString,
|
||||||
|
ParseLiteral: func(valueAST ast.Value) interface{} {
|
||||||
|
switch valueAST := valueAST.(type) {
|
||||||
|
case *ast.IntValue:
|
||||||
|
return valueAST.Value
|
||||||
|
case *ast.StringValue:
|
||||||
|
return valueAST.Value
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
func serializeDateTime(value interface{}) interface{} {
|
||||||
|
switch value := value.(type) {
|
||||||
|
case time.Time:
|
||||||
|
buff, err := value.MarshalText()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(buff)
|
||||||
|
case *time.Time:
|
||||||
|
return serializeDateTime(*value)
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unserializeDateTime(value interface{}) interface{} {
|
||||||
|
switch value := value.(type) {
|
||||||
|
case []byte:
|
||||||
|
t := time.Time{}
|
||||||
|
err := t.UnmarshalText(value)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return t
|
||||||
|
case string:
|
||||||
|
return unserializeDateTime([]byte(value))
|
||||||
|
case *string:
|
||||||
|
return unserializeDateTime([]byte(*value))
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var DateTime = NewScalar(ScalarConfig{
|
||||||
|
Name: "DateTime",
|
||||||
|
Description: "The `DateTime` scalar type represents a DateTime." +
|
||||||
|
" The DateTime is serialized as an RFC 3339 quoted string",
|
||||||
|
Serialize: serializeDateTime,
|
||||||
|
ParseValue: unserializeDateTime,
|
||||||
|
ParseLiteral: func(valueAST ast.Value) interface{} {
|
||||||
|
switch valueAST := valueAST.(type) {
|
||||||
|
case *ast.StringValue:
|
||||||
|
return valueAST.Value
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
70
vendor/github.com/graphql-go/graphql/schema-kitchen-sink.graphql
generated
vendored
Normal file
70
vendor/github.com/graphql-go/graphql/schema-kitchen-sink.graphql
generated
vendored
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
# Filename: schema-kitchen-sink.graphql
|
||||||
|
|
||||||
|
schema {
|
||||||
|
query: QueryType
|
||||||
|
mutation: MutationType
|
||||||
|
}
|
||||||
|
|
||||||
|
type Foo implements Bar {
|
||||||
|
one: Type
|
||||||
|
two(argument: InputType!): Type
|
||||||
|
three(argument: InputType, other: String): Int
|
||||||
|
four(argument: String = "string"): String
|
||||||
|
five(argument: [String] = ["string", "string"]): String
|
||||||
|
six(argument: InputType = {key: "value"}): Type
|
||||||
|
}
|
||||||
|
|
||||||
|
type AnnotatedObject @onObject(arg: "value") {
|
||||||
|
annotatedField(arg: Type = "default" @onArg): Type @onField
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Bar {
|
||||||
|
one: Type
|
||||||
|
four(argument: String = "string"): String
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AnnotatedInterface @onInterface {
|
||||||
|
annotatedField(arg: Type @onArg): Type @onField
|
||||||
|
}
|
||||||
|
|
||||||
|
union Feed = Story | Article | Advert
|
||||||
|
|
||||||
|
union AnnotatedUnion @onUnion = A | B
|
||||||
|
|
||||||
|
scalar CustomScalar
|
||||||
|
|
||||||
|
scalar AnnotatedScalar @onScalar
|
||||||
|
|
||||||
|
enum Site {
|
||||||
|
DESKTOP
|
||||||
|
MOBILE
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AnnotatedEnum @onEnum {
|
||||||
|
ANNOTATED_VALUE @onEnumValue
|
||||||
|
OTHER_VALUE
|
||||||
|
}
|
||||||
|
|
||||||
|
input InputType {
|
||||||
|
key: String!
|
||||||
|
answer: Int = 42
|
||||||
|
}
|
||||||
|
|
||||||
|
input AnnotatedInput @onInputObjectType {
|
||||||
|
annotatedField: Type @onField
|
||||||
|
}
|
||||||
|
|
||||||
|
extend type Foo {
|
||||||
|
seven(argument: [String]): Type
|
||||||
|
}
|
||||||
|
|
||||||
|
extend type Foo @onType {}
|
||||||
|
|
||||||
|
type NoFields {}
|
||||||
|
|
||||||
|
directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
|
||||||
|
|
||||||
|
directive @include(if: Boolean!)
|
||||||
|
on FIELD
|
||||||
|
| FRAGMENT_SPREAD
|
||||||
|
| INLINE_FRAGMENT
|
566
vendor/github.com/graphql-go/graphql/schema.go
generated
vendored
Normal file
566
vendor/github.com/graphql-go/graphql/schema.go
generated
vendored
Normal file
@ -0,0 +1,566 @@
|
|||||||
|
package graphql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SchemaConfig struct {
|
||||||
|
Query *Object
|
||||||
|
Mutation *Object
|
||||||
|
Subscription *Object
|
||||||
|
Types []Type
|
||||||
|
Directives []*Directive
|
||||||
|
}
|
||||||
|
|
||||||
|
type TypeMap map[string]Type
|
||||||
|
|
||||||
|
// Schema Definition
|
||||||
|
// A Schema is created by supplying the root types of each type of operation,
|
||||||
|
// query, mutation (optional) and subscription (optional). A schema definition is then supplied to the
|
||||||
|
// validator and executor.
|
||||||
|
// Example:
|
||||||
|
// myAppSchema, err := NewSchema(SchemaConfig({
|
||||||
|
// Query: MyAppQueryRootType,
|
||||||
|
// Mutation: MyAppMutationRootType,
|
||||||
|
// Subscription: MyAppSubscriptionRootType,
|
||||||
|
// });
|
||||||
|
// Note: If an array of `directives` are provided to GraphQLSchema, that will be
|
||||||
|
// the exact list of directives represented and allowed. If `directives` is not
|
||||||
|
// provided then a default set of the specified directives (e.g. @include and
|
||||||
|
// @skip) will be used. If you wish to provide *additional* directives to these
|
||||||
|
// specified directives, you must explicitly declare them. Example:
|
||||||
|
//
|
||||||
|
// const MyAppSchema = new GraphQLSchema({
|
||||||
|
// ...
|
||||||
|
// directives: specifiedDirectives.concat([ myCustomDirective ]),
|
||||||
|
// })
|
||||||
|
type Schema struct {
|
||||||
|
typeMap TypeMap
|
||||||
|
directives []*Directive
|
||||||
|
|
||||||
|
queryType *Object
|
||||||
|
mutationType *Object
|
||||||
|
subscriptionType *Object
|
||||||
|
implementations map[string][]*Object
|
||||||
|
possibleTypeMap map[string]map[string]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSchema(config SchemaConfig) (Schema, error) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
schema := Schema{}
|
||||||
|
|
||||||
|
err = invariant(config.Query != nil, "Schema query must be Object Type but got: nil.")
|
||||||
|
if err != nil {
|
||||||
|
return schema, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// if schema config contains error at creation time, return those errors
|
||||||
|
if config.Query != nil && config.Query.err != nil {
|
||||||
|
return schema, config.Query.err
|
||||||
|
}
|
||||||
|
if config.Mutation != nil && config.Mutation.err != nil {
|
||||||
|
return schema, config.Mutation.err
|
||||||
|
}
|
||||||
|
|
||||||
|
schema.queryType = config.Query
|
||||||
|
schema.mutationType = config.Mutation
|
||||||
|
schema.subscriptionType = config.Subscription
|
||||||
|
|
||||||
|
// Provide specified directives (e.g. @include and @skip) by default.
|
||||||
|
schema.directives = config.Directives
|
||||||
|
if len(schema.directives) == 0 {
|
||||||
|
schema.directives = SpecifiedDirectives
|
||||||
|
}
|
||||||
|
// Ensure directive definitions are error-free
|
||||||
|
for _, dir := range schema.directives {
|
||||||
|
if dir.err != nil {
|
||||||
|
return schema, dir.err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build type map now to detect any errors within this schema.
|
||||||
|
typeMap := TypeMap{}
|
||||||
|
initialTypes := []Type{}
|
||||||
|
if schema.QueryType() != nil {
|
||||||
|
initialTypes = append(initialTypes, schema.QueryType())
|
||||||
|
}
|
||||||
|
if schema.MutationType() != nil {
|
||||||
|
initialTypes = append(initialTypes, schema.MutationType())
|
||||||
|
}
|
||||||
|
if schema.SubscriptionType() != nil {
|
||||||
|
initialTypes = append(initialTypes, schema.SubscriptionType())
|
||||||
|
}
|
||||||
|
if SchemaType != nil {
|
||||||
|
initialTypes = append(initialTypes, SchemaType)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ttype := range config.Types {
|
||||||
|
// assume that user will never add a nil object to config
|
||||||
|
initialTypes = append(initialTypes, ttype)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ttype := range initialTypes {
|
||||||
|
if ttype.Error() != nil {
|
||||||
|
return schema, ttype.Error()
|
||||||
|
}
|
||||||
|
typeMap, err = typeMapReducer(&schema, typeMap, ttype)
|
||||||
|
if err != nil {
|
||||||
|
return schema, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
schema.typeMap = typeMap
|
||||||
|
|
||||||
|
// Keep track of all implementations by interface name.
|
||||||
|
if schema.implementations == nil {
|
||||||
|
schema.implementations = map[string][]*Object{}
|
||||||
|
}
|
||||||
|
for _, ttype := range schema.typeMap {
|
||||||
|
if ttype, ok := ttype.(*Object); ok {
|
||||||
|
for _, iface := range ttype.Interfaces() {
|
||||||
|
impls, ok := schema.implementations[iface.Name()]
|
||||||
|
if impls == nil || !ok {
|
||||||
|
impls = []*Object{}
|
||||||
|
}
|
||||||
|
impls = append(impls, ttype)
|
||||||
|
schema.implementations[iface.Name()] = impls
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enforce correct interface implementations
|
||||||
|
for _, ttype := range schema.typeMap {
|
||||||
|
if ttype, ok := ttype.(*Object); ok {
|
||||||
|
for _, iface := range ttype.Interfaces() {
|
||||||
|
err := assertObjectImplementsInterface(&schema, ttype, iface)
|
||||||
|
if err != nil {
|
||||||
|
return schema, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return schema, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Added Check implementation of interfaces at runtime..
|
||||||
|
//Add Implementations at Runtime..
|
||||||
|
func (gq *Schema) AddImplementation() error{
|
||||||
|
|
||||||
|
// Keep track of all implementations by interface name.
|
||||||
|
if gq.implementations == nil {
|
||||||
|
gq.implementations = map[string][]*Object{}
|
||||||
|
}
|
||||||
|
for _, ttype := range gq.typeMap {
|
||||||
|
if ttype, ok := ttype.(*Object); ok {
|
||||||
|
for _, iface := range ttype.Interfaces() {
|
||||||
|
impls, ok := gq.implementations[iface.Name()]
|
||||||
|
if impls == nil || !ok {
|
||||||
|
impls = []*Object{}
|
||||||
|
}
|
||||||
|
impls = append(impls, ttype)
|
||||||
|
gq.implementations[iface.Name()] = impls
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enforce correct interface implementations
|
||||||
|
for _, ttype := range gq.typeMap {
|
||||||
|
if ttype, ok := ttype.(*Object); ok {
|
||||||
|
for _, iface := range ttype.Interfaces() {
|
||||||
|
err := assertObjectImplementsInterface(gq, ttype, iface)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Edited. To check add Types at RunTime..
|
||||||
|
//Append Runtime schema to typeMap
|
||||||
|
func (gq *Schema)AppendType(objectType Type) error {
|
||||||
|
if objectType.Error() != nil {
|
||||||
|
return objectType.Error()
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
gq.typeMap, err = typeMapReducer(gq, gq.typeMap, objectType)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//Now Add interface implementation..
|
||||||
|
return gq.AddImplementation()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func (gq *Schema) QueryType() *Object {
|
||||||
|
return gq.queryType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gq *Schema) MutationType() *Object {
|
||||||
|
return gq.mutationType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gq *Schema) SubscriptionType() *Object {
|
||||||
|
return gq.subscriptionType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gq *Schema) Directives() []*Directive {
|
||||||
|
return gq.directives
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gq *Schema) Directive(name string) *Directive {
|
||||||
|
for _, directive := range gq.Directives() {
|
||||||
|
if directive.Name == name {
|
||||||
|
return directive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gq *Schema) TypeMap() TypeMap {
|
||||||
|
return gq.typeMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gq *Schema) Type(name string) Type {
|
||||||
|
return gq.TypeMap()[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gq *Schema) PossibleTypes(abstractType Abstract) []*Object {
|
||||||
|
if abstractType, ok := abstractType.(*Union); ok {
|
||||||
|
return abstractType.Types()
|
||||||
|
}
|
||||||
|
if abstractType, ok := abstractType.(*Interface); ok {
|
||||||
|
if impls, ok := gq.implementations[abstractType.Name()]; ok {
|
||||||
|
return impls
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return []*Object{}
|
||||||
|
}
|
||||||
|
func (gq *Schema) IsPossibleType(abstractType Abstract, possibleType *Object) bool {
|
||||||
|
possibleTypeMap := gq.possibleTypeMap
|
||||||
|
if possibleTypeMap == nil {
|
||||||
|
possibleTypeMap = map[string]map[string]bool{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if typeMap, ok := possibleTypeMap[abstractType.Name()]; !ok {
|
||||||
|
typeMap = map[string]bool{}
|
||||||
|
for _, possibleType := range gq.PossibleTypes(abstractType) {
|
||||||
|
typeMap[possibleType.Name()] = true
|
||||||
|
}
|
||||||
|
possibleTypeMap[abstractType.Name()] = typeMap
|
||||||
|
}
|
||||||
|
|
||||||
|
gq.possibleTypeMap = possibleTypeMap
|
||||||
|
if typeMap, ok := possibleTypeMap[abstractType.Name()]; ok {
|
||||||
|
isPossible, _ := typeMap[possibleType.Name()]
|
||||||
|
return isPossible
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
func typeMapReducer(schema *Schema, typeMap TypeMap, objectType Type) (TypeMap, error) {
|
||||||
|
var err error
|
||||||
|
if objectType == nil || objectType.Name() == "" {
|
||||||
|
return typeMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch objectType := objectType.(type) {
|
||||||
|
case *List:
|
||||||
|
if objectType.OfType != nil {
|
||||||
|
return typeMapReducer(schema, typeMap, objectType.OfType)
|
||||||
|
}
|
||||||
|
case *NonNull:
|
||||||
|
if objectType.OfType != nil {
|
||||||
|
return typeMapReducer(schema, typeMap, objectType.OfType)
|
||||||
|
}
|
||||||
|
case *Object:
|
||||||
|
if objectType.err != nil {
|
||||||
|
return typeMap, objectType.err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if mappedObjectType, ok := typeMap[objectType.Name()]; ok {
|
||||||
|
err = invariantf(
|
||||||
|
mappedObjectType == objectType,
|
||||||
|
`Schema must contain unique named types but contains multiple types named "%v".`, objectType.Name())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return typeMap, err
|
||||||
|
}
|
||||||
|
return typeMap, err
|
||||||
|
}
|
||||||
|
if objectType.Name() == "" {
|
||||||
|
return typeMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
typeMap[objectType.Name()] = objectType
|
||||||
|
|
||||||
|
switch objectType := objectType.(type) {
|
||||||
|
case *Union:
|
||||||
|
types := schema.PossibleTypes(objectType)
|
||||||
|
if objectType.err != nil {
|
||||||
|
return typeMap, objectType.err
|
||||||
|
}
|
||||||
|
for _, innerObjectType := range types {
|
||||||
|
if innerObjectType.err != nil {
|
||||||
|
return typeMap, innerObjectType.err
|
||||||
|
}
|
||||||
|
typeMap, err = typeMapReducer(schema, typeMap, innerObjectType)
|
||||||
|
if err != nil {
|
||||||
|
return typeMap, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case *Interface:
|
||||||
|
types := schema.PossibleTypes(objectType)
|
||||||
|
if objectType.err != nil {
|
||||||
|
return typeMap, objectType.err
|
||||||
|
}
|
||||||
|
for _, innerObjectType := range types {
|
||||||
|
if innerObjectType.err != nil {
|
||||||
|
return typeMap, innerObjectType.err
|
||||||
|
}
|
||||||
|
typeMap, err = typeMapReducer(schema, typeMap, innerObjectType)
|
||||||
|
if err != nil {
|
||||||
|
return typeMap, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case *Object:
|
||||||
|
interfaces := objectType.Interfaces()
|
||||||
|
if objectType.err != nil {
|
||||||
|
return typeMap, objectType.err
|
||||||
|
}
|
||||||
|
for _, innerObjectType := range interfaces {
|
||||||
|
if innerObjectType.err != nil {
|
||||||
|
return typeMap, innerObjectType.err
|
||||||
|
}
|
||||||
|
typeMap, err = typeMapReducer(schema, typeMap, innerObjectType)
|
||||||
|
if err != nil {
|
||||||
|
return typeMap, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch objectType := objectType.(type) {
|
||||||
|
case *Object:
|
||||||
|
fieldMap := objectType.Fields()
|
||||||
|
if objectType.err != nil {
|
||||||
|
return typeMap, objectType.err
|
||||||
|
}
|
||||||
|
for _, field := range fieldMap {
|
||||||
|
for _, arg := range field.Args {
|
||||||
|
typeMap, err = typeMapReducer(schema, typeMap, arg.Type)
|
||||||
|
if err != nil {
|
||||||
|
return typeMap, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
typeMap, err = typeMapReducer(schema, typeMap, field.Type)
|
||||||
|
if err != nil {
|
||||||
|
return typeMap, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case *Interface:
|
||||||
|
fieldMap := objectType.Fields()
|
||||||
|
if objectType.err != nil {
|
||||||
|
return typeMap, objectType.err
|
||||||
|
}
|
||||||
|
for _, field := range fieldMap {
|
||||||
|
for _, arg := range field.Args {
|
||||||
|
typeMap, err = typeMapReducer(schema, typeMap, arg.Type)
|
||||||
|
if err != nil {
|
||||||
|
return typeMap, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
typeMap, err = typeMapReducer(schema, typeMap, field.Type)
|
||||||
|
if err != nil {
|
||||||
|
return typeMap, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case *InputObject:
|
||||||
|
fieldMap := objectType.Fields()
|
||||||
|
if objectType.err != nil {
|
||||||
|
return typeMap, objectType.err
|
||||||
|
}
|
||||||
|
for _, field := range fieldMap {
|
||||||
|
typeMap, err = typeMapReducer(schema, typeMap, field.Type)
|
||||||
|
if err != nil {
|
||||||
|
return typeMap, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return typeMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertObjectImplementsInterface(schema *Schema, object *Object, iface *Interface) error {
|
||||||
|
objectFieldMap := object.Fields()
|
||||||
|
ifaceFieldMap := iface.Fields()
|
||||||
|
|
||||||
|
// Assert each interface field is implemented.
|
||||||
|
for fieldName := range ifaceFieldMap {
|
||||||
|
objectField := objectFieldMap[fieldName]
|
||||||
|
ifaceField := ifaceFieldMap[fieldName]
|
||||||
|
|
||||||
|
// Assert interface field exists on object.
|
||||||
|
err := invariantf(
|
||||||
|
objectField != nil,
|
||||||
|
`"%v" expects field "%v" but "%v" does not `+
|
||||||
|
`provide it.`, iface, fieldName, object)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assert interface field type is satisfied by object field type, by being
|
||||||
|
// a valid subtype. (covariant)
|
||||||
|
err = invariant(
|
||||||
|
isTypeSubTypeOf(schema, objectField.Type, ifaceField.Type),
|
||||||
|
fmt.Sprintf(`%v.%v expects type "%v" but `+
|
||||||
|
`%v.%v provides type "%v".`,
|
||||||
|
iface, fieldName, ifaceField.Type,
|
||||||
|
object, fieldName, objectField.Type),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assert each interface field arg is implemented.
|
||||||
|
for _, ifaceArg := range ifaceField.Args {
|
||||||
|
argName := ifaceArg.PrivateName
|
||||||
|
var objectArg *Argument
|
||||||
|
for _, arg := range objectField.Args {
|
||||||
|
if arg.PrivateName == argName {
|
||||||
|
objectArg = arg
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Assert interface field arg exists on object field.
|
||||||
|
err = invariant(
|
||||||
|
objectArg != nil,
|
||||||
|
fmt.Sprintf(`%v.%v expects argument "%v" but `+
|
||||||
|
`%v.%v does not provide it.`,
|
||||||
|
iface, fieldName, argName,
|
||||||
|
object, fieldName),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assert interface field arg type matches object field arg type.
|
||||||
|
// (invariant)
|
||||||
|
err = invariant(
|
||||||
|
isEqualType(ifaceArg.Type, objectArg.Type),
|
||||||
|
fmt.Sprintf(
|
||||||
|
`%v.%v(%v:) expects type "%v" `+
|
||||||
|
`but %v.%v(%v:) provides `+
|
||||||
|
`type "%v".`,
|
||||||
|
iface, fieldName, argName, ifaceArg.Type,
|
||||||
|
object, fieldName, argName, objectArg.Type),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Assert additional arguments must not be required.
|
||||||
|
for _, objectArg := range objectField.Args {
|
||||||
|
argName := objectArg.PrivateName
|
||||||
|
var ifaceArg *Argument
|
||||||
|
for _, arg := range ifaceField.Args {
|
||||||
|
if arg.PrivateName == argName {
|
||||||
|
ifaceArg = arg
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ifaceArg == nil {
|
||||||
|
_, ok := objectArg.Type.(*NonNull)
|
||||||
|
err = invariant(
|
||||||
|
!ok,
|
||||||
|
fmt.Sprintf(`%v.%v(%v:) is of required type `+
|
||||||
|
`"%v" but is not also provided by the interface %v.%v.`,
|
||||||
|
object, fieldName, argName,
|
||||||
|
objectArg.Type, iface, fieldName),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isEqualType(typeA Type, typeB Type) bool {
|
||||||
|
// Equivalent type is a valid subtype
|
||||||
|
if typeA == typeB {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// If either type is non-null, the other must also be non-null.
|
||||||
|
if typeA, ok := typeA.(*NonNull); ok {
|
||||||
|
if typeB, ok := typeB.(*NonNull); ok {
|
||||||
|
return isEqualType(typeA.OfType, typeB.OfType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If either type is a list, the other must also be a list.
|
||||||
|
if typeA, ok := typeA.(*List); ok {
|
||||||
|
if typeB, ok := typeB.(*List); ok {
|
||||||
|
return isEqualType(typeA.OfType, typeB.OfType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Otherwise the types are not equal.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// isTypeSubTypeOf Provided a type and a super type, return true if the first type is either
|
||||||
|
// equal or a subset of the second super type (covariant).
|
||||||
|
func isTypeSubTypeOf(schema *Schema, maybeSubType Type, superType Type) bool {
|
||||||
|
// Equivalent type is a valid subtype
|
||||||
|
if maybeSubType == superType {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// If superType is non-null, maybeSubType must also be nullable.
|
||||||
|
if superType, ok := superType.(*NonNull); ok {
|
||||||
|
if maybeSubType, ok := maybeSubType.(*NonNull); ok {
|
||||||
|
return isTypeSubTypeOf(schema, maybeSubType.OfType, superType.OfType)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if maybeSubType, ok := maybeSubType.(*NonNull); ok {
|
||||||
|
// If superType is nullable, maybeSubType may be non-null.
|
||||||
|
return isTypeSubTypeOf(schema, maybeSubType.OfType, superType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If superType type is a list, maybeSubType type must also be a list.
|
||||||
|
if superType, ok := superType.(*List); ok {
|
||||||
|
if maybeSubType, ok := maybeSubType.(*List); ok {
|
||||||
|
return isTypeSubTypeOf(schema, maybeSubType.OfType, superType.OfType)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
} else if _, ok := maybeSubType.(*List); ok {
|
||||||
|
// If superType is not a list, maybeSubType must also be not a list.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// If superType type is an abstract type, maybeSubType type may be a currently
|
||||||
|
// possible object type.
|
||||||
|
if superType, ok := superType.(*Interface); ok {
|
||||||
|
if maybeSubType, ok := maybeSubType.(*Object); ok && schema.IsPossibleType(superType, maybeSubType) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if superType, ok := superType.(*Union); ok {
|
||||||
|
if maybeSubType, ok := maybeSubType.(*Object); ok && schema.IsPossibleType(superType, maybeSubType) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, the child type is not a valid subtype of the parent type.
|
||||||
|
return false
|
||||||
|
}
|
276
vendor/github.com/graphql-go/graphql/type_info.go
generated
vendored
Normal file
276
vendor/github.com/graphql-go/graphql/type_info.go
generated
vendored
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
package graphql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/graphql-go/graphql/language/ast"
|
||||||
|
"github.com/graphql-go/graphql/language/kinds"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: can move TypeInfo to a utils package if there ever is one
|
||||||
|
/**
|
||||||
|
* TypeInfo is a utility class which, given a GraphQL schema, can keep track
|
||||||
|
* of the current field and type definitions at any point in a GraphQL document
|
||||||
|
* AST during a recursive descent by calling `enter(node)` and `leave(node)`.
|
||||||
|
*/
|
||||||
|
type fieldDefFn func(schema *Schema, parentType Type, fieldAST *ast.Field) *FieldDefinition
|
||||||
|
|
||||||
|
type TypeInfo struct {
|
||||||
|
schema *Schema
|
||||||
|
typeStack []Output
|
||||||
|
parentTypeStack []Composite
|
||||||
|
inputTypeStack []Input
|
||||||
|
fieldDefStack []*FieldDefinition
|
||||||
|
directive *Directive
|
||||||
|
argument *Argument
|
||||||
|
getFieldDef fieldDefFn
|
||||||
|
}
|
||||||
|
|
||||||
|
type TypeInfoConfig struct {
|
||||||
|
Schema *Schema
|
||||||
|
|
||||||
|
// NOTE: this experimental optional second parameter is only needed in order
|
||||||
|
// to support non-spec-compliant codebases. You should never need to use it.
|
||||||
|
// It may disappear in the future.
|
||||||
|
FieldDefFn fieldDefFn
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTypeInfo(opts *TypeInfoConfig) *TypeInfo {
|
||||||
|
getFieldDef := opts.FieldDefFn
|
||||||
|
if getFieldDef == nil {
|
||||||
|
getFieldDef = DefaultTypeInfoFieldDef
|
||||||
|
}
|
||||||
|
return &TypeInfo{
|
||||||
|
schema: opts.Schema,
|
||||||
|
getFieldDef: getFieldDef,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ti *TypeInfo) Type() Output {
|
||||||
|
if len(ti.typeStack) > 0 {
|
||||||
|
return ti.typeStack[len(ti.typeStack)-1]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ti *TypeInfo) ParentType() Composite {
|
||||||
|
if len(ti.parentTypeStack) > 0 {
|
||||||
|
return ti.parentTypeStack[len(ti.parentTypeStack)-1]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ti *TypeInfo) InputType() Input {
|
||||||
|
if len(ti.inputTypeStack) > 0 {
|
||||||
|
return ti.inputTypeStack[len(ti.inputTypeStack)-1]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (ti *TypeInfo) FieldDef() *FieldDefinition {
|
||||||
|
if len(ti.fieldDefStack) > 0 {
|
||||||
|
return ti.fieldDefStack[len(ti.fieldDefStack)-1]
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ti *TypeInfo) Directive() *Directive {
|
||||||
|
return ti.directive
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ti *TypeInfo) Argument() *Argument {
|
||||||
|
return ti.argument
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ti *TypeInfo) Enter(node ast.Node) {
|
||||||
|
|
||||||
|
schema := ti.schema
|
||||||
|
var ttype Type
|
||||||
|
switch node := node.(type) {
|
||||||
|
case *ast.SelectionSet:
|
||||||
|
namedType := GetNamed(ti.Type())
|
||||||
|
var compositeType Composite
|
||||||
|
if IsCompositeType(namedType) {
|
||||||
|
compositeType, _ = namedType.(Composite)
|
||||||
|
}
|
||||||
|
ti.parentTypeStack = append(ti.parentTypeStack, compositeType)
|
||||||
|
case *ast.Field:
|
||||||
|
parentType := ti.ParentType()
|
||||||
|
var fieldDef *FieldDefinition
|
||||||
|
if parentType != nil {
|
||||||
|
fieldDef = ti.getFieldDef(schema, parentType.(Type), node)
|
||||||
|
}
|
||||||
|
ti.fieldDefStack = append(ti.fieldDefStack, fieldDef)
|
||||||
|
if fieldDef != nil {
|
||||||
|
ti.typeStack = append(ti.typeStack, fieldDef.Type)
|
||||||
|
} else {
|
||||||
|
ti.typeStack = append(ti.typeStack, nil)
|
||||||
|
}
|
||||||
|
case *ast.Directive:
|
||||||
|
nameVal := ""
|
||||||
|
if node.Name != nil {
|
||||||
|
nameVal = node.Name.Value
|
||||||
|
}
|
||||||
|
ti.directive = schema.Directive(nameVal)
|
||||||
|
case *ast.OperationDefinition:
|
||||||
|
if node.Operation == ast.OperationTypeQuery {
|
||||||
|
ttype = schema.QueryType()
|
||||||
|
} else if node.Operation == ast.OperationTypeMutation {
|
||||||
|
ttype = schema.MutationType()
|
||||||
|
} else if node.Operation == ast.OperationTypeSubscription {
|
||||||
|
ttype = schema.SubscriptionType()
|
||||||
|
}
|
||||||
|
ti.typeStack = append(ti.typeStack, ttype)
|
||||||
|
case *ast.InlineFragment:
|
||||||
|
typeConditionAST := node.TypeCondition
|
||||||
|
if typeConditionAST != nil {
|
||||||
|
ttype, _ = typeFromAST(*schema, node.TypeCondition)
|
||||||
|
ti.typeStack = append(ti.typeStack, ttype)
|
||||||
|
} else {
|
||||||
|
ti.typeStack = append(ti.typeStack, ti.Type())
|
||||||
|
}
|
||||||
|
case *ast.FragmentDefinition:
|
||||||
|
typeConditionAST := node.TypeCondition
|
||||||
|
if typeConditionAST != nil {
|
||||||
|
ttype, _ = typeFromAST(*schema, typeConditionAST)
|
||||||
|
ti.typeStack = append(ti.typeStack, ttype)
|
||||||
|
} else {
|
||||||
|
ti.typeStack = append(ti.typeStack, ti.Type())
|
||||||
|
}
|
||||||
|
case *ast.VariableDefinition:
|
||||||
|
ttype, _ = typeFromAST(*schema, node.Type)
|
||||||
|
ti.inputTypeStack = append(ti.inputTypeStack, ttype)
|
||||||
|
case *ast.Argument:
|
||||||
|
nameVal := ""
|
||||||
|
if node.Name != nil {
|
||||||
|
nameVal = node.Name.Value
|
||||||
|
}
|
||||||
|
var argType Input
|
||||||
|
var argDef *Argument
|
||||||
|
directive := ti.Directive()
|
||||||
|
fieldDef := ti.FieldDef()
|
||||||
|
if directive != nil {
|
||||||
|
for _, arg := range directive.Args {
|
||||||
|
if arg.Name() == nameVal {
|
||||||
|
argDef = arg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if fieldDef != nil {
|
||||||
|
for _, arg := range fieldDef.Args {
|
||||||
|
if arg.Name() == nameVal {
|
||||||
|
argDef = arg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if argDef != nil {
|
||||||
|
argType = argDef.Type
|
||||||
|
}
|
||||||
|
ti.argument = argDef
|
||||||
|
ti.inputTypeStack = append(ti.inputTypeStack, argType)
|
||||||
|
case *ast.ListValue:
|
||||||
|
listType := GetNullable(ti.InputType())
|
||||||
|
if list, ok := listType.(*List); ok {
|
||||||
|
ti.inputTypeStack = append(ti.inputTypeStack, list.OfType)
|
||||||
|
} else {
|
||||||
|
ti.inputTypeStack = append(ti.inputTypeStack, nil)
|
||||||
|
}
|
||||||
|
case *ast.ObjectField:
|
||||||
|
var fieldType Input
|
||||||
|
objectType := GetNamed(ti.InputType())
|
||||||
|
|
||||||
|
if objectType, ok := objectType.(*InputObject); ok {
|
||||||
|
nameVal := ""
|
||||||
|
if node.Name != nil {
|
||||||
|
nameVal = node.Name.Value
|
||||||
|
}
|
||||||
|
if inputField, ok := objectType.Fields()[nameVal]; ok {
|
||||||
|
fieldType = inputField.Type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ti.inputTypeStack = append(ti.inputTypeStack, fieldType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (ti *TypeInfo) Leave(node ast.Node) {
|
||||||
|
kind := node.GetKind()
|
||||||
|
switch kind {
|
||||||
|
case kinds.SelectionSet:
|
||||||
|
// pop ti.parentTypeStack
|
||||||
|
if len(ti.parentTypeStack) > 0 {
|
||||||
|
_, ti.parentTypeStack = ti.parentTypeStack[len(ti.parentTypeStack)-1], ti.parentTypeStack[:len(ti.parentTypeStack)-1]
|
||||||
|
}
|
||||||
|
case kinds.Field:
|
||||||
|
// pop ti.fieldDefStack
|
||||||
|
if len(ti.fieldDefStack) > 0 {
|
||||||
|
_, ti.fieldDefStack = ti.fieldDefStack[len(ti.fieldDefStack)-1], ti.fieldDefStack[:len(ti.fieldDefStack)-1]
|
||||||
|
}
|
||||||
|
// pop ti.typeStack
|
||||||
|
if len(ti.typeStack) > 0 {
|
||||||
|
_, ti.typeStack = ti.typeStack[len(ti.typeStack)-1], ti.typeStack[:len(ti.typeStack)-1]
|
||||||
|
}
|
||||||
|
case kinds.Directive:
|
||||||
|
ti.directive = nil
|
||||||
|
case kinds.OperationDefinition:
|
||||||
|
fallthrough
|
||||||
|
case kinds.InlineFragment:
|
||||||
|
fallthrough
|
||||||
|
case kinds.FragmentDefinition:
|
||||||
|
// pop ti.typeStack
|
||||||
|
if len(ti.typeStack) > 0 {
|
||||||
|
_, ti.typeStack = ti.typeStack[len(ti.typeStack)-1], ti.typeStack[:len(ti.typeStack)-1]
|
||||||
|
}
|
||||||
|
case kinds.VariableDefinition:
|
||||||
|
// pop ti.inputTypeStack
|
||||||
|
if len(ti.inputTypeStack) > 0 {
|
||||||
|
_, ti.inputTypeStack = ti.inputTypeStack[len(ti.inputTypeStack)-1], ti.inputTypeStack[:len(ti.inputTypeStack)-1]
|
||||||
|
}
|
||||||
|
case kinds.Argument:
|
||||||
|
ti.argument = nil
|
||||||
|
// pop ti.inputTypeStack
|
||||||
|
if len(ti.inputTypeStack) > 0 {
|
||||||
|
_, ti.inputTypeStack = ti.inputTypeStack[len(ti.inputTypeStack)-1], ti.inputTypeStack[:len(ti.inputTypeStack)-1]
|
||||||
|
}
|
||||||
|
case kinds.ListValue:
|
||||||
|
fallthrough
|
||||||
|
case kinds.ObjectField:
|
||||||
|
// pop ti.inputTypeStack
|
||||||
|
if len(ti.inputTypeStack) > 0 {
|
||||||
|
_, ti.inputTypeStack = ti.inputTypeStack[len(ti.inputTypeStack)-1], ti.inputTypeStack[:len(ti.inputTypeStack)-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultTypeInfoFieldDef Not exactly the same as the executor's definition of FieldDef, in this
|
||||||
|
// statically evaluated environment we do not always have an Object type,
|
||||||
|
// and need to handle Interface and Union types.
|
||||||
|
func DefaultTypeInfoFieldDef(schema *Schema, parentType Type, fieldAST *ast.Field) *FieldDefinition {
|
||||||
|
name := ""
|
||||||
|
if fieldAST.Name != nil {
|
||||||
|
name = fieldAST.Name.Value
|
||||||
|
}
|
||||||
|
if name == SchemaMetaFieldDef.Name &&
|
||||||
|
schema.QueryType() == parentType {
|
||||||
|
return SchemaMetaFieldDef
|
||||||
|
}
|
||||||
|
if name == TypeMetaFieldDef.Name &&
|
||||||
|
schema.QueryType() == parentType {
|
||||||
|
return TypeMetaFieldDef
|
||||||
|
}
|
||||||
|
if name == TypeNameMetaFieldDef.Name && parentType != nil {
|
||||||
|
if t, ok := parentType.(*Object); ok && t != nil {
|
||||||
|
return TypeNameMetaFieldDef
|
||||||
|
}
|
||||||
|
if t, ok := parentType.(*Interface); ok && t != nil {
|
||||||
|
return TypeNameMetaFieldDef
|
||||||
|
}
|
||||||
|
if t, ok := parentType.(*Union); ok && t != nil {
|
||||||
|
return TypeNameMetaFieldDef
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if parentType, ok := parentType.(*Object); ok && parentType != nil {
|
||||||
|
field, _ := parentType.Fields()[name]
|
||||||
|
return field
|
||||||
|
}
|
||||||
|
if parentType, ok := parentType.(*Interface); ok && parentType != nil {
|
||||||
|
field, _ := parentType.Fields()[name]
|
||||||
|
return field
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
16
vendor/github.com/graphql-go/graphql/types.go
generated
vendored
Normal file
16
vendor/github.com/graphql-go/graphql/types.go
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package graphql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/graphql-go/graphql/gqlerrors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// type Schema interface{}
|
||||||
|
|
||||||
|
type Result struct {
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
Errors []gqlerrors.FormattedError `json:"errors,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Result) HasErrors() bool {
|
||||||
|
return len(r.Errors) > 0
|
||||||
|
}
|
180
vendor/github.com/graphql-go/graphql/util.go
generated
vendored
Normal file
180
vendor/github.com/graphql-go/graphql/util.go
generated
vendored
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
package graphql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const TAG = "json"
|
||||||
|
|
||||||
|
// can't take recursive slice type
|
||||||
|
// e.g
|
||||||
|
// type Person struct{
|
||||||
|
// Friends []Person
|
||||||
|
// }
|
||||||
|
// it will throw panic stack-overflow
|
||||||
|
func BindFields(obj interface{}) Fields {
|
||||||
|
v := reflect.ValueOf(obj)
|
||||||
|
fields := make(map[string]*Field)
|
||||||
|
|
||||||
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
typeField := v.Type().Field(i)
|
||||||
|
|
||||||
|
tag := extractTag(typeField.Tag)
|
||||||
|
if tag == "-" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var graphType Output
|
||||||
|
if typeField.Type.Kind() == reflect.Struct {
|
||||||
|
|
||||||
|
structFields := BindFields(v.Field(i).Interface())
|
||||||
|
if tag == "" {
|
||||||
|
fields = appendFields(fields, structFields)
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
graphType = NewObject(ObjectConfig{
|
||||||
|
Name: tag,
|
||||||
|
Fields: structFields,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if tag == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if graphType == nil {
|
||||||
|
graphType = getGraphType(typeField.Type)
|
||||||
|
}
|
||||||
|
fields[tag] = &Field{
|
||||||
|
Type: graphType,
|
||||||
|
Resolve: func(p ResolveParams) (interface{}, error) {
|
||||||
|
return extractValue(tag, p.Source), nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGraphType(tipe reflect.Type) Output {
|
||||||
|
kind := tipe.Kind()
|
||||||
|
switch kind {
|
||||||
|
case reflect.String:
|
||||||
|
return String
|
||||||
|
case reflect.Int:
|
||||||
|
fallthrough
|
||||||
|
case reflect.Int8:
|
||||||
|
fallthrough
|
||||||
|
case reflect.Int32:
|
||||||
|
fallthrough
|
||||||
|
case reflect.Int64:
|
||||||
|
return Int
|
||||||
|
case reflect.Float32:
|
||||||
|
fallthrough
|
||||||
|
case reflect.Float64:
|
||||||
|
return Float
|
||||||
|
case reflect.Bool:
|
||||||
|
return Boolean
|
||||||
|
case reflect.Slice:
|
||||||
|
return getGraphList(tipe)
|
||||||
|
}
|
||||||
|
return String
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGraphList(tipe reflect.Type) *List {
|
||||||
|
if tipe.Kind() == reflect.Slice {
|
||||||
|
switch tipe.Elem().Kind() {
|
||||||
|
case reflect.Int:
|
||||||
|
fallthrough
|
||||||
|
case reflect.Int8:
|
||||||
|
fallthrough
|
||||||
|
case reflect.Int32:
|
||||||
|
fallthrough
|
||||||
|
case reflect.Int64:
|
||||||
|
return NewList(Int)
|
||||||
|
case reflect.Bool:
|
||||||
|
return NewList(Boolean)
|
||||||
|
case reflect.Float32:
|
||||||
|
fallthrough
|
||||||
|
case reflect.Float64:
|
||||||
|
return NewList(Float)
|
||||||
|
case reflect.String:
|
||||||
|
return NewList(String)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// finaly bind object
|
||||||
|
t := reflect.New(tipe.Elem())
|
||||||
|
name := strings.Replace(fmt.Sprint(tipe.Elem()), ".", "_", -1)
|
||||||
|
obj := NewObject(ObjectConfig{
|
||||||
|
Name: name,
|
||||||
|
Fields: BindFields(t.Elem().Interface()),
|
||||||
|
})
|
||||||
|
return NewList(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendFields(dest, origin Fields) Fields {
|
||||||
|
for key, value := range origin {
|
||||||
|
dest[key] = value
|
||||||
|
}
|
||||||
|
return dest
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractValue(originTag string, obj interface{}) interface{} {
|
||||||
|
val := reflect.ValueOf(obj)
|
||||||
|
|
||||||
|
for j := 0; j < val.NumField(); j++ {
|
||||||
|
typeField := val.Type().Field(j)
|
||||||
|
if typeField.Type.Kind() == reflect.Struct {
|
||||||
|
res := extractValue(originTag, val.Field(j).Interface())
|
||||||
|
if res != nil {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if originTag == extractTag(typeField.Tag) {
|
||||||
|
return val.Field(j).Interface()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractTag(tag reflect.StructTag) string {
|
||||||
|
t := tag.Get(TAG)
|
||||||
|
if t != "" {
|
||||||
|
t = strings.Split(t, ",")[0]
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
// lazy way of binding args
|
||||||
|
func BindArg(obj interface{}, tags ...string) FieldConfigArgument {
|
||||||
|
v := reflect.ValueOf(obj)
|
||||||
|
var config = make(FieldConfigArgument)
|
||||||
|
for i := 0; i < v.NumField(); i++ {
|
||||||
|
typeField := v.Type().Field(i)
|
||||||
|
|
||||||
|
mytag := extractTag(typeField.Tag)
|
||||||
|
if inArray(tags, mytag) {
|
||||||
|
config[mytag] = &ArgumentConfig{
|
||||||
|
Type: getGraphType(typeField.Type),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
func inArray(slice interface{}, item interface{}) bool {
|
||||||
|
s := reflect.ValueOf(slice)
|
||||||
|
if s.Kind() != reflect.Slice {
|
||||||
|
panic("inArray() given a non-slice type")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < s.Len(); i++ {
|
||||||
|
if reflect.DeepEqual(item, s.Index(i).Interface()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
288
vendor/github.com/graphql-go/graphql/validator.go
generated
vendored
Normal file
288
vendor/github.com/graphql-go/graphql/validator.go
generated
vendored
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
package graphql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/graphql-go/graphql/gqlerrors"
|
||||||
|
"github.com/graphql-go/graphql/language/ast"
|
||||||
|
"github.com/graphql-go/graphql/language/kinds"
|
||||||
|
"github.com/graphql-go/graphql/language/visitor"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ValidationResult struct {
|
||||||
|
IsValid bool
|
||||||
|
Errors []gqlerrors.FormattedError
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements the "Validation" section of the spec.
|
||||||
|
*
|
||||||
|
* Validation runs synchronously, returning an array of encountered errors, or
|
||||||
|
* an empty array if no errors were encountered and the document is valid.
|
||||||
|
*
|
||||||
|
* A list of specific validation rules may be provided. If not provided, the
|
||||||
|
* default list of rules defined by the GraphQL specification will be used.
|
||||||
|
*
|
||||||
|
* Each validation rules is a function which returns a visitor
|
||||||
|
* (see the language/visitor API). Visitor methods are expected to return
|
||||||
|
* GraphQLErrors, or Arrays of GraphQLErrors when invalid.
|
||||||
|
*/
|
||||||
|
|
||||||
|
func ValidateDocument(schema *Schema, astDoc *ast.Document, rules []ValidationRuleFn) (vr ValidationResult) {
|
||||||
|
if len(rules) == 0 {
|
||||||
|
rules = SpecifiedRules
|
||||||
|
}
|
||||||
|
|
||||||
|
vr.IsValid = false
|
||||||
|
if schema == nil {
|
||||||
|
vr.Errors = append(vr.Errors, gqlerrors.NewFormattedError("Must provide schema"))
|
||||||
|
return vr
|
||||||
|
}
|
||||||
|
if astDoc == nil {
|
||||||
|
vr.Errors = append(vr.Errors, gqlerrors.NewFormattedError("Must provide document"))
|
||||||
|
return vr
|
||||||
|
}
|
||||||
|
|
||||||
|
typeInfo := NewTypeInfo(&TypeInfoConfig{
|
||||||
|
Schema: schema,
|
||||||
|
})
|
||||||
|
vr.Errors = VisitUsingRules(schema, typeInfo, astDoc, rules)
|
||||||
|
if len(vr.Errors) == 0 {
|
||||||
|
vr.IsValid = true
|
||||||
|
}
|
||||||
|
return vr
|
||||||
|
}
|
||||||
|
|
||||||
|
// VisitUsingRules This uses a specialized visitor which runs multiple visitors in parallel,
|
||||||
|
// while maintaining the visitor skip and break API.
|
||||||
|
//
|
||||||
|
// @internal
|
||||||
|
// Had to expose it to unit test experimental customizable validation feature,
|
||||||
|
// but not meant for public consumption
|
||||||
|
func VisitUsingRules(schema *Schema, typeInfo *TypeInfo, astDoc *ast.Document, rules []ValidationRuleFn) []gqlerrors.FormattedError {
|
||||||
|
|
||||||
|
context := NewValidationContext(schema, astDoc, typeInfo)
|
||||||
|
visitors := []*visitor.VisitorOptions{}
|
||||||
|
|
||||||
|
for _, rule := range rules {
|
||||||
|
instance := rule(context)
|
||||||
|
visitors = append(visitors, instance.VisitorOpts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Visit the whole document with each instance of all provided rules.
|
||||||
|
visitor.Visit(astDoc, visitor.VisitWithTypeInfo(typeInfo, visitor.VisitInParallel(visitors...)), nil)
|
||||||
|
return context.Errors()
|
||||||
|
}
|
||||||
|
|
||||||
|
type HasSelectionSet interface {
|
||||||
|
GetKind() string
|
||||||
|
GetLoc() *ast.Location
|
||||||
|
GetSelectionSet() *ast.SelectionSet
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ HasSelectionSet = (*ast.OperationDefinition)(nil)
|
||||||
|
var _ HasSelectionSet = (*ast.FragmentDefinition)(nil)
|
||||||
|
|
||||||
|
type VariableUsage struct {
|
||||||
|
Node *ast.Variable
|
||||||
|
Type Input
|
||||||
|
}
|
||||||
|
|
||||||
|
type ValidationContext struct {
|
||||||
|
schema *Schema
|
||||||
|
astDoc *ast.Document
|
||||||
|
typeInfo *TypeInfo
|
||||||
|
errors []gqlerrors.FormattedError
|
||||||
|
fragments map[string]*ast.FragmentDefinition
|
||||||
|
variableUsages map[HasSelectionSet][]*VariableUsage
|
||||||
|
recursiveVariableUsages map[*ast.OperationDefinition][]*VariableUsage
|
||||||
|
recursivelyReferencedFragments map[*ast.OperationDefinition][]*ast.FragmentDefinition
|
||||||
|
fragmentSpreads map[*ast.SelectionSet][]*ast.FragmentSpread
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewValidationContext(schema *Schema, astDoc *ast.Document, typeInfo *TypeInfo) *ValidationContext {
|
||||||
|
return &ValidationContext{
|
||||||
|
schema: schema,
|
||||||
|
astDoc: astDoc,
|
||||||
|
typeInfo: typeInfo,
|
||||||
|
fragments: map[string]*ast.FragmentDefinition{},
|
||||||
|
variableUsages: map[HasSelectionSet][]*VariableUsage{},
|
||||||
|
recursiveVariableUsages: map[*ast.OperationDefinition][]*VariableUsage{},
|
||||||
|
recursivelyReferencedFragments: map[*ast.OperationDefinition][]*ast.FragmentDefinition{},
|
||||||
|
fragmentSpreads: map[*ast.SelectionSet][]*ast.FragmentSpread{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *ValidationContext) ReportError(err error) {
|
||||||
|
formattedErr := gqlerrors.FormatError(err)
|
||||||
|
ctx.errors = append(ctx.errors, formattedErr)
|
||||||
|
}
|
||||||
|
func (ctx *ValidationContext) Errors() []gqlerrors.FormattedError {
|
||||||
|
return ctx.errors
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *ValidationContext) Schema() *Schema {
|
||||||
|
return ctx.schema
|
||||||
|
}
|
||||||
|
func (ctx *ValidationContext) Document() *ast.Document {
|
||||||
|
return ctx.astDoc
|
||||||
|
}
|
||||||
|
func (ctx *ValidationContext) Fragment(name string) *ast.FragmentDefinition {
|
||||||
|
if len(ctx.fragments) == 0 {
|
||||||
|
if ctx.Document() == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
defs := ctx.Document().Definitions
|
||||||
|
fragments := map[string]*ast.FragmentDefinition{}
|
||||||
|
for _, def := range defs {
|
||||||
|
if def, ok := def.(*ast.FragmentDefinition); ok {
|
||||||
|
defName := ""
|
||||||
|
if def.Name != nil {
|
||||||
|
defName = def.Name.Value
|
||||||
|
}
|
||||||
|
fragments[defName] = def
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.fragments = fragments
|
||||||
|
}
|
||||||
|
f, _ := ctx.fragments[name]
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
func (ctx *ValidationContext) FragmentSpreads(node *ast.SelectionSet) []*ast.FragmentSpread {
|
||||||
|
if spreads, ok := ctx.fragmentSpreads[node]; ok && spreads != nil {
|
||||||
|
return spreads
|
||||||
|
}
|
||||||
|
|
||||||
|
spreads := []*ast.FragmentSpread{}
|
||||||
|
setsToVisit := []*ast.SelectionSet{node}
|
||||||
|
|
||||||
|
for {
|
||||||
|
if len(setsToVisit) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
var set *ast.SelectionSet
|
||||||
|
// pop
|
||||||
|
set, setsToVisit = setsToVisit[len(setsToVisit)-1], setsToVisit[:len(setsToVisit)-1]
|
||||||
|
if set.Selections != nil {
|
||||||
|
for _, selection := range set.Selections {
|
||||||
|
switch selection := selection.(type) {
|
||||||
|
case *ast.FragmentSpread:
|
||||||
|
spreads = append(spreads, selection)
|
||||||
|
case *ast.Field:
|
||||||
|
if selection.SelectionSet != nil {
|
||||||
|
setsToVisit = append(setsToVisit, selection.SelectionSet)
|
||||||
|
}
|
||||||
|
case *ast.InlineFragment:
|
||||||
|
if selection.SelectionSet != nil {
|
||||||
|
setsToVisit = append(setsToVisit, selection.SelectionSet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.fragmentSpreads[node] = spreads
|
||||||
|
}
|
||||||
|
return spreads
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *ValidationContext) RecursivelyReferencedFragments(operation *ast.OperationDefinition) []*ast.FragmentDefinition {
|
||||||
|
if fragments, ok := ctx.recursivelyReferencedFragments[operation]; ok && fragments != nil {
|
||||||
|
return fragments
|
||||||
|
}
|
||||||
|
|
||||||
|
fragments := []*ast.FragmentDefinition{}
|
||||||
|
collectedNames := map[string]bool{}
|
||||||
|
nodesToVisit := []*ast.SelectionSet{operation.SelectionSet}
|
||||||
|
|
||||||
|
for {
|
||||||
|
if len(nodesToVisit) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
var node *ast.SelectionSet
|
||||||
|
|
||||||
|
node, nodesToVisit = nodesToVisit[len(nodesToVisit)-1], nodesToVisit[:len(nodesToVisit)-1]
|
||||||
|
spreads := ctx.FragmentSpreads(node)
|
||||||
|
for _, spread := range spreads {
|
||||||
|
fragName := ""
|
||||||
|
if spread.Name != nil {
|
||||||
|
fragName = spread.Name.Value
|
||||||
|
}
|
||||||
|
if res, ok := collectedNames[fragName]; !ok || !res {
|
||||||
|
collectedNames[fragName] = true
|
||||||
|
fragment := ctx.Fragment(fragName)
|
||||||
|
if fragment != nil {
|
||||||
|
fragments = append(fragments, fragment)
|
||||||
|
nodesToVisit = append(nodesToVisit, fragment.SelectionSet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.recursivelyReferencedFragments[operation] = fragments
|
||||||
|
return fragments
|
||||||
|
}
|
||||||
|
func (ctx *ValidationContext) VariableUsages(node HasSelectionSet) []*VariableUsage {
|
||||||
|
if usages, ok := ctx.variableUsages[node]; ok && usages != nil {
|
||||||
|
return usages
|
||||||
|
}
|
||||||
|
usages := []*VariableUsage{}
|
||||||
|
typeInfo := NewTypeInfo(&TypeInfoConfig{
|
||||||
|
Schema: ctx.schema,
|
||||||
|
})
|
||||||
|
|
||||||
|
visitor.Visit(node, visitor.VisitWithTypeInfo(typeInfo, &visitor.VisitorOptions{
|
||||||
|
KindFuncMap: map[string]visitor.NamedVisitFuncs{
|
||||||
|
kinds.VariableDefinition: {
|
||||||
|
Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
return visitor.ActionSkip, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
kinds.Variable: {
|
||||||
|
Kind: func(p visitor.VisitFuncParams) (string, interface{}) {
|
||||||
|
if node, ok := p.Node.(*ast.Variable); ok && node != nil {
|
||||||
|
usages = append(usages, &VariableUsage{
|
||||||
|
Node: node,
|
||||||
|
Type: typeInfo.InputType(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return visitor.ActionNoChange, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}), nil)
|
||||||
|
|
||||||
|
ctx.variableUsages[node] = usages
|
||||||
|
return usages
|
||||||
|
}
|
||||||
|
func (ctx *ValidationContext) RecursiveVariableUsages(operation *ast.OperationDefinition) []*VariableUsage {
|
||||||
|
if usages, ok := ctx.recursiveVariableUsages[operation]; ok && usages != nil {
|
||||||
|
return usages
|
||||||
|
}
|
||||||
|
usages := ctx.VariableUsages(operation)
|
||||||
|
|
||||||
|
fragments := ctx.RecursivelyReferencedFragments(operation)
|
||||||
|
for _, fragment := range fragments {
|
||||||
|
fragmentUsages := ctx.VariableUsages(fragment)
|
||||||
|
usages = append(usages, fragmentUsages...)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.recursiveVariableUsages[operation] = usages
|
||||||
|
return usages
|
||||||
|
}
|
||||||
|
func (ctx *ValidationContext) Type() Output {
|
||||||
|
return ctx.typeInfo.Type()
|
||||||
|
}
|
||||||
|
func (ctx *ValidationContext) ParentType() Composite {
|
||||||
|
return ctx.typeInfo.ParentType()
|
||||||
|
}
|
||||||
|
func (ctx *ValidationContext) InputType() Input {
|
||||||
|
return ctx.typeInfo.InputType()
|
||||||
|
}
|
||||||
|
func (ctx *ValidationContext) FieldDef() *FieldDefinition {
|
||||||
|
return ctx.typeInfo.FieldDef()
|
||||||
|
}
|
||||||
|
func (ctx *ValidationContext) Directive() *Directive {
|
||||||
|
return ctx.typeInfo.Directive()
|
||||||
|
}
|
||||||
|
func (ctx *ValidationContext) Argument() *Argument {
|
||||||
|
return ctx.typeInfo.Argument()
|
||||||
|
}
|
476
vendor/github.com/graphql-go/graphql/values.go
generated
vendored
Normal file
476
vendor/github.com/graphql-go/graphql/values.go
generated
vendored
Normal file
@ -0,0 +1,476 @@
|
|||||||
|
package graphql
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/graphql-go/graphql/gqlerrors"
|
||||||
|
"github.com/graphql-go/graphql/language/ast"
|
||||||
|
"github.com/graphql-go/graphql/language/kinds"
|
||||||
|
"github.com/graphql-go/graphql/language/printer"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Prepares an object map of variableValues of the correct type based on the
|
||||||
|
// provided variable definitions and arbitrary input. If the input cannot be
|
||||||
|
// parsed to match the variable definitions, a GraphQLError will be returned.
|
||||||
|
func getVariableValues(schema Schema, definitionASTs []*ast.VariableDefinition, inputs map[string]interface{}) (map[string]interface{}, error) {
|
||||||
|
values := map[string]interface{}{}
|
||||||
|
for _, defAST := range definitionASTs {
|
||||||
|
if defAST == nil || defAST.Variable == nil || defAST.Variable.Name == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
varName := defAST.Variable.Name.Value
|
||||||
|
varValue, err := getVariableValue(schema, defAST, inputs[varName])
|
||||||
|
if err != nil {
|
||||||
|
return values, err
|
||||||
|
}
|
||||||
|
values[varName] = varValue
|
||||||
|
}
|
||||||
|
return values, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepares an object map of argument values given a list of argument
|
||||||
|
// definitions and list of argument AST nodes.
|
||||||
|
func getArgumentValues(argDefs []*Argument, argASTs []*ast.Argument, variableVariables map[string]interface{}) (map[string]interface{}, error) {
|
||||||
|
|
||||||
|
argASTMap := map[string]*ast.Argument{}
|
||||||
|
for _, argAST := range argASTs {
|
||||||
|
if argAST.Name != nil {
|
||||||
|
argASTMap[argAST.Name.Value] = argAST
|
||||||
|
}
|
||||||
|
}
|
||||||
|
results := map[string]interface{}{}
|
||||||
|
for _, argDef := range argDefs {
|
||||||
|
|
||||||
|
name := argDef.PrivateName
|
||||||
|
var valueAST ast.Value
|
||||||
|
if argAST, ok := argASTMap[name]; ok {
|
||||||
|
valueAST = argAST.Value
|
||||||
|
}
|
||||||
|
value := valueFromAST(valueAST, argDef.Type, variableVariables)
|
||||||
|
if isNullish(value) {
|
||||||
|
value = argDef.DefaultValue
|
||||||
|
}
|
||||||
|
if !isNullish(value) {
|
||||||
|
results[name] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given a variable definition, and any value of input, return a value which
|
||||||
|
// adheres to the variable definition, or throw an error.
|
||||||
|
func getVariableValue(schema Schema, definitionAST *ast.VariableDefinition, input interface{}) (interface{}, error) {
|
||||||
|
ttype, err := typeFromAST(schema, definitionAST.Type)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
variable := definitionAST.Variable
|
||||||
|
|
||||||
|
if ttype == nil || !IsInputType(ttype) {
|
||||||
|
return "", gqlerrors.NewError(
|
||||||
|
fmt.Sprintf(`Variable "$%v" expected value of type `+
|
||||||
|
`"%v" which cannot be used as an input type.`, variable.Name.Value, printer.Print(definitionAST.Type)),
|
||||||
|
[]ast.Node{definitionAST},
|
||||||
|
"",
|
||||||
|
nil,
|
||||||
|
[]int{},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
isValid, messages := isValidInputValue(input, ttype)
|
||||||
|
if isValid {
|
||||||
|
if isNullish(input) {
|
||||||
|
defaultValue := definitionAST.DefaultValue
|
||||||
|
if defaultValue != nil {
|
||||||
|
variables := map[string]interface{}{}
|
||||||
|
val := valueFromAST(defaultValue, ttype, variables)
|
||||||
|
return val, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return coerceValue(ttype, input), nil
|
||||||
|
}
|
||||||
|
if isNullish(input) {
|
||||||
|
return "", gqlerrors.NewError(
|
||||||
|
fmt.Sprintf(`Variable "$%v" of required type `+
|
||||||
|
`"%v" was not provided.`, variable.Name.Value, printer.Print(definitionAST.Type)),
|
||||||
|
[]ast.Node{definitionAST},
|
||||||
|
"",
|
||||||
|
nil,
|
||||||
|
[]int{},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// convert input interface into string for error message
|
||||||
|
inputStr := ""
|
||||||
|
b, err := json.Marshal(input)
|
||||||
|
if err == nil {
|
||||||
|
inputStr = string(b)
|
||||||
|
}
|
||||||
|
messagesStr := ""
|
||||||
|
if len(messages) > 0 {
|
||||||
|
messagesStr = "\n" + strings.Join(messages, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", gqlerrors.NewError(
|
||||||
|
fmt.Sprintf(`Variable "$%v" got invalid value `+
|
||||||
|
`%v.%v`, variable.Name.Value, inputStr, messagesStr),
|
||||||
|
[]ast.Node{definitionAST},
|
||||||
|
"",
|
||||||
|
nil,
|
||||||
|
[]int{},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given a type and any value, return a runtime value coerced to match the type.
|
||||||
|
func coerceValue(ttype Input, value interface{}) interface{} {
|
||||||
|
if ttype, ok := ttype.(*NonNull); ok {
|
||||||
|
return coerceValue(ttype.OfType, value)
|
||||||
|
}
|
||||||
|
if isNullish(value) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if ttype, ok := ttype.(*List); ok {
|
||||||
|
itemType := ttype.OfType
|
||||||
|
valType := reflect.ValueOf(value)
|
||||||
|
if valType.Kind() == reflect.Slice {
|
||||||
|
values := []interface{}{}
|
||||||
|
for i := 0; i < valType.Len(); i++ {
|
||||||
|
val := valType.Index(i).Interface()
|
||||||
|
v := coerceValue(itemType, val)
|
||||||
|
values = append(values, v)
|
||||||
|
}
|
||||||
|
return values
|
||||||
|
}
|
||||||
|
val := coerceValue(itemType, value)
|
||||||
|
return []interface{}{val}
|
||||||
|
}
|
||||||
|
if ttype, ok := ttype.(*InputObject); ok {
|
||||||
|
|
||||||
|
valueMap, ok := value.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
valueMap = map[string]interface{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
obj := map[string]interface{}{}
|
||||||
|
for fieldName, field := range ttype.Fields() {
|
||||||
|
value, _ := valueMap[fieldName]
|
||||||
|
fieldValue := coerceValue(field.Type, value)
|
||||||
|
if isNullish(fieldValue) {
|
||||||
|
fieldValue = field.DefaultValue
|
||||||
|
}
|
||||||
|
if !isNullish(fieldValue) {
|
||||||
|
obj[fieldName] = fieldValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ttype := ttype.(type) {
|
||||||
|
case *Scalar:
|
||||||
|
parsed := ttype.ParseValue(value)
|
||||||
|
if !isNullish(parsed) {
|
||||||
|
return parsed
|
||||||
|
}
|
||||||
|
case *Enum:
|
||||||
|
parsed := ttype.ParseValue(value)
|
||||||
|
if !isNullish(parsed) {
|
||||||
|
return parsed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// graphql-js/src/utilities.js`
|
||||||
|
// TODO: figure out where to organize utils
|
||||||
|
// TODO: change to *Schema
|
||||||
|
func typeFromAST(schema Schema, inputTypeAST ast.Type) (Type, error) {
|
||||||
|
switch inputTypeAST := inputTypeAST.(type) {
|
||||||
|
case *ast.List:
|
||||||
|
innerType, err := typeFromAST(schema, inputTypeAST.Type)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return NewList(innerType), nil
|
||||||
|
case *ast.NonNull:
|
||||||
|
innerType, err := typeFromAST(schema, inputTypeAST.Type)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return NewNonNull(innerType), nil
|
||||||
|
case *ast.Named:
|
||||||
|
nameValue := ""
|
||||||
|
if inputTypeAST.Name != nil {
|
||||||
|
nameValue = inputTypeAST.Name.Value
|
||||||
|
}
|
||||||
|
ttype := schema.Type(nameValue)
|
||||||
|
return ttype, nil
|
||||||
|
default:
|
||||||
|
return nil, invariant(inputTypeAST.GetKind() == kinds.Named, "Must be a named type.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// isValidInputValue alias isValidJSValue
|
||||||
|
// Given a value and a GraphQL type, determine if the value will be
|
||||||
|
// accepted for that type. This is primarily useful for validating the
|
||||||
|
// runtime values of query variables.
|
||||||
|
func isValidInputValue(value interface{}, ttype Input) (bool, []string) {
|
||||||
|
if ttype, ok := ttype.(*NonNull); ok {
|
||||||
|
if isNullish(value) {
|
||||||
|
if ttype.OfType.Name() != "" {
|
||||||
|
return false, []string{fmt.Sprintf(`Expected "%v!", found null.`, ttype.OfType.Name())}
|
||||||
|
}
|
||||||
|
return false, []string{"Expected non-null value, found null."}
|
||||||
|
}
|
||||||
|
return isValidInputValue(value, ttype.OfType)
|
||||||
|
}
|
||||||
|
|
||||||
|
if isNullish(value) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ttype := ttype.(type) {
|
||||||
|
case *List:
|
||||||
|
itemType := ttype.OfType
|
||||||
|
valType := reflect.ValueOf(value)
|
||||||
|
if valType.Kind() == reflect.Ptr {
|
||||||
|
valType = valType.Elem()
|
||||||
|
}
|
||||||
|
if valType.Kind() == reflect.Slice {
|
||||||
|
messagesReduce := []string{}
|
||||||
|
for i := 0; i < valType.Len(); i++ {
|
||||||
|
val := valType.Index(i).Interface()
|
||||||
|
_, messages := isValidInputValue(val, itemType)
|
||||||
|
for idx, message := range messages {
|
||||||
|
messagesReduce = append(messagesReduce, fmt.Sprintf(`In element #%v: %v`, idx+1, message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (len(messagesReduce) == 0), messagesReduce
|
||||||
|
}
|
||||||
|
return isValidInputValue(value, itemType)
|
||||||
|
|
||||||
|
case *InputObject:
|
||||||
|
messagesReduce := []string{}
|
||||||
|
|
||||||
|
valueMap, ok := value.(map[string]interface{})
|
||||||
|
if !ok {
|
||||||
|
return false, []string{fmt.Sprintf(`Expected "%v", found not an object.`, ttype.Name())}
|
||||||
|
}
|
||||||
|
fields := ttype.Fields()
|
||||||
|
|
||||||
|
// to ensure stable order of field evaluation
|
||||||
|
fieldNames := []string{}
|
||||||
|
valueMapFieldNames := []string{}
|
||||||
|
|
||||||
|
for fieldName := range fields {
|
||||||
|
fieldNames = append(fieldNames, fieldName)
|
||||||
|
}
|
||||||
|
sort.Strings(fieldNames)
|
||||||
|
|
||||||
|
for fieldName := range valueMap {
|
||||||
|
valueMapFieldNames = append(valueMapFieldNames, fieldName)
|
||||||
|
}
|
||||||
|
sort.Strings(valueMapFieldNames)
|
||||||
|
|
||||||
|
// Ensure every provided field is defined.
|
||||||
|
for _, fieldName := range valueMapFieldNames {
|
||||||
|
if _, ok := fields[fieldName]; !ok {
|
||||||
|
messagesReduce = append(messagesReduce, fmt.Sprintf(`In field "%v": Unknown field.`, fieldName))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure every defined field is valid.
|
||||||
|
for _, fieldName := range fieldNames {
|
||||||
|
_, messages := isValidInputValue(valueMap[fieldName], fields[fieldName].Type)
|
||||||
|
if messages != nil {
|
||||||
|
for _, message := range messages {
|
||||||
|
messagesReduce = append(messagesReduce, fmt.Sprintf(`In field "%v": %v`, fieldName, message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (len(messagesReduce) == 0), messagesReduce
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ttype := ttype.(type) {
|
||||||
|
case *Scalar:
|
||||||
|
parsedVal := ttype.ParseValue(value)
|
||||||
|
if isNullish(parsedVal) {
|
||||||
|
return false, []string{fmt.Sprintf(`Expected type "%v", found "%v".`, ttype.Name(), value)}
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
|
||||||
|
case *Enum:
|
||||||
|
parsedVal := ttype.ParseValue(value)
|
||||||
|
if isNullish(parsedVal) {
|
||||||
|
return false, []string{fmt.Sprintf(`Expected type "%v", found "%v".`, ttype.Name(), value)}
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if a value is null, undefined, or NaN.
|
||||||
|
func isNullish(value interface{}) bool {
|
||||||
|
if value, ok := value.(*string); ok {
|
||||||
|
if value == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return *value == ""
|
||||||
|
}
|
||||||
|
if value, ok := value.(int); ok {
|
||||||
|
return math.IsNaN(float64(value))
|
||||||
|
}
|
||||||
|
if value, ok := value.(*int); ok {
|
||||||
|
if value == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return math.IsNaN(float64(*value))
|
||||||
|
}
|
||||||
|
if value, ok := value.(float32); ok {
|
||||||
|
return math.IsNaN(float64(value))
|
||||||
|
}
|
||||||
|
if value, ok := value.(*float32); ok {
|
||||||
|
if value == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return math.IsNaN(float64(*value))
|
||||||
|
}
|
||||||
|
if value, ok := value.(float64); ok {
|
||||||
|
return math.IsNaN(value)
|
||||||
|
}
|
||||||
|
if value, ok := value.(*float64); ok {
|
||||||
|
if value == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return math.IsNaN(*value)
|
||||||
|
}
|
||||||
|
return value == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produces a value given a GraphQL Value AST.
|
||||||
|
*
|
||||||
|
* A GraphQL type must be provided, which will be used to interpret different
|
||||||
|
* GraphQL Value literals.
|
||||||
|
*
|
||||||
|
* | GraphQL Value | JSON Value |
|
||||||
|
* | -------------------- | ------------- |
|
||||||
|
* | Input Object | Object |
|
||||||
|
* | List | Array |
|
||||||
|
* | Boolean | Boolean |
|
||||||
|
* | String / Enum Value | String |
|
||||||
|
* | Int / Float | Number |
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
func valueFromAST(valueAST ast.Value, ttype Input, variables map[string]interface{}) interface{} {
|
||||||
|
|
||||||
|
if ttype, ok := ttype.(*NonNull); ok {
|
||||||
|
val := valueFromAST(valueAST, ttype.OfType, variables)
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
if valueAST == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if valueAST, ok := valueAST.(*ast.Variable); ok && valueAST.Kind == kinds.Variable {
|
||||||
|
if valueAST.Name == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if variables == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
variableName := valueAST.Name.Value
|
||||||
|
variableVal, ok := variables[variableName]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Note: we're not doing any checking that this variable is correct. We're
|
||||||
|
// assuming that this query has been validated and the variable usage here
|
||||||
|
// is of the correct type.
|
||||||
|
return variableVal
|
||||||
|
}
|
||||||
|
|
||||||
|
if ttype, ok := ttype.(*List); ok {
|
||||||
|
itemType := ttype.OfType
|
||||||
|
if valueAST, ok := valueAST.(*ast.ListValue); ok && valueAST.Kind == kinds.ListValue {
|
||||||
|
values := []interface{}{}
|
||||||
|
for _, itemAST := range valueAST.Values {
|
||||||
|
v := valueFromAST(itemAST, itemType, variables)
|
||||||
|
values = append(values, v)
|
||||||
|
}
|
||||||
|
return values
|
||||||
|
}
|
||||||
|
v := valueFromAST(valueAST, itemType, variables)
|
||||||
|
return []interface{}{v}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ttype, ok := ttype.(*InputObject); ok {
|
||||||
|
valueAST, ok := valueAST.(*ast.ObjectValue)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
fieldASTs := map[string]*ast.ObjectField{}
|
||||||
|
for _, fieldAST := range valueAST.Fields {
|
||||||
|
if fieldAST.Name == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fieldName := fieldAST.Name.Value
|
||||||
|
fieldASTs[fieldName] = fieldAST
|
||||||
|
|
||||||
|
}
|
||||||
|
obj := map[string]interface{}{}
|
||||||
|
for fieldName, field := range ttype.Fields() {
|
||||||
|
fieldAST, ok := fieldASTs[fieldName]
|
||||||
|
fieldValue := field.DefaultValue
|
||||||
|
if !ok || fieldAST == nil {
|
||||||
|
if fieldValue == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fieldValue = valueFromAST(fieldAST.Value, field.Type, variables)
|
||||||
|
}
|
||||||
|
if isNullish(fieldValue) {
|
||||||
|
fieldValue = field.DefaultValue
|
||||||
|
}
|
||||||
|
if !isNullish(fieldValue) {
|
||||||
|
obj[fieldName] = fieldValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ttype := ttype.(type) {
|
||||||
|
case *Scalar:
|
||||||
|
parsed := ttype.ParseLiteral(valueAST)
|
||||||
|
if !isNullish(parsed) {
|
||||||
|
return parsed
|
||||||
|
}
|
||||||
|
case *Enum:
|
||||||
|
parsed := ttype.ParseLiteral(valueAST)
|
||||||
|
if !isNullish(parsed) {
|
||||||
|
return parsed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func invariant(condition bool, message string) error {
|
||||||
|
if !condition {
|
||||||
|
return gqlerrors.NewFormattedError(message)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func invariantf(condition bool, format string, a ...interface{}) error {
|
||||||
|
if !condition {
|
||||||
|
return gqlerrors.NewFormattedError(fmt.Sprintf(format, a...))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
25
vendor/github.com/graphql-go/handler/.gitignore
generated
vendored
Normal file
25
vendor/github.com/graphql-go/handler/.gitignore
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Folders
|
||||||
|
_obj
|
||||||
|
_test
|
||||||
|
|
||||||
|
# Architecture specific extensions/prefixes
|
||||||
|
*.[568vq]
|
||||||
|
[568vq].out
|
||||||
|
|
||||||
|
*.cgo1.go
|
||||||
|
*.cgo2.c
|
||||||
|
_cgo_defun.c
|
||||||
|
_cgo_gotypes.go
|
||||||
|
_cgo_export.*
|
||||||
|
|
||||||
|
_testmain.go
|
||||||
|
|
||||||
|
*.exe
|
||||||
|
*.test
|
||||||
|
*.prof
|
||||||
|
*.swp
|
12
vendor/github.com/graphql-go/handler/.travis.yml
generated
vendored
Normal file
12
vendor/github.com/graphql-go/handler/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.x
|
||||||
|
- tip
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- go get github.com/axw/gocov/gocov
|
||||||
|
- go get github.com/mattn/goveralls
|
||||||
|
|
||||||
|
script:
|
||||||
|
- $HOME/gopath/bin/goveralls -service=travis-ci
|
22
vendor/github.com/graphql-go/handler/LICENSE
generated
vendored
Normal file
22
vendor/github.com/graphql-go/handler/LICENSE
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Hafiz Ismail
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
79
vendor/github.com/graphql-go/handler/README.md
generated
vendored
Normal file
79
vendor/github.com/graphql-go/handler/README.md
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
# graphql-go-handler [![Build Status](https://travis-ci.org/graphql-go/handler.svg)](https://travis-ci.org/graphql-go/handler) [![GoDoc](https://godoc.org/graphql-go/handler?status.svg)](https://godoc.org/github.com/graphql-go/handler) [![Coverage Status](https://coveralls.io/repos/graphql-go/handler/badge.svg?branch=master&service=github)](https://coveralls.io/github/graphql-go/handler?branch=master) [![Join the chat at https://gitter.im/graphql-go/graphql](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/graphql-go/graphql?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
|
||||||
|
Golang HTTP.Handler for [graphl-go](https://github.com/graphql-go/graphql)
|
||||||
|
|
||||||
|
### Notes:
|
||||||
|
This is based on alpha version of `graphql-go` and `graphql-relay-go`.
|
||||||
|
Be sure to watch both repositories for latest changes.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"github.com/graphql-go/handler"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
// define GraphQL schema using relay library helpers
|
||||||
|
schema := graphql.NewSchema(...)
|
||||||
|
|
||||||
|
h := handler.New(&handler.Config{
|
||||||
|
Schema: &schema,
|
||||||
|
Pretty: true,
|
||||||
|
GraphiQL: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
// serve HTTP
|
||||||
|
http.Handle("/graphql", h)
|
||||||
|
http.ListenAndServe(":8080", nil)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Details
|
||||||
|
|
||||||
|
The handler will accept requests with
|
||||||
|
the parameters:
|
||||||
|
|
||||||
|
* **`query`**: A string GraphQL document to be executed.
|
||||||
|
|
||||||
|
* **`variables`**: The runtime values to use for any GraphQL query variables
|
||||||
|
as a JSON object.
|
||||||
|
|
||||||
|
* **`operationName`**: If the provided `query` contains multiple named
|
||||||
|
operations, this specifies which operation should be executed. If not
|
||||||
|
provided, an 400 error will be returned if the `query` contains multiple
|
||||||
|
named operations.
|
||||||
|
|
||||||
|
GraphQL will first look for each parameter in the URL's query-string:
|
||||||
|
|
||||||
|
```
|
||||||
|
/graphql?query=query+getUser($id:ID){user(id:$id){name}}&variables={"id":"4"}
|
||||||
|
```
|
||||||
|
|
||||||
|
If not found in the query-string, it will look in the POST request body.
|
||||||
|
The `handler` will interpret it
|
||||||
|
depending on the provided `Content-Type` header.
|
||||||
|
|
||||||
|
* **`application/json`**: the POST body will be parsed as a JSON
|
||||||
|
object of parameters.
|
||||||
|
|
||||||
|
* **`application/x-www-form-urlencoded`**: this POST body will be
|
||||||
|
parsed as a url-encoded string of key-value pairs.
|
||||||
|
|
||||||
|
* **`application/graphql`**: The POST body will be parsed as GraphQL
|
||||||
|
query string, which provides the `query` parameter.
|
||||||
|
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
- [golang-graphql-playground](https://github.com/graphql-go/playground)
|
||||||
|
- [golang-relay-starter-kit](https://github.com/sogko/golang-relay-starter-kit)
|
||||||
|
- [todomvc-relay-go](https://github.com/sogko/todomvc-relay-go)
|
||||||
|
|
||||||
|
### Test
|
||||||
|
```bash
|
||||||
|
$ go get github.com/graphql-go/handler
|
||||||
|
$ go build && go test ./...
|
199
vendor/github.com/graphql-go/handler/graphiql.go
generated
vendored
Normal file
199
vendor/github.com/graphql-go/handler/graphiql.go
generated
vendored
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"html/template"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/graphql-go/graphql"
|
||||||
|
)
|
||||||
|
|
||||||
|
// page is the page data structure of the rendered GraphiQL page
|
||||||
|
type graphiqlPage struct {
|
||||||
|
GraphiqlVersion string
|
||||||
|
QueryString string
|
||||||
|
ResultString string
|
||||||
|
VariablesString string
|
||||||
|
OperationName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// renderGraphiQL renders the GraphiQL GUI
|
||||||
|
func renderGraphiQL(w http.ResponseWriter, params graphql.Params) {
|
||||||
|
t := template.New("GraphiQL")
|
||||||
|
t, err := t.Parse(graphiqlTemplate)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create variables string
|
||||||
|
vars, err := json.MarshalIndent(params.VariableValues, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
varsString := string(vars)
|
||||||
|
if varsString == "null" {
|
||||||
|
varsString = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create result string
|
||||||
|
var resString string
|
||||||
|
if params.RequestString == "" {
|
||||||
|
resString = ""
|
||||||
|
} else {
|
||||||
|
result, err := json.MarshalIndent(graphql.Do(params), "", " ")
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
resString = string(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
p := graphiqlPage{
|
||||||
|
GraphiqlVersion: graphiqlVersion,
|
||||||
|
QueryString: params.RequestString,
|
||||||
|
ResultString: resString,
|
||||||
|
VariablesString: varsString,
|
||||||
|
OperationName: params.OperationName,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = t.ExecuteTemplate(w, "index", p)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// graphiqlVersion is the current version of GraphiQL
|
||||||
|
const graphiqlVersion = "0.11.3"
|
||||||
|
|
||||||
|
// tmpl is the page template to render GraphiQL
|
||||||
|
const graphiqlTemplate = `
|
||||||
|
{{ define "index" }}
|
||||||
|
<!--
|
||||||
|
The request to this GraphQL server provided the header "Accept: text/html"
|
||||||
|
and as a result has been presented GraphiQL - an in-browser IDE for
|
||||||
|
exploring GraphQL.
|
||||||
|
|
||||||
|
If you wish to receive JSON, provide the header "Accept: application/json" or
|
||||||
|
add "&raw" to the end of the URL within a browser.
|
||||||
|
-->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>GraphiQL</title>
|
||||||
|
<meta name="robots" content="noindex" />
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<link href="//cdn.jsdelivr.net/npm/graphiql@{{ .GraphiqlVersion }}/graphiql.css" rel="stylesheet" />
|
||||||
|
<script src="//cdn.jsdelivr.net/fetch/0.9.0/fetch.min.js"></script>
|
||||||
|
<script src="//cdn.jsdelivr.net/react/15.4.2/react.min.js"></script>
|
||||||
|
<script src="//cdn.jsdelivr.net/react/15.4.2/react-dom.min.js"></script>
|
||||||
|
<script src="//cdn.jsdelivr.net/npm/graphiql@{{ .GraphiqlVersion }}/graphiql.min.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
// Collect the URL parameters
|
||||||
|
var parameters = {};
|
||||||
|
window.location.search.substr(1).split('&').forEach(function (entry) {
|
||||||
|
var eq = entry.indexOf('=');
|
||||||
|
if (eq >= 0) {
|
||||||
|
parameters[decodeURIComponent(entry.slice(0, eq))] =
|
||||||
|
decodeURIComponent(entry.slice(eq + 1));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Produce a Location query string from a parameter object.
|
||||||
|
function locationQuery(params) {
|
||||||
|
return '?' + Object.keys(params).filter(function (key) {
|
||||||
|
return Boolean(params[key]);
|
||||||
|
}).map(function (key) {
|
||||||
|
return encodeURIComponent(key) + '=' +
|
||||||
|
encodeURIComponent(params[key]);
|
||||||
|
}).join('&');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Derive a fetch URL from the current URL, sans the GraphQL parameters.
|
||||||
|
var graphqlParamNames = {
|
||||||
|
query: true,
|
||||||
|
variables: true,
|
||||||
|
operationName: true
|
||||||
|
};
|
||||||
|
|
||||||
|
var otherParams = {};
|
||||||
|
for (var k in parameters) {
|
||||||
|
if (parameters.hasOwnProperty(k) && graphqlParamNames[k] !== true) {
|
||||||
|
otherParams[k] = parameters[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var fetchURL = locationQuery(otherParams);
|
||||||
|
|
||||||
|
// Defines a GraphQL fetcher using the fetch API.
|
||||||
|
function graphQLFetcher(graphQLParams) {
|
||||||
|
return fetch(fetchURL, {
|
||||||
|
method: 'post',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(graphQLParams),
|
||||||
|
credentials: 'include',
|
||||||
|
}).then(function (response) {
|
||||||
|
return response.text();
|
||||||
|
}).then(function (responseBody) {
|
||||||
|
try {
|
||||||
|
return JSON.parse(responseBody);
|
||||||
|
} catch (error) {
|
||||||
|
return responseBody;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// When the query and variables string is edited, update the URL bar so
|
||||||
|
// that it can be easily shared.
|
||||||
|
function onEditQuery(newQuery) {
|
||||||
|
parameters.query = newQuery;
|
||||||
|
updateURL();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEditVariables(newVariables) {
|
||||||
|
parameters.variables = newVariables;
|
||||||
|
updateURL();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEditOperationName(newOperationName) {
|
||||||
|
parameters.operationName = newOperationName;
|
||||||
|
updateURL();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateURL() {
|
||||||
|
history.replaceState(null, null, locationQuery(parameters));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render <GraphiQL /> into the body.
|
||||||
|
ReactDOM.render(
|
||||||
|
React.createElement(GraphiQL, {
|
||||||
|
fetcher: graphQLFetcher,
|
||||||
|
onEditQuery: onEditQuery,
|
||||||
|
onEditVariables: onEditVariables,
|
||||||
|
onEditOperationName: onEditOperationName,
|
||||||
|
query: {{ .QueryString }},
|
||||||
|
response: {{ .ResultString }},
|
||||||
|
variables: {{ .VariablesString }},
|
||||||
|
operationName: {{ .OperationName }},
|
||||||
|
}),
|
||||||
|
document.body
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
{{ end }}
|
||||||
|
`
|
189
vendor/github.com/graphql-go/handler/handler.go
generated
vendored
Normal file
189
vendor/github.com/graphql-go/handler/handler.go
generated
vendored
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/graphql-go/graphql"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ContentTypeJSON = "application/json"
|
||||||
|
ContentTypeGraphQL = "application/graphql"
|
||||||
|
ContentTypeFormURLEncoded = "application/x-www-form-urlencoded"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Handler struct {
|
||||||
|
Schema *graphql.Schema
|
||||||
|
pretty bool
|
||||||
|
graphiql bool
|
||||||
|
}
|
||||||
|
type RequestOptions struct {
|
||||||
|
Query string `json:"query" url:"query" schema:"query"`
|
||||||
|
Variables map[string]interface{} `json:"variables" url:"variables" schema:"variables"`
|
||||||
|
OperationName string `json:"operationName" url:"operationName" schema:"operationName"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// a workaround for getting`variables` as a JSON string
|
||||||
|
type requestOptionsCompatibility struct {
|
||||||
|
Query string `json:"query" url:"query" schema:"query"`
|
||||||
|
Variables string `json:"variables" url:"variables" schema:"variables"`
|
||||||
|
OperationName string `json:"operationName" url:"operationName" schema:"operationName"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func getFromForm(values url.Values) *RequestOptions {
|
||||||
|
query := values.Get("query")
|
||||||
|
if query != "" {
|
||||||
|
// get variables map
|
||||||
|
variables := make(map[string]interface{}, len(values))
|
||||||
|
variablesStr := values.Get("variables")
|
||||||
|
json.Unmarshal([]byte(variablesStr), &variables)
|
||||||
|
|
||||||
|
return &RequestOptions{
|
||||||
|
Query: query,
|
||||||
|
Variables: variables,
|
||||||
|
OperationName: values.Get("operationName"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestOptions Parses a http.Request into GraphQL request options struct
|
||||||
|
func NewRequestOptions(r *http.Request) *RequestOptions {
|
||||||
|
if reqOpt := getFromForm(r.URL.Query()); reqOpt != nil {
|
||||||
|
return reqOpt
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Method != "POST" {
|
||||||
|
return &RequestOptions{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Body == nil {
|
||||||
|
return &RequestOptions{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: improve Content-Type handling
|
||||||
|
contentTypeStr := r.Header.Get("Content-Type")
|
||||||
|
contentTypeTokens := strings.Split(contentTypeStr, ";")
|
||||||
|
contentType := contentTypeTokens[0]
|
||||||
|
|
||||||
|
switch contentType {
|
||||||
|
case ContentTypeGraphQL:
|
||||||
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
return &RequestOptions{}
|
||||||
|
}
|
||||||
|
return &RequestOptions{
|
||||||
|
Query: string(body),
|
||||||
|
}
|
||||||
|
case ContentTypeFormURLEncoded:
|
||||||
|
if err := r.ParseForm(); err != nil {
|
||||||
|
return &RequestOptions{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if reqOpt := getFromForm(r.PostForm); reqOpt != nil {
|
||||||
|
return reqOpt
|
||||||
|
}
|
||||||
|
|
||||||
|
return &RequestOptions{}
|
||||||
|
|
||||||
|
case ContentTypeJSON:
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
var opts RequestOptions
|
||||||
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
return &opts
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(body, &opts)
|
||||||
|
if err != nil {
|
||||||
|
// Probably `variables` was sent as a string instead of an object.
|
||||||
|
// So, we try to be polite and try to parse that as a JSON string
|
||||||
|
var optsCompatible requestOptionsCompatibility
|
||||||
|
json.Unmarshal(body, &optsCompatible)
|
||||||
|
json.Unmarshal([]byte(optsCompatible.Variables), &opts.Variables)
|
||||||
|
}
|
||||||
|
return &opts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContextHandler provides an entrypoint into executing graphQL queries with a
|
||||||
|
// user-provided context.
|
||||||
|
func (h *Handler) ContextHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
// get query
|
||||||
|
opts := NewRequestOptions(r)
|
||||||
|
|
||||||
|
// execute graphql query
|
||||||
|
params := graphql.Params{
|
||||||
|
Schema: *h.Schema,
|
||||||
|
RequestString: opts.Query,
|
||||||
|
VariableValues: opts.Variables,
|
||||||
|
OperationName: opts.OperationName,
|
||||||
|
Context: ctx,
|
||||||
|
}
|
||||||
|
result := graphql.Do(params)
|
||||||
|
|
||||||
|
if h.graphiql {
|
||||||
|
acceptHeader := r.Header.Get("Accept")
|
||||||
|
_, raw := r.URL.Query()["raw"]
|
||||||
|
if !raw && !strings.Contains(acceptHeader, "application/json") && strings.Contains(acceptHeader, "text/html") {
|
||||||
|
renderGraphiQL(w, params)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// use proper JSON Header
|
||||||
|
w.Header().Add("Content-Type", "application/json; charset=utf-8")
|
||||||
|
|
||||||
|
if h.pretty {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
buff, _ := json.MarshalIndent(result, "", "\t")
|
||||||
|
|
||||||
|
w.Write(buff)
|
||||||
|
} else {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
buff, _ := json.Marshal(result)
|
||||||
|
|
||||||
|
w.Write(buff)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServeHTTP provides an entrypoint into executing graphQL queries.
|
||||||
|
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
h.ContextHandler(r.Context(), w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Schema *graphql.Schema
|
||||||
|
Pretty bool
|
||||||
|
GraphiQL bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConfig() *Config {
|
||||||
|
return &Config{
|
||||||
|
Schema: nil,
|
||||||
|
Pretty: true,
|
||||||
|
GraphiQL: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(p *Config) *Handler {
|
||||||
|
if p == nil {
|
||||||
|
p = NewConfig()
|
||||||
|
}
|
||||||
|
if p.Schema == nil {
|
||||||
|
panic("undefined GraphQL schema")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Handler{
|
||||||
|
Schema: p.Schema,
|
||||||
|
pretty: p.Pretty,
|
||||||
|
graphiql: p.GraphiQL,
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"main.css": "static/css/main.c17080f1.css",
|
"main.css": "static/css/main.c17080f1.css",
|
||||||
"main.css.map": "static/css/main.c17080f1.css.map",
|
"main.css.map": "static/css/main.c17080f1.css.map",
|
||||||
"main.js": "static/js/main.547de5b3.js",
|
"main.js": "static/js/main.247e472c.js",
|
||||||
"main.js.map": "static/js/main.547de5b3.js.map"
|
"main.js.map": "static/js/main.247e472c.js.map"
|
||||||
}
|
}
|
@ -1 +1 @@
|
|||||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="theme-color" content="#000000"><link rel="manifest" href="/manifest.json"><link rel="shortcut icon" href="/favicon.ico"><title>React App</title><link href="/static/css/main.c17080f1.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script type="text/javascript" src="/static/js/main.547de5b3.js"></script></body></html>
|
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name="theme-color" content="#000000"><link rel="manifest" href="/manifest.json"><link rel="shortcut icon" href="/favicon.ico"><title>React App</title><link href="/static/css/main.c17080f1.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script type="text/javascript" src="/static/js/main.247e472c.js"></script></body></html>
|
@ -1 +1 @@
|
|||||||
"use strict";var precacheConfig=[["/index.html","567808aa124459130c91a80c15d71d75"],["/static/css/main.c17080f1.css","302476b8b379a677f648aa1e48918ebd"],["/static/js/main.547de5b3.js","4475d96003b1a38d6a00115dad58a0db"]],cacheName="sw-precache-v3-sw-precache-webpack-plugin-"+(self.registration?self.registration.scope:""),ignoreUrlParametersMatching=[/^utm_/],addDirectoryIndex=function(e,t){var n=new URL(e);return"/"===n.pathname.slice(-1)&&(n.pathname+=t),n.toString()},cleanResponse=function(t){return t.redirected?("body"in t?Promise.resolve(t.body):t.blob()).then(function(e){return new Response(e,{headers:t.headers,status:t.status,statusText:t.statusText})}):Promise.resolve(t)},createCacheKey=function(e,t,n,r){var a=new URL(e);return r&&a.pathname.match(r)||(a.search+=(a.search?"&":"")+encodeURIComponent(t)+"="+encodeURIComponent(n)),a.toString()},isPathWhitelisted=function(e,t){if(0===e.length)return!0;var n=new URL(t).pathname;return e.some(function(e){return n.match(e)})},stripIgnoredUrlParameters=function(e,n){var t=new URL(e);return t.hash="",t.search=t.search.slice(1).split("&").map(function(e){return e.split("=")}).filter(function(t){return n.every(function(e){return!e.test(t[0])})}).map(function(e){return e.join("=")}).join("&"),t.toString()},hashParamName="_sw-precache",urlsToCacheKeys=new Map(precacheConfig.map(function(e){var t=e[0],n=e[1],r=new URL(t,self.location),a=createCacheKey(r,hashParamName,n,/\.\w{8}\./);return[r.toString(),a]}));function setOfCachedUrls(e){return e.keys().then(function(e){return e.map(function(e){return e.url})}).then(function(e){return new Set(e)})}self.addEventListener("install",function(e){e.waitUntil(caches.open(cacheName).then(function(r){return setOfCachedUrls(r).then(function(n){return Promise.all(Array.from(urlsToCacheKeys.values()).map(function(t){if(!n.has(t)){var e=new Request(t,{credentials:"same-origin"});return fetch(e).then(function(e){if(!e.ok)throw new Error("Request for "+t+" returned a response with status "+e.status);return cleanResponse(e).then(function(e){return r.put(t,e)})})}}))})}).then(function(){return self.skipWaiting()}))}),self.addEventListener("activate",function(e){var n=new Set(urlsToCacheKeys.values());e.waitUntil(caches.open(cacheName).then(function(t){return t.keys().then(function(e){return Promise.all(e.map(function(e){if(!n.has(e.url))return t.delete(e)}))})}).then(function(){return self.clients.claim()}))}),self.addEventListener("fetch",function(t){if("GET"===t.request.method){var e,n=stripIgnoredUrlParameters(t.request.url,ignoreUrlParametersMatching),r="index.html";(e=urlsToCacheKeys.has(n))||(n=addDirectoryIndex(n,r),e=urlsToCacheKeys.has(n));var a="/index.html";!e&&"navigate"===t.request.mode&&isPathWhitelisted(["^(?!\\/__).*"],t.request.url)&&(n=new URL(a,self.location).toString(),e=urlsToCacheKeys.has(n)),e&&t.respondWith(caches.open(cacheName).then(function(e){return e.match(urlsToCacheKeys.get(n)).then(function(e){if(e)return e;throw Error("The cached response that was expected is missing.")})}).catch(function(e){return console.warn('Couldn\'t serve response for "%s" from cache: %O',t.request.url,e),fetch(t.request)}))}});
|
"use strict";var precacheConfig=[["/index.html","beb77075e5de23451b3193c4d44a922c"],["/static/css/main.c17080f1.css","302476b8b379a677f648aa1e48918ebd"],["/static/js/main.247e472c.js","c1802efdceffa79d53e7766deaf1daea"]],cacheName="sw-precache-v3-sw-precache-webpack-plugin-"+(self.registration?self.registration.scope:""),ignoreUrlParametersMatching=[/^utm_/],addDirectoryIndex=function(e,t){var n=new URL(e);return"/"===n.pathname.slice(-1)&&(n.pathname+=t),n.toString()},cleanResponse=function(t){return t.redirected?("body"in t?Promise.resolve(t.body):t.blob()).then(function(e){return new Response(e,{headers:t.headers,status:t.status,statusText:t.statusText})}):Promise.resolve(t)},createCacheKey=function(e,t,n,r){var a=new URL(e);return r&&a.pathname.match(r)||(a.search+=(a.search?"&":"")+encodeURIComponent(t)+"="+encodeURIComponent(n)),a.toString()},isPathWhitelisted=function(e,t){if(0===e.length)return!0;var n=new URL(t).pathname;return e.some(function(e){return n.match(e)})},stripIgnoredUrlParameters=function(e,n){var t=new URL(e);return t.hash="",t.search=t.search.slice(1).split("&").map(function(e){return e.split("=")}).filter(function(t){return n.every(function(e){return!e.test(t[0])})}).map(function(e){return e.join("=")}).join("&"),t.toString()},hashParamName="_sw-precache",urlsToCacheKeys=new Map(precacheConfig.map(function(e){var t=e[0],n=e[1],r=new URL(t,self.location),a=createCacheKey(r,hashParamName,n,/\.\w{8}\./);return[r.toString(),a]}));function setOfCachedUrls(e){return e.keys().then(function(e){return e.map(function(e){return e.url})}).then(function(e){return new Set(e)})}self.addEventListener("install",function(e){e.waitUntil(caches.open(cacheName).then(function(r){return setOfCachedUrls(r).then(function(n){return Promise.all(Array.from(urlsToCacheKeys.values()).map(function(t){if(!n.has(t)){var e=new Request(t,{credentials:"same-origin"});return fetch(e).then(function(e){if(!e.ok)throw new Error("Request for "+t+" returned a response with status "+e.status);return cleanResponse(e).then(function(e){return r.put(t,e)})})}}))})}).then(function(){return self.skipWaiting()}))}),self.addEventListener("activate",function(e){var n=new Set(urlsToCacheKeys.values());e.waitUntil(caches.open(cacheName).then(function(t){return t.keys().then(function(e){return Promise.all(e.map(function(e){if(!n.has(e.url))return t.delete(e)}))})}).then(function(){return self.clients.claim()}))}),self.addEventListener("fetch",function(t){if("GET"===t.request.method){var e,n=stripIgnoredUrlParameters(t.request.url,ignoreUrlParametersMatching),r="index.html";(e=urlsToCacheKeys.has(n))||(n=addDirectoryIndex(n,r),e=urlsToCacheKeys.has(n));var a="/index.html";!e&&"navigate"===t.request.mode&&isPathWhitelisted(["^(?!\\/__).*"],t.request.url)&&(n=new URL(a,self.location).toString(),e=urlsToCacheKeys.has(n)),e&&t.respondWith(caches.open(cacheName).then(function(e){return e.match(urlsToCacheKeys.get(n)).then(function(e){if(e)return e;throw Error("The cached response that was expected is missing.")})}).catch(function(e){return console.warn('Couldn\'t serve response for "%s" from cache: %O',t.request.url,e),fetch(t.request)}))}});
|
2
webui/build/static/js/main.247e472c.js
Normal file
2
webui/build/static/js/main.247e472c.js
Normal file
File diff suppressed because one or more lines are too long
1
webui/build/static/js/main.247e472c.js.map
Normal file
1
webui/build/static/js/main.247e472c.js.map
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -5,4 +5,4 @@ import App from './App';
|
|||||||
import registerServiceWorker from './registerServiceWorker';
|
import registerServiceWorker from './registerServiceWorker';
|
||||||
|
|
||||||
ReactDOM.render(<App />, document.getElementById('root'));
|
ReactDOM.render(<App />, document.getElementById('root'));
|
||||||
registerServiceWorker();
|
// registerServiceWorker();
|
||||||
|
Loading…
Reference in New Issue
Block a user