aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/vektah
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/vektah')
-rw-r--r--vendor/github.com/vektah/gqlgen/LICENSE19
-rw-r--r--vendor/github.com/vektah/gqlgen/graphql/bool.go30
-rw-r--r--vendor/github.com/vektah/gqlgen/graphql/context.go145
-rw-r--r--vendor/github.com/vektah/gqlgen/graphql/defer.go30
-rw-r--r--vendor/github.com/vektah/gqlgen/graphql/error.go46
-rw-r--r--vendor/github.com/vektah/gqlgen/graphql/exec.go118
-rw-r--r--vendor/github.com/vektah/gqlgen/graphql/float.go26
-rw-r--r--vendor/github.com/vektah/gqlgen/graphql/id.go33
-rw-r--r--vendor/github.com/vektah/gqlgen/graphql/int.go26
-rw-r--r--vendor/github.com/vektah/gqlgen/graphql/jsonw.go83
-rw-r--r--vendor/github.com/vektah/gqlgen/graphql/map.go24
-rw-r--r--vendor/github.com/vektah/gqlgen/graphql/oneshot.go14
-rw-r--r--vendor/github.com/vektah/gqlgen/graphql/recovery.go19
-rw-r--r--vendor/github.com/vektah/gqlgen/graphql/response.go18
-rw-r--r--vendor/github.com/vektah/gqlgen/graphql/string.go63
-rw-r--r--vendor/github.com/vektah/gqlgen/graphql/time.go21
-rw-r--r--vendor/github.com/vektah/gqlgen/handler/graphql.go235
-rw-r--r--vendor/github.com/vektah/gqlgen/handler/playground.go51
-rw-r--r--vendor/github.com/vektah/gqlgen/handler/stub.go45
-rw-r--r--vendor/github.com/vektah/gqlgen/handler/websocket.go245
-rw-r--r--vendor/github.com/vektah/gqlgen/neelance/LICENSE24
-rw-r--r--vendor/github.com/vektah/gqlgen/neelance/common/directive.go32
-rw-r--r--vendor/github.com/vektah/gqlgen/neelance/common/lexer.go122
-rw-r--r--vendor/github.com/vektah/gqlgen/neelance/common/literals.go206
-rw-r--r--vendor/github.com/vektah/gqlgen/neelance/common/types.go80
-rw-r--r--vendor/github.com/vektah/gqlgen/neelance/common/values.go77
-rw-r--r--vendor/github.com/vektah/gqlgen/neelance/errors/errors.go41
-rw-r--r--vendor/github.com/vektah/gqlgen/neelance/introspection/introspection.go313
-rw-r--r--vendor/github.com/vektah/gqlgen/neelance/introspection/query.go104
-rw-r--r--vendor/github.com/vektah/gqlgen/neelance/query/query.go261
-rw-r--r--vendor/github.com/vektah/gqlgen/neelance/schema/meta.go193
-rw-r--r--vendor/github.com/vektah/gqlgen/neelance/schema/schema.go489
-rw-r--r--vendor/github.com/vektah/gqlgen/neelance/tests/testdata/LICENSE33
-rw-r--r--vendor/github.com/vektah/gqlgen/neelance/validation/suggestion.go71
-rw-r--r--vendor/github.com/vektah/gqlgen/neelance/validation/validation.go861
35 files changed, 4198 insertions, 0 deletions
diff --git a/vendor/github.com/vektah/gqlgen/LICENSE b/vendor/github.com/vektah/gqlgen/LICENSE
new file mode 100644
index 00000000..18e1b249
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2018 Adam Scarr
+
+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.
diff --git a/vendor/github.com/vektah/gqlgen/graphql/bool.go b/vendor/github.com/vektah/gqlgen/graphql/bool.go
new file mode 100644
index 00000000..7053bbca
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/graphql/bool.go
@@ -0,0 +1,30 @@
+package graphql
+
+import (
+ "fmt"
+ "io"
+ "strings"
+)
+
+func MarshalBoolean(b bool) Marshaler {
+ return WriterFunc(func(w io.Writer) {
+ if b {
+ w.Write(trueLit)
+ } else {
+ w.Write(falseLit)
+ }
+ })
+}
+
+func UnmarshalBoolean(v interface{}) (bool, error) {
+ switch v := v.(type) {
+ case string:
+ return "true" == strings.ToLower(v), nil
+ case int:
+ return v != 0, nil
+ case bool:
+ return v, nil
+ default:
+ return false, fmt.Errorf("%T is not a bool", v)
+ }
+}
diff --git a/vendor/github.com/vektah/gqlgen/graphql/context.go b/vendor/github.com/vektah/gqlgen/graphql/context.go
new file mode 100644
index 00000000..8f544100
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/graphql/context.go
@@ -0,0 +1,145 @@
+package graphql
+
+import (
+ "context"
+ "fmt"
+ "sync"
+
+ "github.com/vektah/gqlgen/neelance/query"
+)
+
+type Resolver func(ctx context.Context) (res interface{}, err error)
+type ResolverMiddleware func(ctx context.Context, next Resolver) (res interface{}, err error)
+type RequestMiddleware func(ctx context.Context, next func(ctx context.Context) []byte) []byte
+
+type RequestContext struct {
+ RawQuery string
+ Variables map[string]interface{}
+ Doc *query.Document
+ // ErrorPresenter will be used to generate the error
+ // message from errors given to Error().
+ ErrorPresenter ErrorPresenterFunc
+ Recover RecoverFunc
+ ResolverMiddleware ResolverMiddleware
+ RequestMiddleware RequestMiddleware
+
+ errorsMu sync.Mutex
+ Errors []*Error
+}
+
+func DefaultResolverMiddleware(ctx context.Context, next Resolver) (res interface{}, err error) {
+ return next(ctx)
+}
+
+func DefaultRequestMiddleware(ctx context.Context, next func(ctx context.Context) []byte) []byte {
+ return next(ctx)
+}
+
+func NewRequestContext(doc *query.Document, query string, variables map[string]interface{}) *RequestContext {
+ return &RequestContext{
+ Doc: doc,
+ RawQuery: query,
+ Variables: variables,
+ ResolverMiddleware: DefaultResolverMiddleware,
+ RequestMiddleware: DefaultRequestMiddleware,
+ Recover: DefaultRecover,
+ ErrorPresenter: DefaultErrorPresenter,
+ }
+}
+
+type key string
+
+const (
+ request key = "request_context"
+ resolver key = "resolver_context"
+)
+
+func GetRequestContext(ctx context.Context) *RequestContext {
+ val := ctx.Value(request)
+ if val == nil {
+ return nil
+ }
+
+ return val.(*RequestContext)
+}
+
+func WithRequestContext(ctx context.Context, rc *RequestContext) context.Context {
+ return context.WithValue(ctx, request, rc)
+}
+
+type ResolverContext struct {
+ // The name of the type this field belongs to
+ Object string
+ // These are the args after processing, they can be mutated in middleware to change what the resolver will get.
+ Args map[string]interface{}
+ // The raw field
+ Field CollectedField
+ // The path of fields to get to this resolver
+ Path []interface{}
+}
+
+func (r *ResolverContext) PushField(alias string) {
+ r.Path = append(r.Path, alias)
+}
+
+func (r *ResolverContext) PushIndex(index int) {
+ r.Path = append(r.Path, index)
+}
+
+func (r *ResolverContext) Pop() {
+ r.Path = r.Path[0 : len(r.Path)-1]
+}
+
+func GetResolverContext(ctx context.Context) *ResolverContext {
+ val := ctx.Value(resolver)
+ if val == nil {
+ return nil
+ }
+
+ return val.(*ResolverContext)
+}
+
+func WithResolverContext(ctx context.Context, rc *ResolverContext) context.Context {
+ parent := GetResolverContext(ctx)
+ rc.Path = nil
+ if parent != nil {
+ rc.Path = append(rc.Path, parent.Path...)
+ }
+ if rc.Field.Alias != "" {
+ rc.PushField(rc.Field.Alias)
+ }
+ return context.WithValue(ctx, resolver, rc)
+}
+
+// This is just a convenient wrapper method for CollectFields
+func CollectFieldsCtx(ctx context.Context, satisfies []string) []CollectedField {
+ reqctx := GetRequestContext(ctx)
+ resctx := GetResolverContext(ctx)
+ return CollectFields(reqctx.Doc, resctx.Field.Selections, satisfies, reqctx.Variables)
+}
+
+// Errorf sends an error string to the client, passing it through the formatter.
+func (c *RequestContext) Errorf(ctx context.Context, format string, args ...interface{}) {
+ c.errorsMu.Lock()
+ defer c.errorsMu.Unlock()
+
+ c.Errors = append(c.Errors, c.ErrorPresenter(ctx, fmt.Errorf(format, args...)))
+}
+
+// Error sends an error to the client, passing it through the formatter.
+func (c *RequestContext) Error(ctx context.Context, err error) {
+ c.errorsMu.Lock()
+ defer c.errorsMu.Unlock()
+
+ c.Errors = append(c.Errors, c.ErrorPresenter(ctx, err))
+}
+
+// AddError is a convenience method for adding an error to the current response
+func AddError(ctx context.Context, err error) {
+ GetRequestContext(ctx).Error(ctx, err)
+}
+
+// AddErrorf is a convenience method for adding an error to the current response
+func AddErrorf(ctx context.Context, format string, args ...interface{}) {
+ GetRequestContext(ctx).Errorf(ctx, format, args...)
+}
diff --git a/vendor/github.com/vektah/gqlgen/graphql/defer.go b/vendor/github.com/vektah/gqlgen/graphql/defer.go
new file mode 100644
index 00000000..79346a84
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/graphql/defer.go
@@ -0,0 +1,30 @@
+package graphql
+
+import (
+ "io"
+ "sync"
+)
+
+// Defer will begin executing the given function and immediately return a result that will block until the function completes
+func Defer(f func() Marshaler) Marshaler {
+ var deferred deferred
+ deferred.mu.Lock()
+
+ go func() {
+ deferred.result = f()
+ deferred.mu.Unlock()
+ }()
+
+ return &deferred
+}
+
+type deferred struct {
+ result Marshaler
+ mu sync.Mutex
+}
+
+func (d *deferred) MarshalGQL(w io.Writer) {
+ d.mu.Lock()
+ d.result.MarshalGQL(w)
+ d.mu.Unlock()
+}
diff --git a/vendor/github.com/vektah/gqlgen/graphql/error.go b/vendor/github.com/vektah/gqlgen/graphql/error.go
new file mode 100644
index 00000000..15e65fab
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/graphql/error.go
@@ -0,0 +1,46 @@
+package graphql
+
+import (
+ "context"
+)
+
+// Error is the standard graphql error type described in https://facebook.github.io/graphql/draft/#sec-Errors
+type Error struct {
+ Message string `json:"message"`
+ Path []interface{} `json:"path,omitempty"`
+ Locations []ErrorLocation `json:"locations,omitempty"`
+ Extensions map[string]interface{} `json:"extensions,omitempty"`
+}
+
+func (e *Error) Error() string {
+ return e.Message
+}
+
+type ErrorLocation struct {
+ Line int `json:"line,omitempty"`
+ Column int `json:"column,omitempty"`
+}
+
+type ErrorPresenterFunc func(context.Context, error) *Error
+
+type ExtendedError interface {
+ Extensions() map[string]interface{}
+}
+
+func DefaultErrorPresenter(ctx context.Context, err error) *Error {
+ if gqlerr, ok := err.(*Error); ok {
+ gqlerr.Path = GetResolverContext(ctx).Path
+ return gqlerr
+ }
+
+ var extensions map[string]interface{}
+ if ee, ok := err.(ExtendedError); ok {
+ extensions = ee.Extensions()
+ }
+
+ return &Error{
+ Message: err.Error(),
+ Path: GetResolverContext(ctx).Path,
+ Extensions: extensions,
+ }
+}
diff --git a/vendor/github.com/vektah/gqlgen/graphql/exec.go b/vendor/github.com/vektah/gqlgen/graphql/exec.go
new file mode 100644
index 00000000..2c034888
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/graphql/exec.go
@@ -0,0 +1,118 @@
+package graphql
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/vektah/gqlgen/neelance/common"
+ "github.com/vektah/gqlgen/neelance/query"
+ "github.com/vektah/gqlgen/neelance/schema"
+)
+
+type ExecutableSchema interface {
+ Schema() *schema.Schema
+
+ Query(ctx context.Context, op *query.Operation) *Response
+ Mutation(ctx context.Context, op *query.Operation) *Response
+ Subscription(ctx context.Context, op *query.Operation) func() *Response
+}
+
+func CollectFields(doc *query.Document, selSet []query.Selection, satisfies []string, variables map[string]interface{}) []CollectedField {
+ return collectFields(doc, selSet, satisfies, variables, map[string]bool{})
+}
+
+func collectFields(doc *query.Document, selSet []query.Selection, satisfies []string, variables map[string]interface{}, visited map[string]bool) []CollectedField {
+ var groupedFields []CollectedField
+
+ for _, sel := range selSet {
+ switch sel := sel.(type) {
+ case *query.Field:
+ f := getOrCreateField(&groupedFields, sel.Alias.Name, func() CollectedField {
+ f := CollectedField{
+ Alias: sel.Alias.Name,
+ Name: sel.Name.Name,
+ }
+ if len(sel.Arguments) > 0 {
+ f.Args = map[string]interface{}{}
+ for _, arg := range sel.Arguments {
+ if variable, ok := arg.Value.(*common.Variable); ok {
+ if val, ok := variables[variable.Name]; ok {
+ f.Args[arg.Name.Name] = val
+ }
+ } else {
+ f.Args[arg.Name.Name] = arg.Value.Value(variables)
+ }
+ }
+ }
+ return f
+ })
+
+ f.Selections = append(f.Selections, sel.Selections...)
+ case *query.InlineFragment:
+ if !instanceOf(sel.On.Ident.Name, satisfies) {
+ continue
+ }
+
+ for _, childField := range collectFields(doc, sel.Selections, satisfies, variables, visited) {
+ f := getOrCreateField(&groupedFields, childField.Name, func() CollectedField { return childField })
+ f.Selections = append(f.Selections, childField.Selections...)
+ }
+
+ case *query.FragmentSpread:
+ fragmentName := sel.Name.Name
+ if _, seen := visited[fragmentName]; seen {
+ continue
+ }
+ visited[fragmentName] = true
+
+ fragment := doc.Fragments.Get(fragmentName)
+ if fragment == nil {
+ // should never happen, validator has already run
+ panic(fmt.Errorf("missing fragment %s", fragmentName))
+ }
+
+ if !instanceOf(fragment.On.Ident.Name, satisfies) {
+ continue
+ }
+
+ for _, childField := range collectFields(doc, fragment.Selections, satisfies, variables, visited) {
+ f := getOrCreateField(&groupedFields, childField.Name, func() CollectedField { return childField })
+ f.Selections = append(f.Selections, childField.Selections...)
+ }
+
+ default:
+ panic(fmt.Errorf("unsupported %T", sel))
+ }
+ }
+
+ return groupedFields
+}
+
+type CollectedField struct {
+ Alias string
+ Name string
+ Args map[string]interface{}
+ Selections []query.Selection
+}
+
+func instanceOf(val string, satisfies []string) bool {
+ for _, s := range satisfies {
+ if val == s {
+ return true
+ }
+ }
+ return false
+}
+
+func getOrCreateField(c *[]CollectedField, name string, creator func() CollectedField) *CollectedField {
+ for i, cf := range *c {
+ if cf.Alias == name {
+ return &(*c)[i]
+ }
+ }
+
+ f := creator()
+
+ *c = append(*c, f)
+ return &(*c)[len(*c)-1]
+}
diff --git a/vendor/github.com/vektah/gqlgen/graphql/float.go b/vendor/github.com/vektah/gqlgen/graphql/float.go
new file mode 100644
index 00000000..c08b490a
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/graphql/float.go
@@ -0,0 +1,26 @@
+package graphql
+
+import (
+ "fmt"
+ "io"
+ "strconv"
+)
+
+func MarshalFloat(f float64) Marshaler {
+ return WriterFunc(func(w io.Writer) {
+ io.WriteString(w, fmt.Sprintf("%f", f))
+ })
+}
+
+func UnmarshalFloat(v interface{}) (float64, error) {
+ switch v := v.(type) {
+ case string:
+ return strconv.ParseFloat(v, 64)
+ case int:
+ return float64(v), nil
+ case float64:
+ return v, nil
+ default:
+ return 0, fmt.Errorf("%T is not an float", v)
+ }
+}
diff --git a/vendor/github.com/vektah/gqlgen/graphql/id.go b/vendor/github.com/vektah/gqlgen/graphql/id.go
new file mode 100644
index 00000000..7958670c
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/graphql/id.go
@@ -0,0 +1,33 @@
+package graphql
+
+import (
+ "fmt"
+ "io"
+ "strconv"
+)
+
+func MarshalID(s string) Marshaler {
+ return WriterFunc(func(w io.Writer) {
+ io.WriteString(w, strconv.Quote(s))
+ })
+}
+func UnmarshalID(v interface{}) (string, error) {
+ switch v := v.(type) {
+ case string:
+ return v, nil
+ case int:
+ return strconv.Itoa(v), nil
+ case float64:
+ return fmt.Sprintf("%f", v), nil
+ case bool:
+ if v {
+ return "true", nil
+ } else {
+ return "false", nil
+ }
+ case nil:
+ return "null", nil
+ default:
+ return "", fmt.Errorf("%T is not a string", v)
+ }
+}
diff --git a/vendor/github.com/vektah/gqlgen/graphql/int.go b/vendor/github.com/vektah/gqlgen/graphql/int.go
new file mode 100644
index 00000000..b63b4c2a
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/graphql/int.go
@@ -0,0 +1,26 @@
+package graphql
+
+import (
+ "fmt"
+ "io"
+ "strconv"
+)
+
+func MarshalInt(i int) Marshaler {
+ return WriterFunc(func(w io.Writer) {
+ io.WriteString(w, strconv.Itoa(i))
+ })
+}
+
+func UnmarshalInt(v interface{}) (int, error) {
+ switch v := v.(type) {
+ case string:
+ return strconv.Atoi(v)
+ case int:
+ return v, nil
+ case float64:
+ return int(v), nil
+ default:
+ return 0, fmt.Errorf("%T is not an int", v)
+ }
+}
diff --git a/vendor/github.com/vektah/gqlgen/graphql/jsonw.go b/vendor/github.com/vektah/gqlgen/graphql/jsonw.go
new file mode 100644
index 00000000..ef9e69c7
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/graphql/jsonw.go
@@ -0,0 +1,83 @@
+package graphql
+
+import (
+ "io"
+ "strconv"
+)
+
+var nullLit = []byte(`null`)
+var trueLit = []byte(`true`)
+var falseLit = []byte(`false`)
+var openBrace = []byte(`{`)
+var closeBrace = []byte(`}`)
+var openBracket = []byte(`[`)
+var closeBracket = []byte(`]`)
+var colon = []byte(`:`)
+var comma = []byte(`,`)
+
+var Null = lit(nullLit)
+var True = lit(trueLit)
+var False = lit(falseLit)
+
+type Marshaler interface {
+ MarshalGQL(w io.Writer)
+}
+
+type Unmarshaler interface {
+ UnmarshalGQL(v interface{}) error
+}
+
+type OrderedMap struct {
+ Keys []string
+ Values []Marshaler
+}
+
+type WriterFunc func(writer io.Writer)
+
+func (f WriterFunc) MarshalGQL(w io.Writer) {
+ f(w)
+}
+
+func NewOrderedMap(len int) *OrderedMap {
+ return &OrderedMap{
+ Keys: make([]string, len),
+ Values: make([]Marshaler, len),
+ }
+}
+
+func (m *OrderedMap) Add(key string, value Marshaler) {
+ m.Keys = append(m.Keys, key)
+ m.Values = append(m.Values, value)
+}
+
+func (m *OrderedMap) MarshalGQL(writer io.Writer) {
+ writer.Write(openBrace)
+ for i, key := range m.Keys {
+ if i != 0 {
+ writer.Write(comma)
+ }
+ io.WriteString(writer, strconv.Quote(key))
+ writer.Write(colon)
+ m.Values[i].MarshalGQL(writer)
+ }
+ writer.Write(closeBrace)
+}
+
+type Array []Marshaler
+
+func (a Array) MarshalGQL(writer io.Writer) {
+ writer.Write(openBracket)
+ for i, val := range a {
+ if i != 0 {
+ writer.Write(comma)
+ }
+ val.MarshalGQL(writer)
+ }
+ writer.Write(closeBracket)
+}
+
+func lit(b []byte) Marshaler {
+ return WriterFunc(func(w io.Writer) {
+ w.Write(b)
+ })
+}
diff --git a/vendor/github.com/vektah/gqlgen/graphql/map.go b/vendor/github.com/vektah/gqlgen/graphql/map.go
new file mode 100644
index 00000000..1e91d1d9
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/graphql/map.go
@@ -0,0 +1,24 @@
+package graphql
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+)
+
+func MarshalMap(val map[string]interface{}) Marshaler {
+ return WriterFunc(func(w io.Writer) {
+ err := json.NewEncoder(w).Encode(val)
+ if err != nil {
+ panic(err)
+ }
+ })
+}
+
+func UnmarshalMap(v interface{}) (map[string]interface{}, error) {
+ if m, ok := v.(map[string]interface{}); ok {
+ return m, nil
+ }
+
+ return nil, fmt.Errorf("%T is not a map", v)
+}
diff --git a/vendor/github.com/vektah/gqlgen/graphql/oneshot.go b/vendor/github.com/vektah/gqlgen/graphql/oneshot.go
new file mode 100644
index 00000000..dd31f5ba
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/graphql/oneshot.go
@@ -0,0 +1,14 @@
+package graphql
+
+func OneShot(resp *Response) func() *Response {
+ var oneshot bool
+
+ return func() *Response {
+ if oneshot {
+ return nil
+ }
+ oneshot = true
+
+ return resp
+ }
+}
diff --git a/vendor/github.com/vektah/gqlgen/graphql/recovery.go b/vendor/github.com/vektah/gqlgen/graphql/recovery.go
new file mode 100644
index 00000000..3aa032dc
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/graphql/recovery.go
@@ -0,0 +1,19 @@
+package graphql
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "os"
+ "runtime/debug"
+)
+
+type RecoverFunc func(ctx context.Context, err interface{}) (userMessage error)
+
+func DefaultRecover(ctx context.Context, err interface{}) error {
+ fmt.Fprintln(os.Stderr, err)
+ fmt.Fprintln(os.Stderr)
+ debug.PrintStack()
+
+ return errors.New("internal system error")
+}
diff --git a/vendor/github.com/vektah/gqlgen/graphql/response.go b/vendor/github.com/vektah/gqlgen/graphql/response.go
new file mode 100644
index 00000000..c0dc1c23
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/graphql/response.go
@@ -0,0 +1,18 @@
+package graphql
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+)
+
+type Response struct {
+ Data json.RawMessage `json:"data"`
+ Errors []*Error `json:"errors,omitempty"`
+}
+
+func ErrorResponse(ctx context.Context, messagef string, args ...interface{}) *Response {
+ return &Response{
+ Errors: []*Error{{Message: fmt.Sprintf(messagef, args...)}},
+ }
+}
diff --git a/vendor/github.com/vektah/gqlgen/graphql/string.go b/vendor/github.com/vektah/gqlgen/graphql/string.go
new file mode 100644
index 00000000..d5fb3294
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/graphql/string.go
@@ -0,0 +1,63 @@
+package graphql
+
+import (
+ "fmt"
+ "io"
+ "strconv"
+)
+
+const encodeHex = "0123456789ABCDEF"
+
+func MarshalString(s string) Marshaler {
+ return WriterFunc(func(w io.Writer) {
+ start := 0
+ io.WriteString(w, `"`)
+
+ for i, c := range s {
+ if c < 0x20 || c == '\\' || c == '"' {
+ io.WriteString(w, s[start:i])
+
+ switch c {
+ case '\t':
+ io.WriteString(w, `\t`)
+ case '\r':
+ io.WriteString(w, `\r`)
+ case '\n':
+ io.WriteString(w, `\n`)
+ case '\\':
+ io.WriteString(w, `\\`)
+ case '"':
+ io.WriteString(w, `\"`)
+ default:
+ io.WriteString(w, `\u00`)
+ w.Write([]byte{encodeHex[c>>4], encodeHex[c&0xf]})
+ }
+
+ start = i + 1
+ }
+ }
+
+ io.WriteString(w, s[start:])
+ io.WriteString(w, `"`)
+ })
+}
+func UnmarshalString(v interface{}) (string, error) {
+ switch v := v.(type) {
+ case string:
+ return v, nil
+ case int:
+ return strconv.Itoa(v), nil
+ case float64:
+ return fmt.Sprintf("%f", v), nil
+ case bool:
+ if v {
+ return "true", nil
+ } else {
+ return "false", nil
+ }
+ case nil:
+ return "null", nil
+ default:
+ return "", fmt.Errorf("%T is not a string", v)
+ }
+}
diff --git a/vendor/github.com/vektah/gqlgen/graphql/time.go b/vendor/github.com/vektah/gqlgen/graphql/time.go
new file mode 100644
index 00000000..4f448560
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/graphql/time.go
@@ -0,0 +1,21 @@
+package graphql
+
+import (
+ "errors"
+ "io"
+ "strconv"
+ "time"
+)
+
+func MarshalTime(t time.Time) Marshaler {
+ return WriterFunc(func(w io.Writer) {
+ io.WriteString(w, strconv.Quote(t.Format(time.RFC3339)))
+ })
+}
+
+func UnmarshalTime(v interface{}) (time.Time, error) {
+ if tmpStr, ok := v.(string); ok {
+ return time.Parse(time.RFC3339, tmpStr)
+ }
+ return time.Time{}, errors.New("time should be RFC3339 formatted string")
+}
diff --git a/vendor/github.com/vektah/gqlgen/handler/graphql.go b/vendor/github.com/vektah/gqlgen/handler/graphql.go
new file mode 100644
index 00000000..4a5c61f5
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/handler/graphql.go
@@ -0,0 +1,235 @@
+package handler
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "strings"
+
+ "github.com/gorilla/websocket"
+ "github.com/vektah/gqlgen/graphql"
+ "github.com/vektah/gqlgen/neelance/errors"
+ "github.com/vektah/gqlgen/neelance/query"
+ "github.com/vektah/gqlgen/neelance/validation"
+)
+
+type params struct {
+ Query string `json:"query"`
+ OperationName string `json:"operationName"`
+ Variables map[string]interface{} `json:"variables"`
+}
+
+type Config struct {
+ upgrader websocket.Upgrader
+ recover graphql.RecoverFunc
+ errorPresenter graphql.ErrorPresenterFunc
+ resolverHook graphql.ResolverMiddleware
+ requestHook graphql.RequestMiddleware
+}
+
+func (c *Config) newRequestContext(doc *query.Document, query string, variables map[string]interface{}) *graphql.RequestContext {
+ reqCtx := graphql.NewRequestContext(doc, query, variables)
+ if hook := c.recover; hook != nil {
+ reqCtx.Recover = hook
+ }
+
+ if hook := c.errorPresenter; hook != nil {
+ reqCtx.ErrorPresenter = hook
+ }
+
+ if hook := c.resolverHook; hook != nil {
+ reqCtx.ResolverMiddleware = hook
+ }
+
+ if hook := c.requestHook; hook != nil {
+ reqCtx.RequestMiddleware = hook
+ }
+
+ return reqCtx
+}
+
+type Option func(cfg *Config)
+
+func WebsocketUpgrader(upgrader websocket.Upgrader) Option {
+ return func(cfg *Config) {
+ cfg.upgrader = upgrader
+ }
+}
+
+func RecoverFunc(recover graphql.RecoverFunc) Option {
+ return func(cfg *Config) {
+ cfg.recover = recover
+ }
+}
+
+// ErrorPresenter transforms errors found while resolving into errors that will be returned to the user. It provides
+// a good place to add any extra fields, like error.type, that might be desired by your frontend. Check the default
+// implementation in graphql.DefaultErrorPresenter for an example.
+func ErrorPresenter(f graphql.ErrorPresenterFunc) Option {
+ return func(cfg *Config) {
+ cfg.errorPresenter = f
+ }
+}
+
+// ResolverMiddleware allows you to define a function that will be called around every resolver,
+// useful for tracing and logging.
+// It will only be called for user defined resolvers, any direct binding to models is assumed
+// to cost nothing.
+func ResolverMiddleware(middleware graphql.ResolverMiddleware) Option {
+ return func(cfg *Config) {
+ if cfg.resolverHook == nil {
+ cfg.resolverHook = middleware
+ return
+ }
+
+ lastResolve := cfg.resolverHook
+ cfg.resolverHook = func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
+ return lastResolve(ctx, func(ctx context.Context) (res interface{}, err error) {
+ return middleware(ctx, next)
+ })
+ }
+ }
+}
+
+// RequestMiddleware allows you to define a function that will be called around the root request,
+// after the query has been parsed. This is useful for logging and tracing
+func RequestMiddleware(middleware graphql.RequestMiddleware) Option {
+ return func(cfg *Config) {
+ if cfg.requestHook == nil {
+ cfg.requestHook = middleware
+ return
+ }
+
+ lastResolve := cfg.requestHook
+ cfg.requestHook = func(ctx context.Context, next func(ctx context.Context) []byte) []byte {
+ return lastResolve(ctx, func(ctx context.Context) []byte {
+ return middleware(ctx, next)
+ })
+ }
+ }
+}
+
+func GraphQL(exec graphql.ExecutableSchema, options ...Option) http.HandlerFunc {
+ cfg := Config{
+ upgrader: websocket.Upgrader{
+ ReadBufferSize: 1024,
+ WriteBufferSize: 1024,
+ },
+ }
+
+ for _, option := range options {
+ option(&cfg)
+ }
+
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == http.MethodOptions {
+ w.Header().Set("Allow", "OPTIONS, GET, POST")
+ w.WriteHeader(http.StatusOK)
+ return
+ }
+
+ if strings.Contains(r.Header.Get("Upgrade"), "websocket") {
+ connectWs(exec, w, r, &cfg)
+ return
+ }
+
+ var reqParams params
+ switch r.Method {
+ case http.MethodGet:
+ reqParams.Query = r.URL.Query().Get("query")
+ reqParams.OperationName = r.URL.Query().Get("operationName")
+
+ if variables := r.URL.Query().Get("variables"); variables != "" {
+ if err := json.Unmarshal([]byte(variables), &reqParams.Variables); err != nil {
+ sendErrorf(w, http.StatusBadRequest, "variables could not be decoded")
+ return
+ }
+ }
+ case http.MethodPost:
+ if err := json.NewDecoder(r.Body).Decode(&reqParams); err != nil {
+ sendErrorf(w, http.StatusBadRequest, "json body could not be decoded: "+err.Error())
+ return
+ }
+ default:
+ w.WriteHeader(http.StatusMethodNotAllowed)
+ return
+ }
+ w.Header().Set("Content-Type", "application/json")
+
+ doc, qErr := query.Parse(reqParams.Query)
+ if qErr != nil {
+ sendError(w, http.StatusUnprocessableEntity, qErr)
+ return
+ }
+
+ errs := validation.Validate(exec.Schema(), doc)
+ if len(errs) != 0 {
+ sendError(w, http.StatusUnprocessableEntity, errs...)
+ return
+ }
+
+ op, err := doc.GetOperation(reqParams.OperationName)
+ if err != nil {
+ sendErrorf(w, http.StatusUnprocessableEntity, err.Error())
+ return
+ }
+
+ reqCtx := cfg.newRequestContext(doc, reqParams.Query, reqParams.Variables)
+ ctx := graphql.WithRequestContext(r.Context(), reqCtx)
+
+ defer func() {
+ if err := recover(); err != nil {
+ userErr := reqCtx.Recover(ctx, err)
+ sendErrorf(w, http.StatusUnprocessableEntity, userErr.Error())
+ }
+ }()
+
+ switch op.Type {
+ case query.Query:
+ b, err := json.Marshal(exec.Query(ctx, op))
+ if err != nil {
+ panic(err)
+ }
+ w.Write(b)
+ case query.Mutation:
+ b, err := json.Marshal(exec.Mutation(ctx, op))
+ if err != nil {
+ panic(err)
+ }
+ w.Write(b)
+ default:
+ sendErrorf(w, http.StatusBadRequest, "unsupported operation type")
+ }
+ })
+}
+
+func sendError(w http.ResponseWriter, code int, errors ...*errors.QueryError) {
+ w.WriteHeader(code)
+ var errs []*graphql.Error
+ for _, err := range errors {
+ var locations []graphql.ErrorLocation
+ for _, l := range err.Locations {
+ fmt.Println(graphql.ErrorLocation(l))
+ locations = append(locations, graphql.ErrorLocation{
+ Line: l.Line,
+ Column: l.Column,
+ })
+ }
+
+ errs = append(errs, &graphql.Error{
+ Message: err.Message,
+ Path: err.Path,
+ Locations: locations,
+ })
+ }
+ b, err := json.Marshal(&graphql.Response{Errors: errs})
+ if err != nil {
+ panic(err)
+ }
+ w.Write(b)
+}
+
+func sendErrorf(w http.ResponseWriter, code int, format string, args ...interface{}) {
+ sendError(w, code, &errors.QueryError{Message: fmt.Sprintf(format, args...)})
+}
diff --git a/vendor/github.com/vektah/gqlgen/handler/playground.go b/vendor/github.com/vektah/gqlgen/handler/playground.go
new file mode 100644
index 00000000..44533590
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/handler/playground.go
@@ -0,0 +1,51 @@
+package handler
+
+import (
+ "html/template"
+ "net/http"
+)
+
+var page = template.Must(template.New("graphiql").Parse(`<!DOCTYPE html>
+<html>
+<head>
+ <meta charset=utf-8/>
+ <meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
+ <link rel="shortcut icon" href="https://graphcool-playground.netlify.com/favicon.png">
+ <link rel="stylesheet" href="//cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/static/css/index.css"/>
+ <link rel="shortcut icon" href="//cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/favicon.png"/>
+ <script src="//cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/static/js/middleware.js"></script>
+ <title>{{.title}}</title>
+</head>
+<body>
+<style type="text/css">
+ html { font-family: "Open Sans", sans-serif; overflow: hidden; }
+ body { margin: 0; background: #172a3a; }
+</style>
+<div id="root"/>
+<script type="text/javascript">
+ window.addEventListener('load', function (event) {
+ const root = document.getElementById('root');
+ root.classList.add('playgroundIn');
+ const wsProto = location.protocol == 'https:' ? 'wss:' : 'ws:'
+ GraphQLPlayground.init(root, {
+ endpoint: location.protocol + '//' + location.host + '{{.endpoint}}',
+ subscriptionsEndpoint: wsProto + '//' + location.host + '{{.endpoint }}',
+ })
+ })
+</script>
+</body>
+</html>
+`))
+
+func Playground(title string, endpoint string) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ err := page.Execute(w, map[string]string{
+ "title": title,
+ "endpoint": endpoint,
+ "version": "1.4.3",
+ })
+ if err != nil {
+ panic(err)
+ }
+ }
+}
diff --git a/vendor/github.com/vektah/gqlgen/handler/stub.go b/vendor/github.com/vektah/gqlgen/handler/stub.go
new file mode 100644
index 00000000..46b27e46
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/handler/stub.go
@@ -0,0 +1,45 @@
+package handler
+
+import (
+ "context"
+ "time"
+
+ "github.com/vektah/gqlgen/graphql"
+ "github.com/vektah/gqlgen/neelance/query"
+ "github.com/vektah/gqlgen/neelance/schema"
+)
+
+type executableSchemaStub struct {
+}
+
+var _ graphql.ExecutableSchema = &executableSchemaStub{}
+
+func (e *executableSchemaStub) Schema() *schema.Schema {
+ return schema.MustParse(`
+ schema { query: Query }
+ type Query { me: User! }
+ type User { name: String! }
+ `)
+}
+
+func (e *executableSchemaStub) Query(ctx context.Context, op *query.Operation) *graphql.Response {
+ return &graphql.Response{Data: []byte(`{"name":"test"}`)}
+}
+
+func (e *executableSchemaStub) Mutation(ctx context.Context, op *query.Operation) *graphql.Response {
+ return graphql.ErrorResponse(ctx, "mutations are not supported")
+}
+
+func (e *executableSchemaStub) Subscription(ctx context.Context, op *query.Operation) func() *graphql.Response {
+ return func() *graphql.Response {
+ time.Sleep(50 * time.Millisecond)
+ select {
+ case <-ctx.Done():
+ return nil
+ default:
+ return &graphql.Response{
+ Data: []byte(`{"name":"test"}`),
+ }
+ }
+ }
+}
diff --git a/vendor/github.com/vektah/gqlgen/handler/websocket.go b/vendor/github.com/vektah/gqlgen/handler/websocket.go
new file mode 100644
index 00000000..e80748ca
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/handler/websocket.go
@@ -0,0 +1,245 @@
+package handler
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "log"
+ "net/http"
+ "sync"
+
+ "github.com/gorilla/websocket"
+ "github.com/vektah/gqlgen/graphql"
+ "github.com/vektah/gqlgen/neelance/errors"
+ "github.com/vektah/gqlgen/neelance/query"
+ "github.com/vektah/gqlgen/neelance/validation"
+)
+
+const (
+ connectionInitMsg = "connection_init" // Client -> Server
+ connectionTerminateMsg = "connection_terminate" // Client -> Server
+ startMsg = "start" // Client -> Server
+ stopMsg = "stop" // Client -> Server
+ connectionAckMsg = "connection_ack" // Server -> Client
+ connectionErrorMsg = "connection_error" // Server -> Client
+ dataMsg = "data" // Server -> Client
+ errorMsg = "error" // Server -> Client
+ completeMsg = "complete" // Server -> Client
+ //connectionKeepAliveMsg = "ka" // Server -> Client TODO: keepalives
+)
+
+type operationMessage struct {
+ Payload json.RawMessage `json:"payload,omitempty"`
+ ID string `json:"id,omitempty"`
+ Type string `json:"type"`
+}
+
+type wsConnection struct {
+ ctx context.Context
+ conn *websocket.Conn
+ exec graphql.ExecutableSchema
+ active map[string]context.CancelFunc
+ mu sync.Mutex
+ cfg *Config
+}
+
+func connectWs(exec graphql.ExecutableSchema, w http.ResponseWriter, r *http.Request, cfg *Config) {
+ ws, err := cfg.upgrader.Upgrade(w, r, http.Header{
+ "Sec-Websocket-Protocol": []string{"graphql-ws"},
+ })
+ if err != nil {
+ log.Printf("unable to upgrade %T to websocket %s: ", w, err.Error())
+ sendErrorf(w, http.StatusBadRequest, "unable to upgrade")
+ return
+ }
+
+ conn := wsConnection{
+ active: map[string]context.CancelFunc{},
+ exec: exec,
+ conn: ws,
+ ctx: r.Context(),
+ cfg: cfg,
+ }
+
+ if !conn.init() {
+ return
+ }
+
+ conn.run()
+}
+
+func (c *wsConnection) init() bool {
+ message := c.readOp()
+ if message == nil {
+ c.close(websocket.CloseProtocolError, "decoding error")
+ return false
+ }
+
+ switch message.Type {
+ case connectionInitMsg:
+ c.write(&operationMessage{Type: connectionAckMsg})
+ case connectionTerminateMsg:
+ c.close(websocket.CloseNormalClosure, "terminated")
+ return false
+ default:
+ c.sendConnectionError("unexpected message %s", message.Type)
+ c.close(websocket.CloseProtocolError, "unexpected message")
+ return false
+ }
+
+ return true
+}
+
+func (c *wsConnection) write(msg *operationMessage) {
+ c.mu.Lock()
+ c.conn.WriteJSON(msg)
+ c.mu.Unlock()
+}
+
+func (c *wsConnection) run() {
+ for {
+ message := c.readOp()
+ if message == nil {
+ return
+ }
+
+ switch message.Type {
+ case startMsg:
+ if !c.subscribe(message) {
+ return
+ }
+ case stopMsg:
+ c.mu.Lock()
+ closer := c.active[message.ID]
+ c.mu.Unlock()
+ if closer == nil {
+ c.sendError(message.ID, errors.Errorf("%s is not running, cannot stop", message.ID))
+ continue
+ }
+
+ closer()
+ case connectionTerminateMsg:
+ c.close(websocket.CloseNormalClosure, "terminated")
+ return
+ default:
+ c.sendConnectionError("unexpected message %s", message.Type)
+ c.close(websocket.CloseProtocolError, "unexpected message")
+ return
+ }
+ }
+}
+
+func (c *wsConnection) subscribe(message *operationMessage) bool {
+ var reqParams params
+ if err := json.Unmarshal(message.Payload, &reqParams); err != nil {
+ c.sendConnectionError("invalid json")
+ return false
+ }
+
+ doc, qErr := query.Parse(reqParams.Query)
+ if qErr != nil {
+ c.sendError(message.ID, qErr)
+ return true
+ }
+
+ errs := validation.Validate(c.exec.Schema(), doc)
+ if len(errs) != 0 {
+ c.sendError(message.ID, errs...)
+ return true
+ }
+
+ op, err := doc.GetOperation(reqParams.OperationName)
+ if err != nil {
+ c.sendError(message.ID, errors.Errorf("%s", err.Error()))
+ return true
+ }
+
+ reqCtx := c.cfg.newRequestContext(doc, reqParams.Query, reqParams.Variables)
+ ctx := graphql.WithRequestContext(c.ctx, reqCtx)
+
+ if op.Type != query.Subscription {
+ var result *graphql.Response
+ if op.Type == query.Query {
+ result = c.exec.Query(ctx, op)
+ } else {
+ result = c.exec.Mutation(ctx, op)
+ }
+
+ c.sendData(message.ID, result)
+ c.write(&operationMessage{ID: message.ID, Type: completeMsg})
+ return true
+ }
+
+ ctx, cancel := context.WithCancel(ctx)
+ c.mu.Lock()
+ c.active[message.ID] = cancel
+ c.mu.Unlock()
+ go func() {
+ defer func() {
+ if r := recover(); r != nil {
+ userErr := reqCtx.Recover(ctx, r)
+ c.sendError(message.ID, &errors.QueryError{Message: userErr.Error()})
+ }
+ }()
+ next := c.exec.Subscription(ctx, op)
+ for result := next(); result != nil; result = next() {
+ c.sendData(message.ID, result)
+ }
+
+ c.write(&operationMessage{ID: message.ID, Type: completeMsg})
+
+ c.mu.Lock()
+ delete(c.active, message.ID)
+ c.mu.Unlock()
+ cancel()
+ }()
+
+ return true
+}
+
+func (c *wsConnection) sendData(id string, response *graphql.Response) {
+ b, err := json.Marshal(response)
+ if err != nil {
+ c.sendError(id, errors.Errorf("unable to encode json response: %s", err.Error()))
+ return
+ }
+
+ c.write(&operationMessage{Type: dataMsg, ID: id, Payload: b})
+}
+
+func (c *wsConnection) sendError(id string, errors ...*errors.QueryError) {
+ var errs []error
+ for _, err := range errors {
+ errs = append(errs, err)
+ }
+ b, err := json.Marshal(errs)
+ if err != nil {
+ panic(err)
+ }
+ c.write(&operationMessage{Type: errorMsg, ID: id, Payload: b})
+}
+
+func (c *wsConnection) sendConnectionError(format string, args ...interface{}) {
+ b, err := json.Marshal(&graphql.Error{Message: fmt.Sprintf(format, args...)})
+ if err != nil {
+ panic(err)
+ }
+
+ c.write(&operationMessage{Type: connectionErrorMsg, Payload: b})
+}
+
+func (c *wsConnection) readOp() *operationMessage {
+ message := operationMessage{}
+ if err := c.conn.ReadJSON(&message); err != nil {
+ c.sendConnectionError("invalid json")
+ return nil
+ }
+ return &message
+}
+
+func (c *wsConnection) close(closeCode int, message string) {
+ c.mu.Lock()
+ _ = c.conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(closeCode, message))
+ c.mu.Unlock()
+ _ = c.conn.Close()
+}
diff --git a/vendor/github.com/vektah/gqlgen/neelance/LICENSE b/vendor/github.com/vektah/gqlgen/neelance/LICENSE
new file mode 100644
index 00000000..3907ceca
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/neelance/LICENSE
@@ -0,0 +1,24 @@
+Copyright (c) 2016 Richard Musiol. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/vektah/gqlgen/neelance/common/directive.go b/vendor/github.com/vektah/gqlgen/neelance/common/directive.go
new file mode 100644
index 00000000..62dca47f
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/neelance/common/directive.go
@@ -0,0 +1,32 @@
+package common
+
+type Directive struct {
+ Name Ident
+ Args ArgumentList
+}
+
+func ParseDirectives(l *Lexer) DirectiveList {
+ var directives DirectiveList
+ for l.Peek() == '@' {
+ l.ConsumeToken('@')
+ d := &Directive{}
+ d.Name = l.ConsumeIdentWithLoc()
+ d.Name.Loc.Column--
+ if l.Peek() == '(' {
+ d.Args = ParseArguments(l)
+ }
+ directives = append(directives, d)
+ }
+ return directives
+}
+
+type DirectiveList []*Directive
+
+func (l DirectiveList) Get(name string) *Directive {
+ for _, d := range l {
+ if d.Name.Name == name {
+ return d
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/vektah/gqlgen/neelance/common/lexer.go b/vendor/github.com/vektah/gqlgen/neelance/common/lexer.go
new file mode 100644
index 00000000..fdc1e622
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/neelance/common/lexer.go
@@ -0,0 +1,122 @@
+package common
+
+import (
+ "fmt"
+ "text/scanner"
+
+ "github.com/vektah/gqlgen/neelance/errors"
+)
+
+type syntaxError string
+
+type Lexer struct {
+ sc *scanner.Scanner
+ next rune
+ descComment string
+}
+
+type Ident struct {
+ Name string
+ Loc errors.Location
+}
+
+func New(sc *scanner.Scanner) *Lexer {
+ l := &Lexer{sc: sc}
+ l.Consume()
+ return l
+}
+
+func (l *Lexer) CatchSyntaxError(f func()) (errRes *errors.QueryError) {
+ defer func() {
+ if err := recover(); err != nil {
+ if err, ok := err.(syntaxError); ok {
+ errRes = errors.Errorf("syntax error: %s", err)
+ errRes.Locations = []errors.Location{l.Location()}
+ return
+ }
+ panic(err)
+ }
+ }()
+
+ f()
+ return
+}
+
+func (l *Lexer) Peek() rune {
+ return l.next
+}
+
+func (l *Lexer) Consume() {
+ l.descComment = ""
+ for {
+ l.next = l.sc.Scan()
+ if l.next == ',' {
+ continue
+ }
+ if l.next == '#' {
+ if l.sc.Peek() == ' ' {
+ l.sc.Next()
+ }
+ if l.descComment != "" {
+ l.descComment += "\n"
+ }
+ for {
+ next := l.sc.Next()
+ if next == '\n' || next == scanner.EOF {
+ break
+ }
+ l.descComment += string(next)
+ }
+ continue
+ }
+ break
+ }
+}
+
+func (l *Lexer) ConsumeIdent() string {
+ name := l.sc.TokenText()
+ l.ConsumeToken(scanner.Ident)
+ return name
+}
+
+func (l *Lexer) ConsumeIdentWithLoc() Ident {
+ loc := l.Location()
+ name := l.sc.TokenText()
+ l.ConsumeToken(scanner.Ident)
+ return Ident{name, loc}
+}
+
+func (l *Lexer) ConsumeKeyword(keyword string) {
+ if l.next != scanner.Ident || l.sc.TokenText() != keyword {
+ l.SyntaxError(fmt.Sprintf("unexpected %q, expecting %q", l.sc.TokenText(), keyword))
+ }
+ l.Consume()
+}
+
+func (l *Lexer) ConsumeLiteral() *BasicLit {
+ lit := &BasicLit{Type: l.next, Text: l.sc.TokenText()}
+ l.Consume()
+ return lit
+}
+
+func (l *Lexer) ConsumeToken(expected rune) {
+ if l.next != expected {
+ l.SyntaxError(fmt.Sprintf("unexpected %q, expecting %s", l.sc.TokenText(), scanner.TokenString(expected)))
+ }
+ l.Consume()
+}
+
+func (l *Lexer) DescComment() string {
+ return l.descComment
+}
+
+func (l *Lexer) SyntaxError(message string) {
+ panic(syntaxError(message))
+}
+
+func (l *Lexer) Location() errors.Location {
+ return errors.Location{
+ Line: l.sc.Line,
+ Column: l.sc.Column,
+ }
+}
diff --git a/vendor/github.com/vektah/gqlgen/neelance/common/literals.go b/vendor/github.com/vektah/gqlgen/neelance/common/literals.go
new file mode 100644
index 00000000..55619ba0
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/neelance/common/literals.go
@@ -0,0 +1,206 @@
+package common
+
+import (
+ "strconv"
+ "strings"
+ "text/scanner"
+
+ "github.com/vektah/gqlgen/neelance/errors"
+)
+
+type Literal interface {
+ Value(vars map[string]interface{}) interface{}
+ String() string
+ Location() errors.Location
+}
+
+type BasicLit struct {
+ Type rune
+ Text string
+ Loc errors.Location
+}
+
+func (lit *BasicLit) Value(vars map[string]interface{}) interface{} {
+ switch lit.Type {
+ case scanner.Int:
+ value, err := strconv.ParseInt(lit.Text, 10, 64)
+ if err != nil {
+ panic(err)
+ }
+ return int(value)
+
+ case scanner.Float:
+ value, err := strconv.ParseFloat(lit.Text, 64)
+ if err != nil {
+ panic(err)
+ }
+ return value
+
+ case scanner.String:
+ value, err := strconv.Unquote(lit.Text)
+ if err != nil {
+ panic(err)
+ }
+ return value
+
+ case scanner.Ident:
+ switch lit.Text {
+ case "true":
+ return true
+ case "false":
+ return false
+ default:
+ return lit.Text
+ }
+
+ default:
+ panic("invalid literal")
+ }
+}
+
+func (lit *BasicLit) String() string {
+ return lit.Text
+}
+
+func (lit *BasicLit) Location() errors.Location {
+ return lit.Loc
+}
+
+type ListLit struct {
+ Entries []Literal
+ Loc errors.Location
+}
+
+func (lit *ListLit) Value(vars map[string]interface{}) interface{} {
+ entries := make([]interface{}, len(lit.Entries))
+ for i, entry := range lit.Entries {
+ entries[i] = entry.Value(vars)
+ }
+ return entries
+}
+
+func (lit *ListLit) String() string {
+ entries := make([]string, len(lit.Entries))
+ for i, entry := range lit.Entries {
+ entries[i] = entry.String()
+ }
+ return "[" + strings.Join(entries, ", ") + "]"
+}
+
+func (lit *ListLit) Location() errors.Location {
+ return lit.Loc
+}
+
+type ObjectLit struct {
+ Fields []*ObjectLitField
+ Loc errors.Location
+}
+
+type ObjectLitField struct {
+ Name Ident
+ Value Literal
+}
+
+func (lit *ObjectLit) Value(vars map[string]interface{}) interface{} {
+ fields := make(map[string]interface{}, len(lit.Fields))
+ for _, f := range lit.Fields {
+ fields[f.Name.Name] = f.Value.Value(vars)
+ }
+ return fields
+}
+
+func (lit *ObjectLit) String() string {
+ entries := make([]string, 0, len(lit.Fields))
+ for _, f := range lit.Fields {
+ entries = append(entries, f.Name.Name+": "+f.Value.String())
+ }
+ return "{" + strings.Join(entries, ", ") + "}"
+}
+
+func (lit *ObjectLit) Location() errors.Location {
+ return lit.Loc
+}
+
+type NullLit struct {
+ Loc errors.Location
+}
+
+func (lit *NullLit) Value(vars map[string]interface{}) interface{} {
+ return nil
+}
+
+func (lit *NullLit) String() string {
+ return "null"
+}
+
+func (lit *NullLit) Location() errors.Location {
+ return lit.Loc
+}
+
+type Variable struct {
+ Name string
+ Loc errors.Location
+}
+
+func (v Variable) Value(vars map[string]interface{}) interface{} {
+ return vars[v.Name]
+}
+
+func (v Variable) String() string {
+ return "$" + v.Name
+}
+
+func (v *Variable) Location() errors.Location {
+ return v.Loc
+}
+
+func ParseLiteral(l *Lexer, constOnly bool) Literal {
+ loc := l.Location()
+ switch l.Peek() {
+ case '$':
+ if constOnly {
+ l.SyntaxError("variable not allowed")
+ panic("unreachable")
+ }
+ l.ConsumeToken('$')
+ return &Variable{l.ConsumeIdent(), loc}
+
+ case scanner.Int, scanner.Float, scanner.String, scanner.Ident:
+ lit := l.ConsumeLiteral()
+ if lit.Type == scanner.Ident && lit.Text == "null" {
+ return &NullLit{loc}
+ }
+ lit.Loc = loc
+ return lit
+ case '-':
+ l.ConsumeToken('-')
+ lit := l.ConsumeLiteral()
+ lit.Text = "-" + lit.Text
+ lit.Loc = loc
+ return lit
+ case '[':
+ l.ConsumeToken('[')
+ var list []Literal
+ for l.Peek() != ']' {
+ list = append(list, ParseLiteral(l, constOnly))
+ }
+ l.ConsumeToken(']')
+ return &ListLit{list, loc}
+
+ case '{':
+ l.ConsumeToken('{')
+ var fields []*ObjectLitField
+ for l.Peek() != '}' {
+ name := l.ConsumeIdentWithLoc()
+ l.ConsumeToken(':')
+ value := ParseLiteral(l, constOnly)
+ fields = append(fields, &ObjectLitField{name, value})
+ }
+ l.ConsumeToken('}')
+ return &ObjectLit{fields, loc}
+
+ default:
+ l.SyntaxError("invalid value")
+ panic("unreachable")
+ }
+}
diff --git a/vendor/github.com/vektah/gqlgen/neelance/common/types.go b/vendor/github.com/vektah/gqlgen/neelance/common/types.go
new file mode 100644
index 00000000..0bbf24ef
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/neelance/common/types.go
@@ -0,0 +1,80 @@
+package common
+
+import (
+ "github.com/vektah/gqlgen/neelance/errors"
+)
+
+type Type interface {
+ Kind() string
+ String() string
+}
+
+type List struct {
+ OfType Type
+}
+
+type NonNull struct {
+ OfType Type
+}
+
+type TypeName struct {
+ Ident
+}
+
+func (*List) Kind() string { return "LIST" }
+func (*NonNull) Kind() string { return "NON_NULL" }
+func (*TypeName) Kind() string { panic("TypeName needs to be resolved to actual type") }
+
+func (t *List) String() string { return "[" + t.OfType.String() + "]" }
+func (t *NonNull) String() string { return t.OfType.String() + "!" }
+func (*TypeName) String() string { panic("TypeName needs to be resolved to actual type") }
+
+func ParseType(l *Lexer) Type {
+ t := parseNullType(l)
+ if l.Peek() == '!' {
+ l.ConsumeToken('!')
+ return &NonNull{OfType: t}
+ }
+ return t
+}
+
+func parseNullType(l *Lexer) Type {
+ if l.Peek() == '[' {
+ l.ConsumeToken('[')
+ ofType := ParseType(l)
+ l.ConsumeToken(']')
+ return &List{OfType: ofType}
+ }
+
+ return &TypeName{Ident: l.ConsumeIdentWithLoc()}
+}
+
+type Resolver func(name string) Type
+
+func ResolveType(t Type, resolver Resolver) (Type, *errors.QueryError) {
+ switch t := t.(type) {
+ case *List:
+ ofType, err := ResolveType(t.OfType, resolver)
+ if err != nil {
+ return nil, err
+ }
+ return &List{OfType: ofType}, nil
+ case *NonNull:
+ ofType, err := ResolveType(t.OfType, resolver)
+ if err != nil {
+ return nil, err
+ }
+ return &NonNull{OfType: ofType}, nil
+ case *TypeName:
+ refT := resolver(t.Name)
+ if refT == nil {
+ err := errors.Errorf("Unknown type %q.", t.Name)
+ err.Rule = "KnownTypeNames"
+ err.Locations = []errors.Location{t.Loc}
+ return nil, err
+ }
+ return refT, nil
+ default:
+ return t, nil
+ }
+}
diff --git a/vendor/github.com/vektah/gqlgen/neelance/common/values.go b/vendor/github.com/vektah/gqlgen/neelance/common/values.go
new file mode 100644
index 00000000..09338da8
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/neelance/common/values.go
@@ -0,0 +1,77 @@
+package common
+
+import (
+ "github.com/vektah/gqlgen/neelance/errors"
+)
+
+type InputValue struct {
+ Name Ident
+ Type Type
+ Default Literal
+ Desc string
+ Loc errors.Location
+ TypeLoc errors.Location
+}
+
+type InputValueList []*InputValue
+
+func (l InputValueList) Get(name string) *InputValue {
+ for _, v := range l {
+ if v.Name.Name == name {
+ return v
+ }
+ }
+ return nil
+}
+
+func ParseInputValue(l *Lexer) *InputValue {
+ p := &InputValue{}
+ p.Loc = l.Location()
+ p.Desc = l.DescComment()
+ p.Name = l.ConsumeIdentWithLoc()
+ l.ConsumeToken(':')
+ p.TypeLoc = l.Location()
+ p.Type = ParseType(l)
+ if l.Peek() == '=' {
+ l.ConsumeToken('=')
+ p.Default = ParseLiteral(l, true)
+ }
+ return p
+}
+
+type Argument struct {
+ Name Ident
+ Value Literal
+}
+
+type ArgumentList []Argument
+
+func (l ArgumentList) Get(name string) (Literal, bool) {
+ for _, arg := range l {
+ if arg.Name.Name == name {
+ return arg.Value, true
+ }
+ }
+ return nil, false
+}
+
+func (l ArgumentList) MustGet(name string) Literal {
+ value, ok := l.Get(name)
+ if !ok {
+ panic("argument not found")
+ }
+ return value
+}
+
+func ParseArguments(l *Lexer) ArgumentList {
+ var args ArgumentList
+ l.ConsumeToken('(')
+ for l.Peek() != ')' {
+ name := l.ConsumeIdentWithLoc()
+ l.ConsumeToken(':')
+ value := ParseLiteral(l, false)
+ args = append(args, Argument{Name: name, Value: value})
+ }
+ l.ConsumeToken(')')
+ return args
+}
diff --git a/vendor/github.com/vektah/gqlgen/neelance/errors/errors.go b/vendor/github.com/vektah/gqlgen/neelance/errors/errors.go
new file mode 100644
index 00000000..fdfa6202
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/neelance/errors/errors.go
@@ -0,0 +1,41 @@
+package errors
+
+import (
+ "fmt"
+)
+
+type QueryError struct {
+ Message string `json:"message"`
+ Locations []Location `json:"locations,omitempty"`
+ Path []interface{} `json:"path,omitempty"`
+ Rule string `json:"-"`
+ ResolverError error `json:"-"`
+}
+
+type Location struct {
+ Line int `json:"line"`
+ Column int `json:"column"`
+}
+
+func (a Location) Before(b Location) bool {
+ return a.Line < b.Line || (a.Line == b.Line && a.Column < b.Column)
+}
+
+func Errorf(format string, a ...interface{}) *QueryError {
+ return &QueryError{
+ Message: fmt.Sprintf(format, a...),
+ }
+}
+
+func (err *QueryError) Error() string {
+ if err == nil {
+ return "<nil>"
+ }
+ str := fmt.Sprintf("graphql: %s", err.Message)
+ for _, loc := range err.Locations {
+ str += fmt.Sprintf(" (line %d, column %d)", loc.Line, loc.Column)
+ }
+ return str
+}
+
+var _ error = &QueryError{}
diff --git a/vendor/github.com/vektah/gqlgen/neelance/introspection/introspection.go b/vendor/github.com/vektah/gqlgen/neelance/introspection/introspection.go
new file mode 100644
index 00000000..5e354c9a
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/neelance/introspection/introspection.go
@@ -0,0 +1,313 @@
+package introspection
+
+import (
+ "sort"
+
+ "github.com/vektah/gqlgen/neelance/common"
+ "github.com/vektah/gqlgen/neelance/schema"
+)
+
+type Schema struct {
+ schema *schema.Schema
+}
+
+// WrapSchema is only used internally.
+func WrapSchema(schema *schema.Schema) *Schema {
+ return &Schema{schema}
+}
+
+func (r *Schema) Types() []Type {
+ var names []string
+ for name := range r.schema.Types {
+ names = append(names, name)
+ }
+ sort.Strings(names)
+
+ l := make([]Type, len(names))
+ for i, name := range names {
+ l[i] = Type{r.schema.Types[name]}
+ }
+ return l
+}
+
+func (r *Schema) Directives() []Directive {
+ var names []string
+ for name := range r.schema.Directives {
+ names = append(names, name)
+ }
+ sort.Strings(names)
+
+ l := make([]Directive, len(names))
+ for i, name := range names {
+ l[i] = Directive{r.schema.Directives[name]}
+ }
+ return l
+}
+
+func (r *Schema) QueryType() Type {
+ t, ok := r.schema.EntryPoints["query"]
+ if !ok {
+ return Type{}
+ }
+ return Type{t}
+}
+
+func (r *Schema) MutationType() *Type {
+ t, ok := r.schema.EntryPoints["mutation"]
+ if !ok {
+ return nil
+ }
+ return &Type{t}
+}
+
+func (r *Schema) SubscriptionType() *Type {
+ t, ok := r.schema.EntryPoints["subscription"]
+ if !ok {
+ return nil
+ }
+ return &Type{t}
+}
+
+type Type struct {
+ typ common.Type
+}
+
+// WrapType is only used internally.
+func WrapType(typ common.Type) *Type {
+ return &Type{typ}
+}
+
+func (r *Type) Kind() string {
+ return r.typ.Kind()
+}
+
+func (r *Type) Name() *string {
+ if named, ok := r.typ.(schema.NamedType); ok {
+ name := named.TypeName()
+ return &name
+ }
+ return nil
+}
+
+func (r *Type) Description() *string {
+ if named, ok := r.typ.(schema.NamedType); ok {
+ desc := named.Description()
+ if desc == "" {
+ return nil
+ }
+ return &desc
+ }
+ return nil
+}
+
+func (r *Type) Fields(includeDeprecated bool) []Field {
+ var fields schema.FieldList
+ switch t := r.typ.(type) {
+ case *schema.Object:
+ fields = t.Fields
+ case *schema.Interface:
+ fields = t.Fields
+ default:
+ return nil
+ }
+
+ var l []Field
+ for _, f := range fields {
+ if d := f.Directives.Get("deprecated"); d == nil || includeDeprecated {
+ l = append(l, Field{f})
+ }
+ }
+ return l
+}
+
+func (r *Type) Interfaces() []Type {
+ t, ok := r.typ.(*schema.Object)
+ if !ok {
+ return nil
+ }
+
+ l := make([]Type, len(t.Interfaces))
+ for i, intf := range t.Interfaces {
+ l[i] = Type{intf}
+ }
+ return l
+}
+
+func (r *Type) PossibleTypes() []Type {
+ var possibleTypes []*schema.Object
+ switch t := r.typ.(type) {
+ case *schema.Interface:
+ possibleTypes = t.PossibleTypes
+ case *schema.Union:
+ possibleTypes = t.PossibleTypes
+ default:
+ return nil
+ }
+
+ l := make([]Type, len(possibleTypes))
+ for i, intf := range possibleTypes {
+ l[i] = Type{intf}
+ }
+ return l
+}
+
+func (r *Type) EnumValues(includeDeprecated bool) []EnumValue {
+ t, ok := r.typ.(*schema.Enum)
+ if !ok {
+ return nil
+ }
+
+ var l []EnumValue
+ for _, v := range t.Values {
+ if d := v.Directives.Get("deprecated"); d == nil || includeDeprecated {
+ l = append(l, EnumValue{v})
+ }
+ }
+ return l
+}
+
+func (r *Type) InputFields() []InputValue {
+ t, ok := r.typ.(*schema.InputObject)
+ if !ok {
+ return nil
+ }
+
+ l := make([]InputValue, len(t.Values))
+ for i, v := range t.Values {
+ l[i] = InputValue{v}
+ }
+ return l
+}
+
+func (r *Type) OfType() *Type {
+ switch t := r.typ.(type) {
+ case *common.List:
+ return &Type{t.OfType}
+ case *common.NonNull:
+ return &Type{t.OfType}
+ default:
+ return nil
+ }
+}
+
+type Field struct {
+ field *schema.Field
+}
+
+func (r *Field) Name() string {
+ return r.field.Name
+}
+
+func (r *Field) Description() *string {
+ if r.field.Desc == "" {
+ return nil
+ }
+ return &r.field.Desc
+}
+
+func (r *Field) Args() []InputValue {
+ l := make([]InputValue, len(r.field.Args))
+ for i, v := range r.field.Args {
+ l[i] = InputValue{v}
+ }
+ return l
+}
+
+func (r *Field) Type() Type {
+ return Type{r.field.Type}
+}
+
+func (r *Field) IsDeprecated() bool {
+ return r.field.Directives.Get("deprecated") != nil
+}
+
+func (r *Field) DeprecationReason() *string {
+ d := r.field.Directives.Get("deprecated")
+ if d == nil {
+ return nil
+ }
+ reason := d.Args.MustGet("reason").Value(nil).(string)
+ return &reason
+}
+
+type InputValue struct {
+ value *common.InputValue
+}
+
+func (r *InputValue) Name() string {
+ return r.value.Name.Name
+}
+
+func (r *InputValue) Description() *string {
+ if r.value.Desc == "" {
+ return nil
+ }
+ return &r.value.Desc
+}
+
+func (r *InputValue) Type() Type {
+ return Type{r.value.Type}
+}
+
+func (r *InputValue) DefaultValue() *string {
+ if r.value.Default == nil {
+ return nil
+ }
+ s := r.value.Default.String()
+ return &s
+}
+
+type EnumValue struct {
+ value *schema.EnumValue
+}
+
+func (r *EnumValue) Name() string {
+ return r.value.Name
+}
+
+func (r *EnumValue) Description() *string {
+ if r.value.Desc == "" {
+ return nil
+ }
+ return &r.value.Desc
+}
+
+func (r *EnumValue) IsDeprecated() bool {
+ return r.value.Directives.Get("deprecated") != nil
+}
+
+func (r *EnumValue) DeprecationReason() *string {
+ d := r.value.Directives.Get("deprecated")
+ if d == nil {
+ return nil
+ }
+ reason := d.Args.MustGet("reason").Value(nil).(string)
+ return &reason
+}
+
+type Directive struct {
+ directive *schema.DirectiveDecl
+}
+
+func (r *Directive) Name() string {
+ return r.directive.Name
+}
+
+func (r *Directive) Description() *string {
+ if r.directive.Desc == "" {
+ return nil
+ }
+ return &r.directive.Desc
+}
+
+func (r *Directive) Locations() []string {
+ return r.directive.Locs
+}
+
+func (r *Directive) Args() []InputValue {
+ l := make([]InputValue, len(r.directive.Args))
+ for i, v := range r.directive.Args {
+ l[i] = InputValue{v}
+ }
+ return l
+}
diff --git a/vendor/github.com/vektah/gqlgen/neelance/introspection/query.go b/vendor/github.com/vektah/gqlgen/neelance/introspection/query.go
new file mode 100644
index 00000000..b1e4fbc6
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/neelance/introspection/query.go
@@ -0,0 +1,104 @@
+package introspection
+
+// Query is the query generated by graphiql to determine type information
+const Query = `
+query IntrospectionQuery {
+ __schema {
+ queryType {
+ name
+ }
+ mutationType {
+ name
+ }
+ subscriptionType {
+ name
+ }
+ types {
+ ...FullType
+ }
+ directives {
+ name
+ description
+ locations
+ args {
+ ...InputValue
+ }
+ }
+ }
+}
+
+fragment FullType on __Type {
+ kind
+ name
+ description
+ fields(includeDeprecated: true) {
+ name
+ description
+ args {
+ ...InputValue
+ }
+ type {
+ ...TypeRef
+ }
+ isDeprecated
+ deprecationReason
+ }
+ inputFields {
+ ...InputValue
+ }
+ interfaces {
+ ...TypeRef
+ }
+ enumValues(includeDeprecated: true) {
+ name
+ description
+ isDeprecated
+ deprecationReason
+ }
+ possibleTypes {
+ ...TypeRef
+ }
+}
+
+fragment InputValue on __InputValue {
+ name
+ description
+ type {
+ ...TypeRef
+ }
+ defaultValue
+}
+
+fragment TypeRef on __Type {
+ kind
+ name
+ ofType {
+ kind
+ name
+ ofType {
+ kind
+ name
+ ofType {
+ kind
+ name
+ ofType {
+ kind
+ name
+ ofType {
+ kind
+ name
+ ofType {
+ kind
+ name
+ ofType {
+ kind
+ name
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+`
diff --git a/vendor/github.com/vektah/gqlgen/neelance/query/query.go b/vendor/github.com/vektah/gqlgen/neelance/query/query.go
new file mode 100644
index 00000000..b6f35354
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/neelance/query/query.go
@@ -0,0 +1,261 @@
+package query
+
+import (
+ "fmt"
+ "strings"
+ "text/scanner"
+
+ "github.com/vektah/gqlgen/neelance/common"
+ "github.com/vektah/gqlgen/neelance/errors"
+)
+
+type Document struct {
+ Operations OperationList
+ Fragments FragmentList
+}
+
+type OperationList []*Operation
+
+func (l OperationList) Get(name string) *Operation {
+ for _, f := range l {
+ if f.Name.Name == name {
+ return f
+ }
+ }
+ return nil
+}
+
+type FragmentList []*FragmentDecl
+
+func (l FragmentList) Get(name string) *FragmentDecl {
+ for _, f := range l {
+ if f.Name.Name == name {
+ return f
+ }
+ }
+ return nil
+}
+
+type Operation struct {
+ Type OperationType
+ Name common.Ident
+ Vars common.InputValueList
+ Selections []Selection
+ Directives common.DirectiveList
+ Loc errors.Location
+}
+
+type OperationType string
+
+const (
+ Query OperationType = "QUERY"
+ Mutation = "MUTATION"
+ Subscription = "SUBSCRIPTION"
+)
+
+type Fragment struct {
+ On common.TypeName
+ Selections []Selection
+}
+
+type FragmentDecl struct {
+ Fragment
+ Name common.Ident
+ Directives common.DirectiveList
+ Loc errors.Location
+}
+
+type Selection interface {
+ isSelection()
+}
+
+type Field struct {
+ Alias common.Ident
+ Name common.Ident
+ Arguments common.ArgumentList
+ Directives common.DirectiveList
+ Selections []Selection
+ SelectionSetLoc errors.Location
+}
+
+type InlineFragment struct {
+ Fragment
+ Directives common.DirectiveList
+ Loc errors.Location
+}
+
+type FragmentSpread struct {
+ Name common.Ident
+ Directives common.DirectiveList
+ Loc errors.Location
+}
+
+func (Field) isSelection() {}
+func (InlineFragment) isSelection() {}
+func (FragmentSpread) isSelection() {}
+
+func Parse(queryString string) (*Document, *errors.QueryError) {
+ sc := &scanner.Scanner{
+ Mode: scanner.ScanIdents | scanner.ScanInts | scanner.ScanFloats | scanner.ScanStrings,
+ }
+ sc.Init(strings.NewReader(queryString))
+
+ l := common.New(sc)
+ var doc *Document
+ err := l.CatchSyntaxError(func() {
+ doc = parseDocument(l)
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return doc, nil
+}
+
+func parseDocument(l *common.Lexer) *Document {
+ d := &Document{}
+ for l.Peek() != scanner.EOF {
+ if l.Peek() == '{' {
+ op := &Operation{Type: Query, Loc: l.Location()}
+ op.Selections = parseSelectionSet(l)
+ d.Operations = append(d.Operations, op)
+ continue
+ }
+
+ loc := l.Location()
+ switch x := l.ConsumeIdent(); x {
+ case "query":
+ op := parseOperation(l, Query)
+ op.Loc = loc
+ d.Operations = append(d.Operations, op)
+
+ case "mutation":
+ d.Operations = append(d.Operations, parseOperation(l, Mutation))
+
+ case "subscription":
+ d.Operations = append(d.Operations, parseOperation(l, Subscription))
+
+ case "fragment":
+ frag := parseFragment(l)
+ frag.Loc = loc
+ d.Fragments = append(d.Fragments, frag)
+
+ default:
+ l.SyntaxError(fmt.Sprintf(`unexpected %q, expecting "fragment"`, x))
+ }
+ }
+ return d
+}
+
+func parseOperation(l *common.Lexer, opType OperationType) *Operation {
+ op := &Operation{Type: opType}
+ op.Name.Loc = l.Location()
+ if l.Peek() == scanner.Ident {
+ op.Name = l.ConsumeIdentWithLoc()
+ }
+ op.Directives = common.ParseDirectives(l)
+ if l.Peek() == '(' {
+ l.ConsumeToken('(')
+ for l.Peek() != ')' {
+ loc := l.Location()
+ l.ConsumeToken('$')
+ iv := common.ParseInputValue(l)
+ iv.Loc = loc
+ op.Vars = append(op.Vars, iv)
+ }
+ l.ConsumeToken(')')
+ }
+ op.Selections = parseSelectionSet(l)
+ return op
+}
+
+func parseFragment(l *common.Lexer) *FragmentDecl {
+ f := &FragmentDecl{}
+ f.Name = l.ConsumeIdentWithLoc()
+ l.ConsumeKeyword("on")
+ f.On = common.TypeName{Ident: l.ConsumeIdentWithLoc()}
+ f.Directives = common.ParseDirectives(l)
+ f.Selections = parseSelectionSet(l)
+ return f
+}
+
+func parseSelectionSet(l *common.Lexer) []Selection {
+ var sels []Selection
+ l.ConsumeToken('{')
+ for l.Peek() != '}' {
+ sels = append(sels, parseSelection(l))
+ }
+ l.ConsumeToken('}')
+ return sels
+}
+
+func parseSelection(l *common.Lexer) Selection {
+ if l.Peek() == '.' {
+ return parseSpread(l)
+ }
+ return parseField(l)
+}
+
+func parseField(l *common.Lexer) *Field {
+ f := &Field{}
+ f.Alias = l.ConsumeIdentWithLoc()
+ f.Name = f.Alias
+ if l.Peek() == ':' {
+ l.ConsumeToken(':')
+ f.Name = l.ConsumeIdentWithLoc()
+ }
+ if l.Peek() == '(' {
+ f.Arguments = common.ParseArguments(l)
+ }
+ f.Directives = common.ParseDirectives(l)
+ if l.Peek() == '{' {
+ f.SelectionSetLoc = l.Location()
+ f.Selections = parseSelectionSet(l)
+ }
+ return f
+}
+
+func parseSpread(l *common.Lexer) Selection {
+ loc := l.Location()
+ l.ConsumeToken('.')
+ l.ConsumeToken('.')
+ l.ConsumeToken('.')
+
+ f := &InlineFragment{Loc: loc}
+ if l.Peek() == scanner.Ident {
+ ident := l.ConsumeIdentWithLoc()
+ if ident.Name != "on" {
+ fs := &FragmentSpread{
+ Name: ident,
+ Loc: loc,
+ }
+ fs.Directives = common.ParseDirectives(l)
+ return fs
+ }
+ f.On = common.TypeName{Ident: l.ConsumeIdentWithLoc()}
+ }
+ f.Directives = common.ParseDirectives(l)
+ f.Selections = parseSelectionSet(l)
+ return f
+}
+
+func (d *Document) GetOperation(operationName string) (*Operation, error) {
+ if len(d.Operations) == 0 {
+ return nil, fmt.Errorf("no operations in query document")
+ }
+
+ if operationName == "" {
+ if len(d.Operations) > 1 {
+ return nil, fmt.Errorf("more than one operation in query document and no operation name given")
+ }
+ for _, op := range d.Operations {
+ return op, nil // return the one and only operation
+ }
+ }
+
+ op := d.Operations.Get(operationName)
+ if op == nil {
+ return nil, fmt.Errorf("no operation with name %q", operationName)
+ }
+ return op, nil
+}
diff --git a/vendor/github.com/vektah/gqlgen/neelance/schema/meta.go b/vendor/github.com/vektah/gqlgen/neelance/schema/meta.go
new file mode 100644
index 00000000..efdcaa2c
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/neelance/schema/meta.go
@@ -0,0 +1,193 @@
+package schema
+
+var Meta *Schema
+
+func init() {
+ Meta = &Schema{} // bootstrap
+ Meta = New()
+ if err := Meta.Parse(metaSrc); err != nil {
+ panic(err)
+ }
+}
+
+var metaSrc = `
+ # The ` + "`" + `Int` + "`" + ` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.
+ scalar Int
+
+ # The ` + "`" + `Float` + "`" + ` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).
+ scalar Float
+
+ # 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.
+ scalar String
+
+ # The ` + "`" + `Boolean` + "`" + ` scalar type represents ` + "`" + `true` + "`" + ` or ` + "`" + `false` + "`" + `.
+ scalar Boolean
+
+ # 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.
+ scalar ID
+
+ # The ` + "`" + `Map` + "`" + ` scalar type is a simple json object
+ scalar Map
+
+ # Directs the executor to include this field or fragment only when the ` + "`" + `if` + "`" + ` argument is true.
+ directive @include(
+ # Included when true.
+ if: Boolean!
+ ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
+
+ # Directs the executor to skip this field or fragment when the ` + "`" + `if` + "`" + ` argument is true.
+ directive @skip(
+ # Skipped when true.
+ if: Boolean!
+ ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
+
+ # Marks an element of a GraphQL schema as no longer supported.
+ directive @deprecated(
+ # 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/).
+ reason: String = "No longer supported"
+ ) on FIELD_DEFINITION | ENUM_VALUE
+
+ # A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.
+ #
+ # In 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.
+ type __Directive {
+ name: String!
+ description: String
+ locations: [__DirectiveLocation!]!
+ args: [__InputValue!]!
+ }
+
+ # A Directive can be adjacent to many parts of the GraphQL language, a
+ # __DirectiveLocation describes one such possible adjacencies.
+ enum __DirectiveLocation {
+ # Location adjacent to a query operation.
+ QUERY
+ # Location adjacent to a mutation operation.
+ MUTATION
+ # Location adjacent to a subscription operation.
+ SUBSCRIPTION
+ # Location adjacent to a field.
+ FIELD
+ # Location adjacent to a fragment definition.
+ FRAGMENT_DEFINITION
+ # Location adjacent to a fragment spread.
+ FRAGMENT_SPREAD
+ # Location adjacent to an inline fragment.
+ INLINE_FRAGMENT
+ # Location adjacent to a schema definition.
+ SCHEMA
+ # Location adjacent to a scalar definition.
+ SCALAR
+ # Location adjacent to an object type definition.
+ OBJECT
+ # Location adjacent to a field definition.
+ FIELD_DEFINITION
+ # Location adjacent to an argument definition.
+ ARGUMENT_DEFINITION
+ # Location adjacent to an interface definition.
+ INTERFACE
+ # Location adjacent to a union definition.
+ UNION
+ # Location adjacent to an enum definition.
+ ENUM
+ # Location adjacent to an enum value definition.
+ ENUM_VALUE
+ # Location adjacent to an input object type definition.
+ INPUT_OBJECT
+ # Location adjacent to an input object field definition.
+ INPUT_FIELD_DEFINITION
+ }
+
+ # 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.
+ type __EnumValue {
+ name: String!
+ description: String
+ isDeprecated: Boolean!
+ deprecationReason: String
+ }
+
+ # 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.
+ type __Field {
+ name: String!
+ description: String
+ args: [__InputValue!]!
+ type: __Type!
+ isDeprecated: Boolean!
+ deprecationReason: String
+ }
+
+ # 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.
+ type __InputValue {
+ name: String!
+ description: String
+ type: __Type!
+ # A GraphQL-formatted string representing the default value for this input value.
+ defaultValue: String
+ }
+
+ # 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.
+ type __Schema {
+ # A list of all types supported by this server.
+ types: [__Type!]!
+ # The type that query operations will be rooted at.
+ queryType: __Type!
+ # If this server supports mutation, the type that mutation operations will be rooted at.
+ mutationType: __Type
+ # If this server support subscription, the type that subscription operations will be rooted at.
+ subscriptionType: __Type
+ # A list of all directives supported by this server.
+ directives: [__Directive!]!
+ }
+
+ # The fundamental unit of any GraphQL Schema is the type. There are many kinds of
+ # types in GraphQL as represented by the ` + "`" + `__TypeKind` + "`" + ` enum.
+ #
+ # Depending 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.
+ type __Type {
+ kind: __TypeKind!
+ name: String
+ description: String
+ fields(includeDeprecated: Boolean = false): [__Field!]
+ interfaces: [__Type!]
+ possibleTypes: [__Type!]
+ enumValues(includeDeprecated: Boolean = false): [__EnumValue!]
+ inputFields: [__InputValue!]
+ ofType: __Type
+ }
+
+ # An enum describing what kind of type a given ` + "`" + `__Type` + "`" + ` is.
+ enum __TypeKind {
+ # Indicates this type is a scalar.
+ SCALAR
+ # Indicates this type is an object. ` + "`" + `fields` + "`" + ` and ` + "`" + `interfaces` + "`" + ` are valid fields.
+ OBJECT
+ # Indicates this type is an interface. ` + "`" + `fields` + "`" + ` and ` + "`" + `possibleTypes` + "`" + ` are valid fields.
+ INTERFACE
+ # Indicates this type is a union. ` + "`" + `possibleTypes` + "`" + ` is a valid field.
+ UNION
+ # Indicates this type is an enum. ` + "`" + `enumValues` + "`" + ` is a valid field.
+ ENUM
+ # Indicates this type is an input object. ` + "`" + `inputFields` + "`" + ` is a valid field.
+ INPUT_OBJECT
+ # Indicates this type is a list. ` + "`" + `ofType` + "`" + ` is a valid field.
+ LIST
+ # Indicates this type is a non-null. ` + "`" + `ofType` + "`" + ` is a valid field.
+ NON_NULL
+ }
+`
diff --git a/vendor/github.com/vektah/gqlgen/neelance/schema/schema.go b/vendor/github.com/vektah/gqlgen/neelance/schema/schema.go
new file mode 100644
index 00000000..0b1317a5
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/neelance/schema/schema.go
@@ -0,0 +1,489 @@
+package schema
+
+import (
+ "fmt"
+ "strings"
+ "text/scanner"
+
+ "github.com/vektah/gqlgen/neelance/common"
+ "github.com/vektah/gqlgen/neelance/errors"
+)
+
+type Schema struct {
+ EntryPoints map[string]NamedType
+ Types map[string]NamedType
+ Directives map[string]*DirectiveDecl
+
+ entryPointNames map[string]string
+ objects []*Object
+ unions []*Union
+ enums []*Enum
+}
+
+var defaultEntrypoints = map[string]string{
+ "query": "Query",
+ "mutation": "Mutation",
+ "subscription": "Subscription",
+}
+
+func (s *Schema) Resolve(name string) common.Type {
+ return s.Types[name]
+}
+
+type NamedType interface {
+ common.Type
+ TypeName() string
+ Description() string
+}
+
+type Scalar struct {
+ Name string
+ Desc string
+}
+
+type Object struct {
+ Name string
+ Interfaces []*Interface
+ Fields FieldList
+ Desc string
+
+ interfaceNames []string
+}
+
+type Interface struct {
+ Name string
+ PossibleTypes []*Object
+ Fields FieldList
+ Desc string
+}
+
+type Union struct {
+ Name string
+ PossibleTypes []*Object
+ Desc string
+
+ typeNames []string
+}
+
+type Enum struct {
+ Name string
+ Values []*EnumValue
+ Desc string
+}
+
+type EnumValue struct {
+ Name string
+ Directives common.DirectiveList
+ Desc string
+}
+
+type InputObject struct {
+ Name string
+ Desc string
+ Values common.InputValueList
+}
+
+type FieldList []*Field
+
+func (l FieldList) Get(name string) *Field {
+ for _, f := range l {
+ if f.Name == name {
+ return f
+ }
+ }
+ return nil
+}
+
+func (l FieldList) Names() []string {
+ names := make([]string, len(l))
+ for i, f := range l {
+ names[i] = f.Name
+ }
+ return names
+}
+
+type DirectiveDecl struct {
+ Name string
+ Desc string
+ Locs []string
+ Args common.InputValueList
+}
+
+func (*Scalar) Kind() string { return "SCALAR" }
+func (*Object) Kind() string { return "OBJECT" }
+func (*Interface) Kind() string { return "INTERFACE" }
+func (*Union) Kind() string { return "UNION" }
+func (*Enum) Kind() string { return "ENUM" }
+func (*InputObject) Kind() string { return "INPUT_OBJECT" }
+
+func (t *Scalar) String() string { return t.Name }
+func (t *Object) String() string { return t.Name }
+func (t *Interface) String() string { return t.Name }
+func (t *Union) String() string { return t.Name }
+func (t *Enum) String() string { return t.Name }
+func (t *InputObject) String() string { return t.Name }
+
+func (t *Scalar) TypeName() string { return t.Name }
+func (t *Object) TypeName() string { return t.Name }
+func (t *Interface) TypeName() string { return t.Name }
+func (t *Union) TypeName() string { return t.Name }
+func (t *Enum) TypeName() string { return t.Name }
+func (t *InputObject) TypeName() string { return t.Name }
+
+func (t *Scalar) Description() string { return t.Desc }
+func (t *Object) Description() string { return t.Desc }
+func (t *Interface) Description() string { return t.Desc }
+func (t *Union) Description() string { return t.Desc }
+func (t *Enum) Description() string { return t.Desc }
+func (t *InputObject) Description() string { return t.Desc }
+
+type Field struct {
+ Name string
+ Args common.InputValueList
+ Type common.Type
+ Directives common.DirectiveList
+ Desc string
+}
+
+func MustParse(str string) *Schema {
+ s := New()
+ err := s.Parse(str)
+ if err != nil {
+ panic(err)
+ }
+ return s
+}
+
+func New() *Schema {
+ s := &Schema{
+ entryPointNames: make(map[string]string),
+ Types: make(map[string]NamedType),
+ Directives: make(map[string]*DirectiveDecl),
+ }
+ for n, t := range Meta.Types {
+ s.Types[n] = t
+ }
+ for n, d := range Meta.Directives {
+ s.Directives[n] = d
+ }
+ return s
+}
+
+func (s *Schema) Parse(schemaString string) error {
+ sc := &scanner.Scanner{
+ Mode: scanner.ScanIdents | scanner.ScanInts | scanner.ScanFloats | scanner.ScanStrings,
+ }
+ sc.Init(strings.NewReader(schemaString))
+
+ l := common.New(sc)
+ err := l.CatchSyntaxError(func() {
+ parseSchema(s, l)
+ })
+ if err != nil {
+ return err
+ }
+
+ for _, t := range s.Types {
+ if err := resolveNamedType(s, t); err != nil {
+ return err
+ }
+ }
+ for _, d := range s.Directives {
+ for _, arg := range d.Args {
+ t, err := common.ResolveType(arg.Type, s.Resolve)
+ if err != nil {
+ return err
+ }
+ arg.Type = t
+ }
+ }
+
+ s.EntryPoints = make(map[string]NamedType)
+ for key, name := range s.entryPointNames {
+ t, ok := s.Types[name]
+ if !ok {
+ if !ok {
+ return errors.Errorf("type %q not found", name)
+ }
+ }
+ s.EntryPoints[key] = t
+ }
+
+ for entrypointName, typeName := range defaultEntrypoints {
+ if _, ok := s.EntryPoints[entrypointName]; ok {
+ continue
+ }
+
+ if _, ok := s.Types[typeName]; !ok {
+ continue
+ }
+
+ s.EntryPoints[entrypointName] = s.Types[typeName]
+ }
+
+ for _, obj := range s.objects {
+ obj.Interfaces = make([]*Interface, len(obj.interfaceNames))
+ for i, intfName := range obj.interfaceNames {
+ t, ok := s.Types[intfName]
+ if !ok {
+ return errors.Errorf("interface %q not found", intfName)
+ }
+ intf, ok := t.(*Interface)
+ if !ok {
+ return errors.Errorf("type %q is not an interface", intfName)
+ }
+ obj.Interfaces[i] = intf
+ intf.PossibleTypes = append(intf.PossibleTypes, obj)
+ }
+ }
+
+ for _, union := range s.unions {
+ union.PossibleTypes = make([]*Object, len(union.typeNames))
+ for i, name := range union.typeNames {
+ t, ok := s.Types[name]
+ if !ok {
+ return errors.Errorf("object type %q not found", name)
+ }
+ obj, ok := t.(*Object)
+ if !ok {
+ return errors.Errorf("type %q is not an object", name)
+ }
+ union.PossibleTypes[i] = obj
+ }
+ }
+
+ for _, enum := range s.enums {
+ for _, value := range enum.Values {
+ if err := resolveDirectives(s, value.Directives); err != nil {
+ return err
+ }
+ }
+ }
+
+ return nil
+}
+
+func resolveNamedType(s *Schema, t NamedType) error {
+ switch t := t.(type) {
+ case *Object:
+ for _, f := range t.Fields {
+ if err := resolveField(s, f); err != nil {
+ return err
+ }
+ }
+ case *Interface:
+ for _, f := range t.Fields {
+ if err := resolveField(s, f); err != nil {
+ return err
+ }
+ }
+ case *InputObject:
+ if err := resolveInputObject(s, t.Values); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func resolveField(s *Schema, f *Field) error {
+ t, err := common.ResolveType(f.Type, s.Resolve)
+ if err != nil {
+ return err
+ }
+ f.Type = t
+ if err := resolveDirectives(s, f.Directives); err != nil {
+ return err
+ }
+ return resolveInputObject(s, f.Args)
+}
+
+func resolveDirectives(s *Schema, directives common.DirectiveList) error {
+ for _, d := range directives {
+ dirName := d.Name.Name
+ dd, ok := s.Directives[dirName]
+ if !ok {
+ return errors.Errorf("directive %q not found", dirName)
+ }
+ for _, arg := range d.Args {
+ if dd.Args.Get(arg.Name.Name) == nil {
+ return errors.Errorf("invalid argument %q for directive %q", arg.Name.Name, dirName)
+ }
+ }
+ for _, arg := range dd.Args {
+ if _, ok := d.Args.Get(arg.Name.Name); !ok {
+ d.Args = append(d.Args, common.Argument{Name: arg.Name, Value: arg.Default})
+ }
+ }
+ }
+ return nil
+}
+
+func resolveInputObject(s *Schema, values common.InputValueList) error {
+ for _, v := range values {
+ t, err := common.ResolveType(v.Type, s.Resolve)
+ if err != nil {
+ return err
+ }
+ v.Type = t
+ }
+ return nil
+}
+
+func parseSchema(s *Schema, l *common.Lexer) {
+ for l.Peek() != scanner.EOF {
+ desc := l.DescComment()
+ switch x := l.ConsumeIdent(); x {
+ case "schema":
+ l.ConsumeToken('{')
+ for l.Peek() != '}' {
+ name := l.ConsumeIdent()
+ l.ConsumeToken(':')
+ typ := l.ConsumeIdent()
+ s.entryPointNames[name] = typ
+ }
+ l.ConsumeToken('}')
+ case "type":
+ obj := parseObjectDecl(l)
+ obj.Desc = desc
+ s.Types[obj.Name] = obj
+ s.objects = append(s.objects, obj)
+ case "interface":
+ intf := parseInterfaceDecl(l)
+ intf.Desc = desc
+ s.Types[intf.Name] = intf
+ case "union":
+ union := parseUnionDecl(l)
+ union.Desc = desc
+ s.Types[union.Name] = union
+ s.unions = append(s.unions, union)
+ case "enum":
+ enum := parseEnumDecl(l)
+ enum.Desc = desc
+ s.Types[enum.Name] = enum
+ s.enums = append(s.enums, enum)
+ case "input":
+ input := parseInputDecl(l)
+ input.Desc = desc
+ s.Types[input.Name] = input
+ case "scalar":
+ name := l.ConsumeIdent()
+ s.Types[name] = &Scalar{Name: name, Desc: desc}
+ case "directive":
+ directive := parseDirectiveDecl(l)
+ directive.Desc = desc
+ s.Directives[directive.Name] = directive
+ default:
+ l.SyntaxError(fmt.Sprintf(`unexpected %q, expecting "schema", "type", "enum", "interface", "union", "input", "scalar" or "directive"`, x))
+ }
+ }
+}
+
+func parseObjectDecl(l *common.Lexer) *Object {
+ o := &Object{}
+ o.Name = l.ConsumeIdent()
+ if l.Peek() == scanner.Ident {
+ l.ConsumeKeyword("implements")
+ for {
+ o.interfaceNames = append(o.interfaceNames, l.ConsumeIdent())
+ if l.Peek() == '{' {
+ break
+ }
+ }
+ }
+ l.ConsumeToken('{')
+ o.Fields = parseFields(l)
+ l.ConsumeToken('}')
+ return o
+}
+
+func parseInterfaceDecl(l *common.Lexer) *Interface {
+ i := &Interface{}
+ i.Name = l.ConsumeIdent()
+ l.ConsumeToken('{')
+ i.Fields = parseFields(l)
+ l.ConsumeToken('}')
+ return i
+}
+
+func parseUnionDecl(l *common.Lexer) *Union {
+ union := &Union{}
+ union.Name = l.ConsumeIdent()
+ l.ConsumeToken('=')
+ union.typeNames = []string{l.ConsumeIdent()}
+ for l.Peek() == '|' {
+ l.ConsumeToken('|')
+ union.typeNames = append(union.typeNames, l.ConsumeIdent())
+ }
+ return union
+}
+
+func parseInputDecl(l *common.Lexer) *InputObject {
+ i := &InputObject{}
+ i.Name = l.ConsumeIdent()
+ l.ConsumeToken('{')
+ for l.Peek() != '}' {
+ i.Values = append(i.Values, common.ParseInputValue(l))
+ }
+ l.ConsumeToken('}')
+ return i
+}
+
+func parseEnumDecl(l *common.Lexer) *Enum {
+ enum := &Enum{}
+ enum.Name = l.ConsumeIdent()
+ l.ConsumeToken('{')
+ for l.Peek() != '}' {
+ v := &EnumValue{}
+ v.Desc = l.DescComment()
+ v.Name = l.ConsumeIdent()
+ v.Directives = common.ParseDirectives(l)
+ enum.Values = append(enum.Values, v)
+ }
+ l.ConsumeToken('}')
+ return enum
+}
+
+func parseDirectiveDecl(l *common.Lexer) *DirectiveDecl {
+ d := &DirectiveDecl{}
+ l.ConsumeToken('@')
+ d.Name = l.ConsumeIdent()
+ if l.Peek() == '(' {
+ l.ConsumeToken('(')
+ for l.Peek() != ')' {
+ v := common.ParseInputValue(l)
+ d.Args = append(d.Args, v)
+ }
+ l.ConsumeToken(')')
+ }
+ l.ConsumeKeyword("on")
+ for {
+ loc := l.ConsumeIdent()
+ d.Locs = append(d.Locs, loc)
+ if l.Peek() != '|' {
+ break
+ }
+ l.ConsumeToken('|')
+ }
+ return d
+}
+
+func parseFields(l *common.Lexer) FieldList {
+ var fields FieldList
+ for l.Peek() != '}' {
+ f := &Field{}
+ f.Desc = l.DescComment()
+ f.Name = l.ConsumeIdent()
+ if l.Peek() == '(' {
+ l.ConsumeToken('(')
+ for l.Peek() != ')' {
+ f.Args = append(f.Args, common.ParseInputValue(l))
+ }
+ l.ConsumeToken(')')
+ }
+ l.ConsumeToken(':')
+ f.Type = common.ParseType(l)
+ f.Directives = common.ParseDirectives(l)
+ fields = append(fields, f)
+ }
+ return fields
+}
diff --git a/vendor/github.com/vektah/gqlgen/neelance/tests/testdata/LICENSE b/vendor/github.com/vektah/gqlgen/neelance/tests/testdata/LICENSE
new file mode 100644
index 00000000..fce4519e
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/neelance/tests/testdata/LICENSE
@@ -0,0 +1,33 @@
+The files in this testdata directory are derived from the graphql-js project:
+https://github.com/graphql/graphql-js
+
+BSD License
+
+For GraphQL software
+
+Copyright (c) 2015, Facebook, Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ * Neither the name Facebook nor the names of its contributors may be used to
+ endorse or promote products derived from this software without specific
+ prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file
diff --git a/vendor/github.com/vektah/gqlgen/neelance/validation/suggestion.go b/vendor/github.com/vektah/gqlgen/neelance/validation/suggestion.go
new file mode 100644
index 00000000..9702b5f5
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/neelance/validation/suggestion.go
@@ -0,0 +1,71 @@
+package validation
+
+import (
+ "fmt"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+func makeSuggestion(prefix string, options []string, input string) string {
+ var selected []string
+ distances := make(map[string]int)
+ for _, opt := range options {
+ distance := levenshteinDistance(input, opt)
+ threshold := max(len(input)/2, max(len(opt)/2, 1))
+ if distance < threshold {
+ selected = append(selected, opt)
+ distances[opt] = distance
+ }
+ }
+
+ if len(selected) == 0 {
+ return ""
+ }
+ sort.Slice(selected, func(i, j int) bool {
+ return distances[selected[i]] < distances[selected[j]]
+ })
+
+ parts := make([]string, len(selected))
+ for i, opt := range selected {
+ parts[i] = strconv.Quote(opt)
+ }
+ if len(parts) > 1 {
+ parts[len(parts)-1] = "or " + parts[len(parts)-1]
+ }
+ return fmt.Sprintf(" %s %s?", prefix, strings.Join(parts, ", "))
+}
+
+func levenshteinDistance(s1, s2 string) int {
+ column := make([]int, len(s1)+1)
+ for y := range s1 {
+ column[y+1] = y + 1
+ }
+ for x, rx := range s2 {
+ column[0] = x + 1
+ lastdiag := x
+ for y, ry := range s1 {
+ olddiag := column[y+1]
+ if rx != ry {
+ lastdiag++
+ }
+ column[y+1] = min(column[y+1]+1, min(column[y]+1, lastdiag))
+ lastdiag = olddiag
+ }
+ }
+ return column[len(s1)]
+}
+
+func min(a, b int) int {
+ if a < b {
+ return a
+ }
+ return b
+}
+
+func max(a, b int) int {
+ if a > b {
+ return a
+ }
+ return b
+}
diff --git a/vendor/github.com/vektah/gqlgen/neelance/validation/validation.go b/vendor/github.com/vektah/gqlgen/neelance/validation/validation.go
new file mode 100644
index 00000000..28124310
--- /dev/null
+++ b/vendor/github.com/vektah/gqlgen/neelance/validation/validation.go
@@ -0,0 +1,861 @@
+package validation
+
+import (
+ "fmt"
+ "math"
+ "reflect"
+ "strconv"
+ "strings"
+ "text/scanner"
+
+ "github.com/vektah/gqlgen/neelance/common"
+ "github.com/vektah/gqlgen/neelance/errors"
+ "github.com/vektah/gqlgen/neelance/query"
+ "github.com/vektah/gqlgen/neelance/schema"
+)
+
+type varSet map[*common.InputValue]struct{}
+
+type selectionPair struct{ a, b query.Selection }
+
+type fieldInfo struct {
+ sf *schema.Field
+ parent schema.NamedType
+}
+
+type context struct {
+ schema *schema.Schema
+ doc *query.Document
+ errs []*errors.QueryError
+ opErrs map[*query.Operation][]*errors.QueryError
+ usedVars map[*query.Operation]varSet
+ fieldMap map[*query.Field]fieldInfo
+ overlapValidated map[selectionPair]struct{}
+}
+
+func (c *context) addErr(loc errors.Location, rule string, format string, a ...interface{}) {
+ c.addErrMultiLoc([]errors.Location{loc}, rule, format, a...)
+}
+
+func (c *context) addErrMultiLoc(locs []errors.Location, rule string, format string, a ...interface{}) {
+ c.errs = append(c.errs, &errors.QueryError{
+ Message: fmt.Sprintf(format, a...),
+ Locations: locs,
+ Rule: rule,
+ })
+}
+
+type opContext struct {
+ *context
+ ops []*query.Operation
+}
+
+func Validate(s *schema.Schema, doc *query.Document) []*errors.QueryError {
+ c := &context{
+ schema: s,
+ doc: doc,
+ opErrs: make(map[*query.Operation][]*errors.QueryError),
+ usedVars: make(map[*query.Operation]varSet),
+ fieldMap: make(map[*query.Field]fieldInfo),
+ overlapValidated: make(map[selectionPair]struct{}),
+ }
+
+ opNames := make(nameSet)
+ fragUsedBy := make(map[*query.FragmentDecl][]*query.Operation)
+ for _, op := range doc.Operations {
+ c.usedVars[op] = make(varSet)
+ opc := &opContext{c, []*query.Operation{op}}
+
+ if op.Name.Name == "" && len(doc.Operations) != 1 {
+ c.addErr(op.Loc, "LoneAnonymousOperation", "This anonymous operation must be the only defined operation.")
+ }
+ if op.Name.Name != "" {
+ validateName(c, opNames, op.Name, "UniqueOperationNames", "operation")
+ }
+
+ validateDirectives(opc, string(op.Type), op.Directives)
+
+ varNames := make(nameSet)
+ for _, v := range op.Vars {
+ validateName(c, varNames, v.Name, "UniqueVariableNames", "variable")
+
+ t := resolveType(c, v.Type)
+ if !canBeInput(t) {
+ c.addErr(v.TypeLoc, "VariablesAreInputTypes", "Variable %q cannot be non-input type %q.", "$"+v.Name.Name, t)
+ }
+
+ if v.Default != nil {
+ validateLiteral(opc, v.Default)
+
+ if t != nil {
+ if nn, ok := t.(*common.NonNull); ok {
+ c.addErr(v.Default.Location(), "DefaultValuesOfCorrectType", "Variable %q of type %q is required and will not use the default value. Perhaps you meant to use type %q.", "$"+v.Name.Name, t, nn.OfType)
+ }
+
+ if ok, reason := validateValueType(opc, v.Default, t); !ok {
+ c.addErr(v.Default.Location(), "DefaultValuesOfCorrectType", "Variable %q of type %q has invalid default value %s.\n%s", "$"+v.Name.Name, t, v.Default, reason)
+ }
+ }
+ }
+ }
+
+ var entryPoint schema.NamedType
+ switch op.Type {
+ case query.Query:
+ entryPoint = s.EntryPoints["query"]
+ case query.Mutation:
+ entryPoint = s.EntryPoints["mutation"]
+ case query.Subscription:
+ entryPoint = s.EntryPoints["subscription"]
+ default:
+ panic("unreachable")
+ }
+
+ validateSelectionSet(opc, op.Selections, entryPoint)
+
+ fragUsed := make(map[*query.FragmentDecl]struct{})
+ markUsedFragments(c, op.Selections, fragUsed)
+ for frag := range fragUsed {
+ fragUsedBy[frag] = append(fragUsedBy[frag], op)
+ }
+ }
+
+ fragNames := make(nameSet)
+ fragVisited := make(map[*query.FragmentDecl]struct{})
+ for _, frag := range doc.Fragments {
+ opc := &opContext{c, fragUsedBy[frag]}
+
+ validateName(c, fragNames, frag.Name, "UniqueFragmentNames", "fragment")
+ validateDirectives(opc, "FRAGMENT_DEFINITION", frag.Directives)
+
+ t := unwrapType(resolveType(c, &frag.On))
+ // continue even if t is nil
+ if t != nil && !canBeFragment(t) {
+ c.addErr(frag.On.Loc, "FragmentsOnCompositeTypes", "Fragment %q cannot condition on non composite type %q.", frag.Name.Name, t)
+ continue
+ }
+
+ validateSelectionSet(opc, frag.Selections, t)
+
+ if _, ok := fragVisited[frag]; !ok {
+ detectFragmentCycle(c, frag.Selections, fragVisited, nil, map[string]int{frag.Name.Name: 0})
+ }
+ }
+
+ for _, frag := range doc.Fragments {
+ if len(fragUsedBy[frag]) == 0 {
+ c.addErr(frag.Loc, "NoUnusedFragments", "Fragment %q is never used.", frag.Name.Name)
+ }
+ }
+
+ for _, op := range doc.Operations {
+ c.errs = append(c.errs, c.opErrs[op]...)
+
+ opUsedVars := c.usedVars[op]
+ for _, v := range op.Vars {
+ if _, ok := opUsedVars[v]; !ok {
+ opSuffix := ""
+ if op.Name.Name != "" {
+ opSuffix = fmt.Sprintf(" in operation %q", op.Name.Name)
+ }
+ c.addErr(v.Loc, "NoUnusedVariables", "Variable %q is never used%s.", "$"+v.Name.Name, opSuffix)
+ }
+ }
+ }
+
+ return c.errs
+}
+
+func validateSelectionSet(c *opContext, sels []query.Selection, t schema.NamedType) {
+ for _, sel := range sels {
+ validateSelection(c, sel, t)
+ }
+
+ for i, a := range sels {
+ for _, b := range sels[i+1:] {
+ c.validateOverlap(a, b, nil, nil)
+ }
+ }
+}
+
+func validateSelection(c *opContext, sel query.Selection, t schema.NamedType) {
+ switch sel := sel.(type) {
+ case *query.Field:
+ validateDirectives(c, "FIELD", sel.Directives)
+
+ fieldName := sel.Name.Name
+ var f *schema.Field
+ switch fieldName {
+ case "__typename":
+ f = &schema.Field{
+ Name: "__typename",
+ Type: c.schema.Types["String"],
+ }
+ case "__schema":
+ f = &schema.Field{
+ Name: "__schema",
+ Type: c.schema.Types["__Schema"],
+ }
+ case "__type":
+ f = &schema.Field{
+ Name: "__type",
+ Args: common.InputValueList{
+ &common.InputValue{
+ Name: common.Ident{Name: "name"},
+ Type: &common.NonNull{OfType: c.schema.Types["String"]},
+ },
+ },
+ Type: c.schema.Types["__Type"],
+ }
+ default:
+ f = fields(t).Get(fieldName)
+ if f == nil && t != nil {
+ suggestion := makeSuggestion("Did you mean", fields(t).Names(), fieldName)
+ c.addErr(sel.Alias.Loc, "FieldsOnCorrectType", "Cannot query field %q on type %q.%s", fieldName, t, suggestion)
+ }
+ }
+ c.fieldMap[sel] = fieldInfo{sf: f, parent: t}
+
+ validateArgumentLiterals(c, sel.Arguments)
+ if f != nil {
+ validateArgumentTypes(c, sel.Arguments, f.Args, sel.Alias.Loc,
+ func() string { return fmt.Sprintf("field %q of type %q", fieldName, t) },
+ func() string { return fmt.Sprintf("Field %q", fieldName) },
+ )
+ }
+
+ var ft common.Type
+ if f != nil {
+ ft = f.Type
+ sf := hasSubfields(ft)
+ if sf && sel.Selections == nil {
+ c.addErr(sel.Alias.Loc, "ScalarLeafs", "Field %q of type %q must have a selection of subfields. Did you mean \"%s { ... }\"?", fieldName, ft, fieldName)
+ }
+ if !sf && sel.Selections != nil {
+ c.addErr(sel.SelectionSetLoc, "ScalarLeafs", "Field %q must not have a selection since type %q has no subfields.", fieldName, ft)
+ }
+ }
+ if sel.Selections != nil {
+ validateSelectionSet(c, sel.Selections, unwrapType(ft))
+ }
+
+ case *query.InlineFragment:
+ validateDirectives(c, "INLINE_FRAGMENT", sel.Directives)
+ if sel.On.Name != "" {
+ fragTyp := unwrapType(resolveType(c.context, &sel.On))
+ if fragTyp != nil && !compatible(t, fragTyp) {
+ c.addErr(sel.Loc, "PossibleFragmentSpreads", "Fragment cannot be spread here as objects of type %q can never be of type %q.", t, fragTyp)
+ }
+ t = fragTyp
+ // continue even if t is nil
+ }
+ if t != nil && !canBeFragment(t) {
+ c.addErr(sel.On.Loc, "FragmentsOnCompositeTypes", "Fragment cannot condition on non composite type %q.", t)
+ return
+ }
+ validateSelectionSet(c, sel.Selections, unwrapType(t))
+
+ case *query.FragmentSpread:
+ validateDirectives(c, "FRAGMENT_SPREAD", sel.Directives)
+ frag := c.doc.Fragments.Get(sel.Name.Name)
+ if frag == nil {
+ c.addErr(sel.Name.Loc, "KnownFragmentNames", "Unknown fragment %q.", sel.Name.Name)
+ return
+ }
+ fragTyp := c.schema.Types[frag.On.Name]
+ if !compatible(t, fragTyp) {
+ c.addErr(sel.Loc, "PossibleFragmentSpreads", "Fragment %q cannot be spread here as objects of type %q can never be of type %q.", frag.Name.Name, t, fragTyp)
+ }
+
+ default:
+ panic("unreachable")
+ }
+}
+
+func compatible(a, b common.Type) bool {
+ for _, pta := range possibleTypes(a) {
+ for _, ptb := range possibleTypes(b) {
+ if pta == ptb {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+func possibleTypes(t common.Type) []*schema.Object {
+ switch t := t.(type) {
+ case *schema.Object:
+ return []*schema.Object{t}
+ case *schema.Interface:
+ return t.PossibleTypes
+ case *schema.Union:
+ return t.PossibleTypes
+ default:
+ return nil
+ }
+}
+
+func markUsedFragments(c *context, sels []query.Selection, fragUsed map[*query.FragmentDecl]struct{}) {
+ for _, sel := range sels {
+ switch sel := sel.(type) {
+ case *query.Field:
+ if sel.Selections != nil {
+ markUsedFragments(c, sel.Selections, fragUsed)
+ }
+
+ case *query.InlineFragment:
+ markUsedFragments(c, sel.Selections, fragUsed)
+
+ case *query.FragmentSpread:
+ frag := c.doc.Fragments.Get(sel.Name.Name)
+ if frag == nil {
+ return
+ }
+
+ if _, ok := fragUsed[frag]; ok {
+ return
+ }
+ fragUsed[frag] = struct{}{}
+ markUsedFragments(c, frag.Selections, fragUsed)
+
+ default:
+ panic("unreachable")
+ }
+ }
+}
+
+func detectFragmentCycle(c *context, sels []query.Selection, fragVisited map[*query.FragmentDecl]struct{}, spreadPath []*query.FragmentSpread, spreadPathIndex map[string]int) {
+ for _, sel := range sels {
+ detectFragmentCycleSel(c, sel, fragVisited, spreadPath, spreadPathIndex)
+ }
+}
+
+func detectFragmentCycleSel(c *context, sel query.Selection, fragVisited map[*query.FragmentDecl]struct{}, spreadPath []*query.FragmentSpread, spreadPathIndex map[string]int) {
+ switch sel := sel.(type) {
+ case *query.Field:
+ if sel.Selections != nil {
+ detectFragmentCycle(c, sel.Selections, fragVisited, spreadPath, spreadPathIndex)
+ }
+
+ case *query.InlineFragment:
+ detectFragmentCycle(c, sel.Selections, fragVisited, spreadPath, spreadPathIndex)
+
+ case *query.FragmentSpread:
+ frag := c.doc.Fragments.Get(sel.Name.Name)
+ if frag == nil {
+ return
+ }
+
+ spreadPath = append(spreadPath, sel)
+ if i, ok := spreadPathIndex[frag.Name.Name]; ok {
+ cyclePath := spreadPath[i:]
+ via := ""
+ if len(cyclePath) > 1 {
+ names := make([]string, len(cyclePath)-1)
+ for i, frag := range cyclePath[:len(cyclePath)-1] {
+ names[i] = frag.Name.Name
+ }
+ via = " via " + strings.Join(names, ", ")
+ }
+
+ locs := make([]errors.Location, len(cyclePath))
+ for i, frag := range cyclePath {
+ locs[i] = frag.Loc
+ }
+ c.addErrMultiLoc(locs, "NoFragmentCycles", "Cannot spread fragment %q within itself%s.", frag.Name.Name, via)
+ return
+ }
+
+ if _, ok := fragVisited[frag]; ok {
+ return
+ }
+ fragVisited[frag] = struct{}{}
+
+ spreadPathIndex[frag.Name.Name] = len(spreadPath)
+ detectFragmentCycle(c, frag.Selections, fragVisited, spreadPath, spreadPathIndex)
+ delete(spreadPathIndex, frag.Name.Name)
+
+ default:
+ panic("unreachable")
+ }
+}
+
+func (c *context) validateOverlap(a, b query.Selection, reasons *[]string, locs *[]errors.Location) {
+ if a == b {
+ return
+ }
+
+ if _, ok := c.overlapValidated[selectionPair{a, b}]; ok {
+ return
+ }
+ c.overlapValidated[selectionPair{a, b}] = struct{}{}
+ c.overlapValidated[selectionPair{b, a}] = struct{}{}
+
+ switch a := a.(type) {
+ case *query.Field:
+ switch b := b.(type) {
+ case *query.Field:
+ if b.Alias.Loc.Before(a.Alias.Loc) {
+ a, b = b, a
+ }
+ if reasons2, locs2 := c.validateFieldOverlap(a, b); len(reasons2) != 0 {
+ locs2 = append(locs2, a.Alias.Loc, b.Alias.Loc)
+ if reasons == nil {
+ c.addErrMultiLoc(locs2, "OverlappingFieldsCanBeMerged", "Fields %q conflict because %s. Use different aliases on the fields to fetch both if this was intentional.", a.Alias.Name, strings.Join(reasons2, " and "))
+ return
+ }
+ for _, r := range reasons2 {
+ *reasons = append(*reasons, fmt.Sprintf("subfields %q conflict because %s", a.Alias.Name, r))
+ }
+ *locs = append(*locs, locs2...)
+ }
+
+ case *query.InlineFragment:
+ for _, sel := range b.Selections {
+ c.validateOverlap(a, sel, reasons, locs)
+ }
+
+ case *query.FragmentSpread:
+ if frag := c.doc.Fragments.Get(b.Name.Name); frag != nil {
+ for _, sel := range frag.Selections {
+ c.validateOverlap(a, sel, reasons, locs)
+ }
+ }
+
+ default:
+ panic("unreachable")
+ }
+
+ case *query.InlineFragment:
+ for _, sel := range a.Selections {
+ c.validateOverlap(sel, b, reasons, locs)
+ }
+
+ case *query.FragmentSpread:
+ if frag := c.doc.Fragments.Get(a.Name.Name); frag != nil {
+ for _, sel := range frag.Selections {
+ c.validateOverlap(sel, b, reasons, locs)
+ }
+ }
+
+ default:
+ panic("unreachable")
+ }
+}
+
+func (c *context) validateFieldOverlap(a, b *query.Field) ([]string, []errors.Location) {
+ if a.Alias.Name != b.Alias.Name {
+ return nil, nil
+ }
+
+ if asf := c.fieldMap[a].sf; asf != nil {
+ if bsf := c.fieldMap[b].sf; bsf != nil {
+ if !typesCompatible(asf.Type, bsf.Type) {
+ return []string{fmt.Sprintf("they return conflicting types %s and %s", asf.Type, bsf.Type)}, nil
+ }
+ }
+ }
+
+ at := c.fieldMap[a].parent
+ bt := c.fieldMap[b].parent
+ if at == nil || bt == nil || at == bt {
+ if a.Name.Name != b.Name.Name {
+ return []string{fmt.Sprintf("%s and %s are different fields", a.Name.Name, b.Name.Name)}, nil
+ }
+
+ if argumentsConflict(a.Arguments, b.Arguments) {
+ return []string{"they have differing arguments"}, nil
+ }
+ }
+
+ var reasons []string
+ var locs []errors.Location
+ for _, a2 := range a.Selections {
+ for _, b2 := range b.Selections {
+ c.validateOverlap(a2, b2, &reasons, &locs)
+ }
+ }
+ return reasons, locs
+}
+
+func argumentsConflict(a, b common.ArgumentList) bool {
+ if len(a) != len(b) {
+ return true
+ }
+ for _, argA := range a {
+ valB, ok := b.Get(argA.Name.Name)
+ if !ok || !reflect.DeepEqual(argA.Value.Value(nil), valB.Value(nil)) {
+ return true
+ }
+ }
+ return false
+}
+
+func fields(t common.Type) schema.FieldList {
+ switch t := t.(type) {
+ case *schema.Object:
+ return t.Fields
+ case *schema.Interface:
+ return t.Fields
+ default:
+ return nil
+ }
+}
+
+func unwrapType(t common.Type) schema.NamedType {
+ if t == nil {
+ return nil
+ }
+ for {
+ switch t2 := t.(type) {
+ case schema.NamedType:
+ return t2
+ case *common.List:
+ t = t2.OfType
+ case *common.NonNull:
+ t = t2.OfType
+ default:
+ panic("unreachable")
+ }
+ }
+}
+
+func resolveType(c *context, t common.Type) common.Type {
+ t2, err := common.ResolveType(t, c.schema.Resolve)
+ if err != nil {
+ c.errs = append(c.errs, err)
+ }
+ return t2
+}
+
+func validateDirectives(c *opContext, loc string, directives common.DirectiveList) {
+ directiveNames := make(nameSet)
+ for _, d := range directives {
+ dirName := d.Name.Name
+ validateNameCustomMsg(c.context, directiveNames, d.Name, "UniqueDirectivesPerLocation", func() string {
+ return fmt.Sprintf("The directive %q can only be used once at this location.", dirName)
+ })
+
+ validateArgumentLiterals(c, d.Args)
+
+ dd, ok := c.schema.Directives[dirName]
+ if !ok {
+ c.addErr(d.Name.Loc, "KnownDirectives", "Unknown directive %q.", dirName)
+ continue
+ }
+
+ locOK := false
+ for _, allowedLoc := range dd.Locs {
+ if loc == allowedLoc {
+ locOK = true
+ break
+ }
+ }
+ if !locOK {
+ c.addErr(d.Name.Loc, "KnownDirectives", "Directive %q may not be used on %s.", dirName, loc)
+ }
+
+ validateArgumentTypes(c, d.Args, dd.Args, d.Name.Loc,
+ func() string { return fmt.Sprintf("directive %q", "@"+dirName) },
+ func() string { return fmt.Sprintf("Directive %q", "@"+dirName) },
+ )
+ }
+}
+
+type nameSet map[string]errors.Location
+
+func validateName(c *context, set nameSet, name common.Ident, rule string, kind string) {
+ validateNameCustomMsg(c, set, name, rule, func() string {
+ return fmt.Sprintf("There can be only one %s named %q.", kind, name.Name)
+ })
+}
+
+func validateNameCustomMsg(c *context, set nameSet, name common.Ident, rule string, msg func() string) {
+ if loc, ok := set[name.Name]; ok {
+ c.addErrMultiLoc([]errors.Location{loc, name.Loc}, rule, msg())
+ return
+ }
+ set[name.Name] = name.Loc
+}
+
+func validateArgumentTypes(c *opContext, args common.ArgumentList, argDecls common.InputValueList, loc errors.Location, owner1, owner2 func() string) {
+ for _, selArg := range args {
+ arg := argDecls.Get(selArg.Name.Name)
+ if arg == nil {
+ c.addErr(selArg.Name.Loc, "KnownArgumentNames", "Unknown argument %q on %s.", selArg.Name.Name, owner1())
+ continue
+ }
+ value := selArg.Value
+ if ok, reason := validateValueType(c, value, arg.Type); !ok {
+ c.addErr(value.Location(), "ArgumentsOfCorrectType", "Argument %q has invalid value %s.\n%s", arg.Name.Name, value, reason)
+ }
+ }
+ for _, decl := range argDecls {
+ if _, ok := decl.Type.(*common.NonNull); ok {
+ if _, ok := args.Get(decl.Name.Name); !ok {
+ c.addErr(loc, "ProvidedNonNullArguments", "%s argument %q of type %q is required but not provided.", owner2(), decl.Name.Name, decl.Type)
+ }
+ }
+ }
+}
+
+func validateArgumentLiterals(c *opContext, args common.ArgumentList) {
+ argNames := make(nameSet)
+ for _, arg := range args {
+ validateName(c.context, argNames, arg.Name, "UniqueArgumentNames", "argument")
+ validateLiteral(c, arg.Value)
+ }
+}
+
+func validateLiteral(c *opContext, l common.Literal) {
+ switch l := l.(type) {
+ case *common.ObjectLit:
+ fieldNames := make(nameSet)
+ for _, f := range l.Fields {
+ validateName(c.context, fieldNames, f.Name, "UniqueInputFieldNames", "input field")
+ validateLiteral(c, f.Value)
+ }
+ case *common.ListLit:
+ for _, entry := range l.Entries {
+ validateLiteral(c, entry)
+ }
+ case *common.Variable:
+ for _, op := range c.ops {
+ v := op.Vars.Get(l.Name)
+ if v == nil {
+ byOp := ""
+ if op.Name.Name != "" {
+ byOp = fmt.Sprintf(" by operation %q", op.Name.Name)
+ }
+ c.opErrs[op] = append(c.opErrs[op], &errors.QueryError{
+ Message: fmt.Sprintf("Variable %q is not defined%s.", "$"+l.Name, byOp),
+ Locations: []errors.Location{l.Loc, op.Loc},
+ Rule: "NoUndefinedVariables",
+ })
+ continue
+ }
+ c.usedVars[op][v] = struct{}{}
+ }
+ }
+}
+
+func validateValueType(c *opContext, v common.Literal, t common.Type) (bool, string) {
+ if v, ok := v.(*common.Variable); ok {
+ for _, op := range c.ops {
+ if v2 := op.Vars.Get(v.Name); v2 != nil {
+ t2, err := common.ResolveType(v2.Type, c.schema.Resolve)
+ if _, ok := t2.(*common.NonNull); !ok && v2.Default != nil {
+ t2 = &common.NonNull{OfType: t2}
+ }
+ if err == nil && !typeCanBeUsedAs(t2, t) {
+ c.addErrMultiLoc([]errors.Location{v2.Loc, v.Loc}, "VariablesInAllowedPosition", "Variable %q of type %q used in position expecting type %q.", "$"+v.Name, t2, t)
+ }
+ }
+ }
+ return true, ""
+ }
+
+ if nn, ok := t.(*common.NonNull); ok {
+ if isNull(v) {
+ return false, fmt.Sprintf("Expected %q, found null.", t)
+ }
+ t = nn.OfType
+ }
+ if isNull(v) {
+ return true, ""
+ }
+
+ switch t := t.(type) {
+ case *schema.Scalar, *schema.Enum:
+ if lit, ok := v.(*common.BasicLit); ok {
+ if validateBasicLit(lit, t) {
+ return true, ""
+ }
+ } else {
+ // custom complex scalars will be validated when unmarshaling
+ return true, ""
+ }
+
+ case *common.List:
+ list, ok := v.(*common.ListLit)
+ if !ok {
+ return validateValueType(c, v, t.OfType) // single value instead of list
+ }
+ for i, entry := range list.Entries {
+ if ok, reason := validateValueType(c, entry, t.OfType); !ok {
+ return false, fmt.Sprintf("In element #%d: %s", i, reason)
+ }
+ }
+ return true, ""
+
+ case *schema.InputObject:
+ v, ok := v.(*common.ObjectLit)
+ if !ok {
+ return false, fmt.Sprintf("Expected %q, found not an object.", t)
+ }
+ for _, f := range v.Fields {
+ name := f.Name.Name
+ iv := t.Values.Get(name)
+ if iv == nil {
+ return false, fmt.Sprintf("In field %q: Unknown field.", name)
+ }
+ if ok, reason := validateValueType(c, f.Value, iv.Type); !ok {
+ return false, fmt.Sprintf("In field %q: %s", name, reason)
+ }
+ }
+ for _, iv := range t.Values {
+ found := false
+ for _, f := range v.Fields {
+ if f.Name.Name == iv.Name.Name {
+ found = true
+ break
+ }
+ }
+ if !found {
+ if _, ok := iv.Type.(*common.NonNull); ok && iv.Default == nil {
+ return false, fmt.Sprintf("In field %q: Expected %q, found null.", iv.Name.Name, iv.Type)
+ }
+ }
+ }
+ return true, ""
+ }
+
+ return false, fmt.Sprintf("Expected type %q, found %s.", t, v)
+}
+
+func validateBasicLit(v *common.BasicLit, t common.Type) bool {
+ switch t := t.(type) {
+ case *schema.Scalar:
+ switch t.Name {
+ case "Int":
+ if v.Type != scanner.Int {
+ return false
+ }
+ f, err := strconv.ParseFloat(v.Text, 64)
+ if err != nil {
+ panic(err)
+ }
+ return f >= math.MinInt32 && f <= math.MaxInt32
+ case "Float":
+ return v.Type == scanner.Int || v.Type == scanner.Float
+ case "String":
+ return v.Type == scanner.String
+ case "Boolean":
+ return v.Type == scanner.Ident && (v.Text == "true" || v.Text == "false")
+ case "ID":
+ return v.Type == scanner.Int || v.Type == scanner.String
+ default:
+ //TODO: Type-check against expected type by Unmarshaling
+ return true
+ }
+
+ case *schema.Enum:
+ if v.Type != scanner.Ident {
+ return false
+ }
+ for _, option := range t.Values {
+ if option.Name == v.Text {
+ return true
+ }
+ }
+ return false
+ }
+
+ return false
+}
+
+func canBeFragment(t common.Type) bool {
+ switch t.(type) {
+ case *schema.Object, *schema.Interface, *schema.Union:
+ return true
+ default:
+ return false
+ }
+}
+
+func canBeInput(t common.Type) bool {
+ switch t := t.(type) {
+ case *schema.InputObject, *schema.Scalar, *schema.Enum:
+ return true
+ case *common.List:
+ return canBeInput(t.OfType)
+ case *common.NonNull:
+ return canBeInput(t.OfType)
+ default:
+ return false
+ }
+}
+
+func hasSubfields(t common.Type) bool {
+ switch t := t.(type) {
+ case *schema.Object, *schema.Interface, *schema.Union:
+ return true
+ case *common.List:
+ return hasSubfields(t.OfType)
+ case *common.NonNull:
+ return hasSubfields(t.OfType)
+ default:
+ return false
+ }
+}
+
+func isLeaf(t common.Type) bool {
+ switch t.(type) {
+ case *schema.Scalar, *schema.Enum:
+ return true
+ default:
+ return false
+ }
+}
+
+func isNull(lit interface{}) bool {
+ _, ok := lit.(*common.NullLit)
+ return ok
+}
+
+func typesCompatible(a, b common.Type) bool {
+ al, aIsList := a.(*common.List)
+ bl, bIsList := b.(*common.List)
+ if aIsList || bIsList {
+ return aIsList && bIsList && typesCompatible(al.OfType, bl.OfType)
+ }
+
+ ann, aIsNN := a.(*common.NonNull)
+ bnn, bIsNN := b.(*common.NonNull)
+ if aIsNN || bIsNN {
+ return aIsNN && bIsNN && typesCompatible(ann.OfType, bnn.OfType)
+ }
+
+ if isLeaf(a) || isLeaf(b) {
+ return a == b
+ }
+
+ return true
+}
+
+func typeCanBeUsedAs(t, as common.Type) bool {
+ nnT, okT := t.(*common.NonNull)
+ if okT {
+ t = nnT.OfType
+ }
+
+ nnAs, okAs := as.(*common.NonNull)
+ if okAs {
+ as = nnAs.OfType
+ if !okT {
+ return false // nullable can not be used as non-null
+ }
+ }
+
+ if t == as {
+ return true
+ }
+
+ if lT, ok := t.(*common.List); ok {
+ if lAs, ok := as.(*common.List); ok {
+ return typeCanBeUsedAs(lT.OfType, lAs.OfType)
+ }
+ }
+ return false
+}