mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 12:54:38 +03:00
Stash box client interface (#751)
* Add gql client generation files * Update dependencies * Add stash-box client generation to the makefile * Move scraped scene object matchers to models * Add stash-box to scrape with dropdown * Add scrape scene from fingerprint in UI
This commit is contained in:
29
vendor/github.com/99designs/gqlgen/graphql/cache.go
generated
vendored
Normal file
29
vendor/github.com/99designs/gqlgen/graphql/cache.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
package graphql
|
||||
|
||||
import "context"
|
||||
|
||||
// Cache is a shared store for APQ and query AST caching
|
||||
type Cache interface {
|
||||
// Get looks up a key's value from the cache.
|
||||
Get(ctx context.Context, key string) (value interface{}, ok bool)
|
||||
|
||||
// Add adds a value to the cache.
|
||||
Add(ctx context.Context, key string, value interface{})
|
||||
}
|
||||
|
||||
// MapCache is the simplest implementation of a cache, because it can not evict it should only be used in tests
|
||||
type MapCache map[string]interface{}
|
||||
|
||||
// Get looks up a key's value from the cache.
|
||||
func (m MapCache) Get(ctx context.Context, key string) (value interface{}, ok bool) {
|
||||
v, ok := m[key]
|
||||
return v, ok
|
||||
}
|
||||
|
||||
// Add adds a value to the cache.
|
||||
func (m MapCache) Add(ctx context.Context, key string, value interface{}) { m[key] = value }
|
||||
|
||||
type NoCache struct{}
|
||||
|
||||
func (n NoCache) Get(ctx context.Context, key string) (value interface{}, ok bool) { return nil, false }
|
||||
func (n NoCache) Add(ctx context.Context, key string, value interface{}) {}
|
||||
274
vendor/github.com/99designs/gqlgen/graphql/context.go
generated
vendored
274
vendor/github.com/99designs/gqlgen/graphql/context.go
generated
vendored
@@ -1,274 +0,0 @@
|
||||
package graphql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/vektah/gqlparser/ast"
|
||||
"github.com/vektah/gqlparser/gqlerror"
|
||||
)
|
||||
|
||||
type Resolver func(ctx context.Context) (res interface{}, err error)
|
||||
type FieldMiddleware func(ctx context.Context, next Resolver) (res interface{}, err error)
|
||||
type RequestMiddleware func(ctx context.Context, next func(ctx context.Context) []byte) []byte
|
||||
type ComplexityLimitFunc func(ctx context.Context) int
|
||||
|
||||
type RequestContext struct {
|
||||
RawQuery string
|
||||
Variables map[string]interface{}
|
||||
Doc *ast.QueryDocument
|
||||
|
||||
ComplexityLimit int
|
||||
OperationComplexity int
|
||||
DisableIntrospection bool
|
||||
|
||||
// ErrorPresenter will be used to generate the error
|
||||
// message from errors given to Error().
|
||||
ErrorPresenter ErrorPresenterFunc
|
||||
Recover RecoverFunc
|
||||
ResolverMiddleware FieldMiddleware
|
||||
DirectiveMiddleware FieldMiddleware
|
||||
RequestMiddleware RequestMiddleware
|
||||
Tracer Tracer
|
||||
|
||||
errorsMu sync.Mutex
|
||||
Errors gqlerror.List
|
||||
extensionsMu sync.Mutex
|
||||
Extensions map[string]interface{}
|
||||
}
|
||||
|
||||
func DefaultResolverMiddleware(ctx context.Context, next Resolver) (res interface{}, err error) {
|
||||
return next(ctx)
|
||||
}
|
||||
|
||||
func DefaultDirectiveMiddleware(ctx context.Context, next Resolver) (res interface{}, err error) {
|
||||
return next(ctx)
|
||||
}
|
||||
|
||||
func DefaultRequestMiddleware(ctx context.Context, next func(ctx context.Context) []byte) []byte {
|
||||
return next(ctx)
|
||||
}
|
||||
|
||||
func NewRequestContext(doc *ast.QueryDocument, query string, variables map[string]interface{}) *RequestContext {
|
||||
return &RequestContext{
|
||||
Doc: doc,
|
||||
RawQuery: query,
|
||||
Variables: variables,
|
||||
ResolverMiddleware: DefaultResolverMiddleware,
|
||||
DirectiveMiddleware: DefaultDirectiveMiddleware,
|
||||
RequestMiddleware: DefaultRequestMiddleware,
|
||||
Recover: DefaultRecover,
|
||||
ErrorPresenter: DefaultErrorPresenter,
|
||||
Tracer: &NopTracer{},
|
||||
}
|
||||
}
|
||||
|
||||
type key string
|
||||
|
||||
const (
|
||||
request key = "request_context"
|
||||
resolver key = "resolver_context"
|
||||
)
|
||||
|
||||
func GetRequestContext(ctx context.Context) *RequestContext {
|
||||
if val, ok := ctx.Value(request).(*RequestContext); ok {
|
||||
return val
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func WithRequestContext(ctx context.Context, rc *RequestContext) context.Context {
|
||||
return context.WithValue(ctx, request, rc)
|
||||
}
|
||||
|
||||
type ResolverContext struct {
|
||||
Parent *ResolverContext
|
||||
// The name of the type this field belongs to
|
||||
Object string
|
||||
// These are the args after processing, they can be mutated in middleware to change what the resolver will get.
|
||||
Args map[string]interface{}
|
||||
// The raw field
|
||||
Field CollectedField
|
||||
// The index of array in path.
|
||||
Index *int
|
||||
// The result object of resolver
|
||||
Result interface{}
|
||||
// IsMethod indicates if the resolver is a method
|
||||
IsMethod bool
|
||||
}
|
||||
|
||||
func (r *ResolverContext) Path() []interface{} {
|
||||
var path []interface{}
|
||||
for it := r; it != nil; it = it.Parent {
|
||||
if it.Index != nil {
|
||||
path = append(path, *it.Index)
|
||||
} else if it.Field.Field != nil {
|
||||
path = append(path, it.Field.Alias)
|
||||
}
|
||||
}
|
||||
|
||||
// because we are walking up the chain, all the elements are backwards, do an inplace flip.
|
||||
for i := len(path)/2 - 1; i >= 0; i-- {
|
||||
opp := len(path) - 1 - i
|
||||
path[i], path[opp] = path[opp], path[i]
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
func GetResolverContext(ctx context.Context) *ResolverContext {
|
||||
if val, ok := ctx.Value(resolver).(*ResolverContext); ok {
|
||||
return val
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func WithResolverContext(ctx context.Context, rc *ResolverContext) context.Context {
|
||||
rc.Parent = GetResolverContext(ctx)
|
||||
return context.WithValue(ctx, resolver, rc)
|
||||
}
|
||||
|
||||
// This is just a convenient wrapper method for CollectFields
|
||||
func CollectFieldsCtx(ctx context.Context, satisfies []string) []CollectedField {
|
||||
resctx := GetResolverContext(ctx)
|
||||
return CollectFields(GetRequestContext(ctx), resctx.Field.Selections, satisfies)
|
||||
}
|
||||
|
||||
// CollectAllFields returns a slice of all GraphQL field names that were selected for the current resolver context.
|
||||
// The slice will contain the unique set of all field names requested regardless of fragment type conditions.
|
||||
func CollectAllFields(ctx context.Context) []string {
|
||||
resctx := GetResolverContext(ctx)
|
||||
collected := CollectFields(GetRequestContext(ctx), resctx.Field.Selections, nil)
|
||||
uniq := make([]string, 0, len(collected))
|
||||
Next:
|
||||
for _, f := range collected {
|
||||
for _, name := range uniq {
|
||||
if name == f.Name {
|
||||
continue Next
|
||||
}
|
||||
}
|
||||
uniq = append(uniq, f.Name)
|
||||
}
|
||||
return uniq
|
||||
}
|
||||
|
||||
// Errorf sends an error string to the client, passing it through the formatter.
|
||||
func (c *RequestContext) Errorf(ctx context.Context, format string, args ...interface{}) {
|
||||
c.errorsMu.Lock()
|
||||
defer c.errorsMu.Unlock()
|
||||
|
||||
c.Errors = append(c.Errors, c.ErrorPresenter(ctx, fmt.Errorf(format, args...)))
|
||||
}
|
||||
|
||||
// Error sends an error to the client, passing it through the formatter.
|
||||
func (c *RequestContext) Error(ctx context.Context, err error) {
|
||||
c.errorsMu.Lock()
|
||||
defer c.errorsMu.Unlock()
|
||||
|
||||
c.Errors = append(c.Errors, c.ErrorPresenter(ctx, err))
|
||||
}
|
||||
|
||||
// HasError returns true if the current field has already errored
|
||||
func (c *RequestContext) HasError(rctx *ResolverContext) bool {
|
||||
c.errorsMu.Lock()
|
||||
defer c.errorsMu.Unlock()
|
||||
path := rctx.Path()
|
||||
|
||||
for _, err := range c.Errors {
|
||||
if equalPath(err.Path, path) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetErrors returns a list of errors that occurred in the current field
|
||||
func (c *RequestContext) GetErrors(rctx *ResolverContext) gqlerror.List {
|
||||
c.errorsMu.Lock()
|
||||
defer c.errorsMu.Unlock()
|
||||
path := rctx.Path()
|
||||
|
||||
var errs gqlerror.List
|
||||
for _, err := range c.Errors {
|
||||
if equalPath(err.Path, path) {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
func equalPath(a []interface{}, b []interface{}) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := 0; i < len(a); i++ {
|
||||
if a[i] != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// AddError is a convenience method for adding an error to the current response
|
||||
func AddError(ctx context.Context, err error) {
|
||||
GetRequestContext(ctx).Error(ctx, err)
|
||||
}
|
||||
|
||||
// AddErrorf is a convenience method for adding an error to the current response
|
||||
func AddErrorf(ctx context.Context, format string, args ...interface{}) {
|
||||
GetRequestContext(ctx).Errorf(ctx, format, args...)
|
||||
}
|
||||
|
||||
// RegisterExtension registers an extension, returns error if extension has already been registered
|
||||
func (c *RequestContext) RegisterExtension(key string, value interface{}) error {
|
||||
c.extensionsMu.Lock()
|
||||
defer c.extensionsMu.Unlock()
|
||||
|
||||
if c.Extensions == nil {
|
||||
c.Extensions = make(map[string]interface{})
|
||||
}
|
||||
|
||||
if _, ok := c.Extensions[key]; ok {
|
||||
return fmt.Errorf("extension already registered for key %s", key)
|
||||
}
|
||||
|
||||
c.Extensions[key] = value
|
||||
return nil
|
||||
}
|
||||
|
||||
// ChainFieldMiddleware add chain by FieldMiddleware
|
||||
func ChainFieldMiddleware(handleFunc ...FieldMiddleware) FieldMiddleware {
|
||||
n := len(handleFunc)
|
||||
|
||||
if n > 1 {
|
||||
lastI := n - 1
|
||||
return func(ctx context.Context, next Resolver) (interface{}, error) {
|
||||
var (
|
||||
chainHandler Resolver
|
||||
curI int
|
||||
)
|
||||
chainHandler = func(currentCtx context.Context) (interface{}, error) {
|
||||
if curI == lastI {
|
||||
return next(currentCtx)
|
||||
}
|
||||
curI++
|
||||
res, err := handleFunc[curI](currentCtx, chainHandler)
|
||||
curI--
|
||||
return res, err
|
||||
|
||||
}
|
||||
return handleFunc[0](ctx, chainHandler)
|
||||
}
|
||||
}
|
||||
|
||||
if n == 1 {
|
||||
return handleFunc[0]
|
||||
}
|
||||
|
||||
return func(ctx context.Context, next Resolver) (interface{}, error) {
|
||||
return next(ctx)
|
||||
}
|
||||
}
|
||||
92
vendor/github.com/99designs/gqlgen/graphql/context_field.go
generated
vendored
Normal file
92
vendor/github.com/99designs/gqlgen/graphql/context_field.go
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
package graphql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
)
|
||||
|
||||
type key string
|
||||
|
||||
const resolverCtx key = "resolver_context"
|
||||
|
||||
// Deprecated: Use FieldContext instead
|
||||
type ResolverContext = FieldContext
|
||||
|
||||
type FieldContext struct {
|
||||
Parent *FieldContext
|
||||
// The name of the type this field belongs to
|
||||
Object string
|
||||
// These are the args after processing, they can be mutated in middleware to change what the resolver will get.
|
||||
Args map[string]interface{}
|
||||
// The raw field
|
||||
Field CollectedField
|
||||
// The index of array in path.
|
||||
Index *int
|
||||
// The result object of resolver
|
||||
Result interface{}
|
||||
// IsMethod indicates if the resolver is a method
|
||||
IsMethod bool
|
||||
}
|
||||
|
||||
type FieldStats struct {
|
||||
// When field execution started
|
||||
Started time.Time
|
||||
|
||||
// When argument marshaling finished
|
||||
ArgumentsCompleted time.Time
|
||||
|
||||
// When the field completed running all middleware. Not available inside field middleware!
|
||||
Completed time.Time
|
||||
}
|
||||
|
||||
func (r *FieldContext) Path() ast.Path {
|
||||
var path ast.Path
|
||||
for it := r; it != nil; it = it.Parent {
|
||||
if it.Index != nil {
|
||||
path = append(path, ast.PathIndex(*it.Index))
|
||||
} else if it.Field.Field != nil {
|
||||
path = append(path, ast.PathName(it.Field.Alias))
|
||||
}
|
||||
}
|
||||
|
||||
// because we are walking up the chain, all the elements are backwards, do an inplace flip.
|
||||
for i := len(path)/2 - 1; i >= 0; i-- {
|
||||
opp := len(path) - 1 - i
|
||||
path[i], path[opp] = path[opp], path[i]
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
// Deprecated: Use GetFieldContext instead
|
||||
func GetResolverContext(ctx context.Context) *ResolverContext {
|
||||
return GetFieldContext(ctx)
|
||||
}
|
||||
|
||||
func GetFieldContext(ctx context.Context) *FieldContext {
|
||||
if val, ok := ctx.Value(resolverCtx).(*FieldContext); ok {
|
||||
return val
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func WithFieldContext(ctx context.Context, rc *FieldContext) context.Context {
|
||||
rc.Parent = GetFieldContext(ctx)
|
||||
return context.WithValue(ctx, resolverCtx, rc)
|
||||
}
|
||||
|
||||
func equalPath(a ast.Path, b ast.Path) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := 0; i < len(a); i++ {
|
||||
if a[i] != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
85
vendor/github.com/99designs/gqlgen/graphql/context_field_input.go
generated
vendored
Normal file
85
vendor/github.com/99designs/gqlgen/graphql/context_field_input.go
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
package graphql
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
const fieldInputCtx key = "field_input_context"
|
||||
|
||||
type FieldInputContext struct {
|
||||
ParentField *FieldContext
|
||||
ParentInput *FieldInputContext
|
||||
Field *string
|
||||
Index *int
|
||||
}
|
||||
|
||||
func (fic *FieldInputContext) Path() ast.Path {
|
||||
var inputPath ast.Path
|
||||
for it := fic; it != nil; it = it.ParentInput {
|
||||
if it.Index != nil {
|
||||
inputPath = append(inputPath, ast.PathIndex(*it.Index))
|
||||
} else if it.Field != nil {
|
||||
inputPath = append(inputPath, ast.PathName(*it.Field))
|
||||
}
|
||||
}
|
||||
|
||||
// because we are walking up the chain, all the elements are backwards, do an inplace flip.
|
||||
for i := len(inputPath)/2 - 1; i >= 0; i-- {
|
||||
opp := len(inputPath) - 1 - i
|
||||
inputPath[i], inputPath[opp] = inputPath[opp], inputPath[i]
|
||||
}
|
||||
|
||||
if fic.ParentField != nil {
|
||||
fieldPath := fic.ParentField.Path()
|
||||
return append(fieldPath, inputPath...)
|
||||
|
||||
}
|
||||
|
||||
return inputPath
|
||||
}
|
||||
|
||||
func NewFieldInputWithField(field string) *FieldInputContext {
|
||||
return &FieldInputContext{Field: &field}
|
||||
}
|
||||
|
||||
func NewFieldInputWithIndex(index int) *FieldInputContext {
|
||||
return &FieldInputContext{Index: &index}
|
||||
}
|
||||
|
||||
func WithFieldInputContext(ctx context.Context, fic *FieldInputContext) context.Context {
|
||||
if fieldContext := GetFieldContext(ctx); fieldContext != nil {
|
||||
fic.ParentField = fieldContext
|
||||
}
|
||||
if fieldInputContext := GetFieldInputContext(ctx); fieldInputContext != nil {
|
||||
fic.ParentInput = fieldInputContext
|
||||
}
|
||||
|
||||
return context.WithValue(ctx, fieldInputCtx, fic)
|
||||
}
|
||||
|
||||
func GetFieldInputContext(ctx context.Context) *FieldInputContext {
|
||||
if val, ok := ctx.Value(fieldInputCtx).(*FieldInputContext); ok {
|
||||
return val
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func WrapErrorWithInputPath(ctx context.Context, err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
inputContext := GetFieldInputContext(ctx)
|
||||
path := inputContext.Path()
|
||||
if gerr, ok := err.(*gqlerror.Error); ok {
|
||||
if gerr.Path == nil {
|
||||
gerr.Path = path
|
||||
}
|
||||
return gerr
|
||||
} else {
|
||||
return gqlerror.WrapPath(path, err)
|
||||
}
|
||||
}
|
||||
107
vendor/github.com/99designs/gqlgen/graphql/context_operation.go
generated
vendored
Normal file
107
vendor/github.com/99designs/gqlgen/graphql/context_operation.go
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
package graphql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
)
|
||||
|
||||
// Deprecated: Please update all references to OperationContext instead
|
||||
type RequestContext = OperationContext
|
||||
|
||||
type OperationContext struct {
|
||||
RawQuery string
|
||||
Variables map[string]interface{}
|
||||
OperationName string
|
||||
Doc *ast.QueryDocument
|
||||
|
||||
Operation *ast.OperationDefinition
|
||||
DisableIntrospection bool
|
||||
Recover RecoverFunc
|
||||
ResolverMiddleware FieldMiddleware
|
||||
|
||||
Stats Stats
|
||||
}
|
||||
|
||||
func (c *OperationContext) Validate(ctx context.Context) error {
|
||||
if c.Doc == nil {
|
||||
return errors.New("field 'Doc'is required")
|
||||
}
|
||||
if c.RawQuery == "" {
|
||||
return errors.New("field 'RawQuery' is required")
|
||||
}
|
||||
if c.Variables == nil {
|
||||
c.Variables = make(map[string]interface{})
|
||||
}
|
||||
if c.ResolverMiddleware == nil {
|
||||
return errors.New("field 'ResolverMiddleware' is required")
|
||||
}
|
||||
if c.Recover == nil {
|
||||
c.Recover = DefaultRecover
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
const operationCtx key = "operation_context"
|
||||
|
||||
// Deprecated: Please update all references to GetOperationContext instead
|
||||
func GetRequestContext(ctx context.Context) *RequestContext {
|
||||
return GetOperationContext(ctx)
|
||||
}
|
||||
|
||||
func GetOperationContext(ctx context.Context) *OperationContext {
|
||||
if val, ok := ctx.Value(operationCtx).(*OperationContext); ok && val != nil {
|
||||
return val
|
||||
}
|
||||
panic("missing operation context")
|
||||
}
|
||||
|
||||
func WithOperationContext(ctx context.Context, rc *OperationContext) context.Context {
|
||||
return context.WithValue(ctx, operationCtx, rc)
|
||||
}
|
||||
|
||||
// HasOperationContext checks if the given context is part of an ongoing operation
|
||||
//
|
||||
// Some errors can happen outside of an operation, eg json unmarshal errors.
|
||||
func HasOperationContext(ctx context.Context) bool {
|
||||
_, ok := ctx.Value(operationCtx).(*OperationContext)
|
||||
return ok
|
||||
}
|
||||
|
||||
// This is just a convenient wrapper method for CollectFields
|
||||
func CollectFieldsCtx(ctx context.Context, satisfies []string) []CollectedField {
|
||||
resctx := GetFieldContext(ctx)
|
||||
return CollectFields(GetOperationContext(ctx), resctx.Field.Selections, satisfies)
|
||||
}
|
||||
|
||||
// CollectAllFields returns a slice of all GraphQL field names that were selected for the current resolver context.
|
||||
// The slice will contain the unique set of all field names requested regardless of fragment type conditions.
|
||||
func CollectAllFields(ctx context.Context) []string {
|
||||
resctx := GetFieldContext(ctx)
|
||||
collected := CollectFields(GetOperationContext(ctx), resctx.Field.Selections, nil)
|
||||
uniq := make([]string, 0, len(collected))
|
||||
Next:
|
||||
for _, f := range collected {
|
||||
for _, name := range uniq {
|
||||
if name == f.Name {
|
||||
continue Next
|
||||
}
|
||||
}
|
||||
uniq = append(uniq, f.Name)
|
||||
}
|
||||
return uniq
|
||||
}
|
||||
|
||||
// Errorf sends an error string to the client, passing it through the formatter.
|
||||
// Deprecated: use graphql.AddErrorf(ctx, err) instead
|
||||
func (c *OperationContext) Errorf(ctx context.Context, format string, args ...interface{}) {
|
||||
AddErrorf(ctx, format, args...)
|
||||
}
|
||||
|
||||
// Error sends an error to the client, passing it through the formatter.
|
||||
// Deprecated: use graphql.AddError(ctx, err) instead
|
||||
func (c *OperationContext) Error(ctx context.Context, err error) {
|
||||
AddError(ctx, err)
|
||||
}
|
||||
157
vendor/github.com/99designs/gqlgen/graphql/context_response.go
generated
vendored
Normal file
157
vendor/github.com/99designs/gqlgen/graphql/context_response.go
generated
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
package graphql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
type responseContext struct {
|
||||
errorPresenter ErrorPresenterFunc
|
||||
recover RecoverFunc
|
||||
|
||||
errors gqlerror.List
|
||||
errorsMu sync.Mutex
|
||||
|
||||
extensions map[string]interface{}
|
||||
extensionsMu sync.Mutex
|
||||
}
|
||||
|
||||
const resultCtx key = "result_context"
|
||||
|
||||
func getResponseContext(ctx context.Context) *responseContext {
|
||||
val, ok := ctx.Value(resultCtx).(*responseContext)
|
||||
if !ok {
|
||||
panic("missing response context")
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
func WithResponseContext(ctx context.Context, presenterFunc ErrorPresenterFunc, recoverFunc RecoverFunc) context.Context {
|
||||
return context.WithValue(ctx, resultCtx, &responseContext{
|
||||
errorPresenter: presenterFunc,
|
||||
recover: recoverFunc,
|
||||
})
|
||||
}
|
||||
|
||||
// AddErrorf writes a formatted error to the client, first passing it through the error presenter.
|
||||
func AddErrorf(ctx context.Context, format string, args ...interface{}) {
|
||||
c := getResponseContext(ctx)
|
||||
|
||||
c.errorsMu.Lock()
|
||||
defer c.errorsMu.Unlock()
|
||||
|
||||
c.errors = append(c.errors, c.errorPresenter(ctx, fmt.Errorf(format, args...)))
|
||||
}
|
||||
|
||||
// AddError sends an error to the client, first passing it through the error presenter.
|
||||
func AddError(ctx context.Context, err error) {
|
||||
c := getResponseContext(ctx)
|
||||
|
||||
c.errorsMu.Lock()
|
||||
defer c.errorsMu.Unlock()
|
||||
|
||||
c.errors = append(c.errors, c.errorPresenter(ctx, err))
|
||||
}
|
||||
|
||||
func Recover(ctx context.Context, err interface{}) (userMessage error) {
|
||||
c := getResponseContext(ctx)
|
||||
return c.recover(ctx, err)
|
||||
}
|
||||
|
||||
// HasFieldError returns true if the given field has already errored
|
||||
func HasFieldError(ctx context.Context, rctx *FieldContext) bool {
|
||||
c := getResponseContext(ctx)
|
||||
|
||||
c.errorsMu.Lock()
|
||||
defer c.errorsMu.Unlock()
|
||||
|
||||
if len(c.errors) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
path := rctx.Path()
|
||||
for _, err := range c.errors {
|
||||
if equalPath(err.Path, path) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetFieldErrors returns a list of errors that occurred in the given field
|
||||
func GetFieldErrors(ctx context.Context, rctx *FieldContext) gqlerror.List {
|
||||
c := getResponseContext(ctx)
|
||||
|
||||
c.errorsMu.Lock()
|
||||
defer c.errorsMu.Unlock()
|
||||
|
||||
if len(c.errors) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
path := rctx.Path()
|
||||
var errs gqlerror.List
|
||||
for _, err := range c.errors {
|
||||
if equalPath(err.Path, path) {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
func GetErrors(ctx context.Context) gqlerror.List {
|
||||
resCtx := getResponseContext(ctx)
|
||||
resCtx.errorsMu.Lock()
|
||||
defer resCtx.errorsMu.Unlock()
|
||||
|
||||
if len(resCtx.errors) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
errs := resCtx.errors
|
||||
cpy := make(gqlerror.List, len(errs))
|
||||
for i := range errs {
|
||||
errCpy := *errs[i]
|
||||
cpy[i] = &errCpy
|
||||
}
|
||||
return cpy
|
||||
}
|
||||
|
||||
// RegisterExtension allows you to add a new extension into the graphql response
|
||||
func RegisterExtension(ctx context.Context, key string, value interface{}) {
|
||||
c := getResponseContext(ctx)
|
||||
c.extensionsMu.Lock()
|
||||
defer c.extensionsMu.Unlock()
|
||||
|
||||
if c.extensions == nil {
|
||||
c.extensions = make(map[string]interface{})
|
||||
}
|
||||
|
||||
if _, ok := c.extensions[key]; ok {
|
||||
panic(fmt.Errorf("extension already registered for key %s", key))
|
||||
}
|
||||
|
||||
c.extensions[key] = value
|
||||
}
|
||||
|
||||
// GetExtensions returns any extensions registered in the current result context
|
||||
func GetExtensions(ctx context.Context) map[string]interface{} {
|
||||
ext := getResponseContext(ctx).extensions
|
||||
if ext == nil {
|
||||
return map[string]interface{}{}
|
||||
}
|
||||
|
||||
return ext
|
||||
}
|
||||
|
||||
func GetExtension(ctx context.Context, name string) interface{} {
|
||||
ext := getResponseContext(ctx).extensions
|
||||
if ext == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return ext[name]
|
||||
}
|
||||
49
vendor/github.com/99designs/gqlgen/graphql/errcode/codes.go
generated
vendored
Normal file
49
vendor/github.com/99designs/gqlgen/graphql/errcode/codes.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package errcode
|
||||
|
||||
import (
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
const ValidationFailed = "GRAPHQL_VALIDATION_FAILED"
|
||||
const ParseFailed = "GRAPHQL_PARSE_FAILED"
|
||||
|
||||
type ErrorKind int
|
||||
|
||||
const (
|
||||
// issues with graphql (validation, parsing). 422s in http, GQL_ERROR in websocket
|
||||
KindProtocol ErrorKind = iota
|
||||
// user errors, 200s in http, GQL_DATA in websocket
|
||||
KindUser
|
||||
)
|
||||
|
||||
var codeType = map[string]ErrorKind{
|
||||
ValidationFailed: KindProtocol,
|
||||
ParseFailed: KindProtocol,
|
||||
}
|
||||
|
||||
// RegisterErrorType should be called by extensions that want to customize the http status codes for errors they return
|
||||
func RegisterErrorType(code string, kind ErrorKind) {
|
||||
codeType[code] = kind
|
||||
}
|
||||
|
||||
// Set the error code on a given graphql error extension
|
||||
func Set(err *gqlerror.Error, value string) {
|
||||
if err.Extensions == nil {
|
||||
err.Extensions = map[string]interface{}{}
|
||||
}
|
||||
|
||||
err.Extensions["code"] = value
|
||||
}
|
||||
|
||||
// get the kind of the first non User error, defaults to User if no errors have a custom extension
|
||||
func GetErrorKind(errs gqlerror.List) ErrorKind {
|
||||
for _, err := range errs {
|
||||
if code, ok := err.Extensions["code"].(string); ok {
|
||||
if kind, ok := codeType[code]; ok && kind != KindUser {
|
||||
return kind
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return KindUser
|
||||
}
|
||||
8
vendor/github.com/99designs/gqlgen/graphql/error.go
generated
vendored
8
vendor/github.com/99designs/gqlgen/graphql/error.go
generated
vendored
@@ -3,10 +3,10 @@ package graphql
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/vektah/gqlparser/gqlerror"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
type ErrorPresenterFunc func(context.Context, error) *gqlerror.Error
|
||||
type ErrorPresenterFunc func(ctx context.Context, err error) *gqlerror.Error
|
||||
|
||||
type ExtendedError interface {
|
||||
Extensions() map[string]interface{}
|
||||
@@ -15,7 +15,7 @@ type ExtendedError interface {
|
||||
func DefaultErrorPresenter(ctx context.Context, err error) *gqlerror.Error {
|
||||
if gqlerr, ok := err.(*gqlerror.Error); ok {
|
||||
if gqlerr.Path == nil {
|
||||
gqlerr.Path = GetResolverContext(ctx).Path()
|
||||
gqlerr.Path = GetFieldContext(ctx).Path()
|
||||
}
|
||||
return gqlerr
|
||||
}
|
||||
@@ -27,7 +27,7 @@ func DefaultErrorPresenter(ctx context.Context, err error) *gqlerror.Error {
|
||||
|
||||
return &gqlerror.Error{
|
||||
Message: err.Error(),
|
||||
Path: GetResolverContext(ctx).Path(),
|
||||
Path: GetFieldContext(ctx).Path(),
|
||||
Extensions: extensions,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
//go:generate go run github.com/matryer/moq -out executable_schema_mock.go . ExecutableSchema
|
||||
|
||||
package graphql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/vektah/gqlparser/ast"
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
)
|
||||
|
||||
type ExecutableSchema interface {
|
||||
Schema() *ast.Schema
|
||||
|
||||
Complexity(typeName, fieldName string, childComplexity int, args map[string]interface{}) (int, bool)
|
||||
Query(ctx context.Context, op *ast.OperationDefinition) *Response
|
||||
Mutation(ctx context.Context, op *ast.OperationDefinition) *Response
|
||||
Subscription(ctx context.Context, op *ast.OperationDefinition) func() *Response
|
||||
Exec(ctx context.Context) ResponseHandler
|
||||
}
|
||||
|
||||
// CollectFields returns the set of fields from an ast.SelectionSet where all collected fields satisfy at least one of the GraphQL types
|
||||
// passed through satisfies. Providing an empty or nil slice for satisfies will return collect all fields regardless of fragment
|
||||
// type conditions.
|
||||
func CollectFields(reqCtx *RequestContext, selSet ast.SelectionSet, satisfies []string) []CollectedField {
|
||||
func CollectFields(reqCtx *OperationContext, selSet ast.SelectionSet, satisfies []string) []CollectedField {
|
||||
return collectFields(reqCtx, selSet, satisfies, map[string]bool{})
|
||||
}
|
||||
|
||||
func collectFields(reqCtx *RequestContext, selSet ast.SelectionSet, satisfies []string, visited map[string]bool) []CollectedField {
|
||||
func collectFields(reqCtx *OperationContext, selSet ast.SelectionSet, satisfies []string, visited map[string]bool) []CollectedField {
|
||||
groupedFields := make([]CollectedField, 0, len(selSet))
|
||||
|
||||
for _, sel := range selSet {
|
||||
@@ -32,7 +32,7 @@ func collectFields(reqCtx *RequestContext, selSet ast.SelectionSet, satisfies []
|
||||
if !shouldIncludeNode(sel.Directives, reqCtx.Variables) {
|
||||
continue
|
||||
}
|
||||
f := getOrCreateAndAppendField(&groupedFields, sel.Alias, func() CollectedField {
|
||||
f := getOrCreateAndAppendField(&groupedFields, sel.Alias, sel.ObjectDefinition, func() CollectedField {
|
||||
return CollectedField{Field: sel}
|
||||
})
|
||||
|
||||
@@ -45,7 +45,7 @@ func collectFields(reqCtx *RequestContext, selSet ast.SelectionSet, satisfies []
|
||||
continue
|
||||
}
|
||||
for _, childField := range collectFields(reqCtx, sel.SelectionSet, satisfies, visited) {
|
||||
f := getOrCreateAndAppendField(&groupedFields, childField.Name, func() CollectedField { return childField })
|
||||
f := getOrCreateAndAppendField(&groupedFields, childField.Name, childField.ObjectDefinition, func() CollectedField { return childField })
|
||||
f.Selections = append(f.Selections, childField.Selections...)
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ func collectFields(reqCtx *RequestContext, selSet ast.SelectionSet, satisfies []
|
||||
}
|
||||
|
||||
for _, childField := range collectFields(reqCtx, fragment.SelectionSet, satisfies, visited) {
|
||||
f := getOrCreateAndAppendField(&groupedFields, childField.Name, func() CollectedField { return childField })
|
||||
f := getOrCreateAndAppendField(&groupedFields, childField.Name, childField.ObjectDefinition, func() CollectedField { return childField })
|
||||
f.Selections = append(f.Selections, childField.Selections...)
|
||||
}
|
||||
default:
|
||||
@@ -96,9 +96,9 @@ func instanceOf(val string, satisfies []string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func getOrCreateAndAppendField(c *[]CollectedField, name string, creator func() CollectedField) *CollectedField {
|
||||
func getOrCreateAndAppendField(c *[]CollectedField, name string, objectDefinition *ast.Definition, creator func() CollectedField) *CollectedField {
|
||||
for i, cf := range *c {
|
||||
if cf.Alias == name {
|
||||
if cf.Alias == name && (cf.ObjectDefinition == objectDefinition || (cf.ObjectDefinition != nil && objectDefinition != nil && cf.ObjectDefinition.Name == objectDefinition.Name)) {
|
||||
return &(*c)[i]
|
||||
}
|
||||
}
|
||||
175
vendor/github.com/99designs/gqlgen/graphql/executable_schema_mock.go
generated
vendored
Normal file
175
vendor/github.com/99designs/gqlgen/graphql/executable_schema_mock.go
generated
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
// Code generated by moq; DO NOT EDIT.
|
||||
// github.com/matryer/moq
|
||||
|
||||
package graphql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var (
|
||||
lockExecutableSchemaMockComplexity sync.RWMutex
|
||||
lockExecutableSchemaMockExec sync.RWMutex
|
||||
lockExecutableSchemaMockSchema sync.RWMutex
|
||||
)
|
||||
|
||||
// Ensure, that ExecutableSchemaMock does implement ExecutableSchema.
|
||||
// If this is not the case, regenerate this file with moq.
|
||||
var _ ExecutableSchema = &ExecutableSchemaMock{}
|
||||
|
||||
// ExecutableSchemaMock is a mock implementation of ExecutableSchema.
|
||||
//
|
||||
// func TestSomethingThatUsesExecutableSchema(t *testing.T) {
|
||||
//
|
||||
// // make and configure a mocked ExecutableSchema
|
||||
// mockedExecutableSchema := &ExecutableSchemaMock{
|
||||
// ComplexityFunc: func(typeName string, fieldName string, childComplexity int, args map[string]interface{}) (int, bool) {
|
||||
// panic("mock out the Complexity method")
|
||||
// },
|
||||
// ExecFunc: func(ctx context.Context) ResponseHandler {
|
||||
// panic("mock out the Exec method")
|
||||
// },
|
||||
// SchemaFunc: func() *ast.Schema {
|
||||
// panic("mock out the Schema method")
|
||||
// },
|
||||
// }
|
||||
//
|
||||
// // use mockedExecutableSchema in code that requires ExecutableSchema
|
||||
// // and then make assertions.
|
||||
//
|
||||
// }
|
||||
type ExecutableSchemaMock struct {
|
||||
// ComplexityFunc mocks the Complexity method.
|
||||
ComplexityFunc func(typeName string, fieldName string, childComplexity int, args map[string]interface{}) (int, bool)
|
||||
|
||||
// ExecFunc mocks the Exec method.
|
||||
ExecFunc func(ctx context.Context) ResponseHandler
|
||||
|
||||
// SchemaFunc mocks the Schema method.
|
||||
SchemaFunc func() *ast.Schema
|
||||
|
||||
// calls tracks calls to the methods.
|
||||
calls struct {
|
||||
// Complexity holds details about calls to the Complexity method.
|
||||
Complexity []struct {
|
||||
// TypeName is the typeName argument value.
|
||||
TypeName string
|
||||
// FieldName is the fieldName argument value.
|
||||
FieldName string
|
||||
// ChildComplexity is the childComplexity argument value.
|
||||
ChildComplexity int
|
||||
// Args is the args argument value.
|
||||
Args map[string]interface{}
|
||||
}
|
||||
// Exec holds details about calls to the Exec method.
|
||||
Exec []struct {
|
||||
// Ctx is the ctx argument value.
|
||||
Ctx context.Context
|
||||
}
|
||||
// Schema holds details about calls to the Schema method.
|
||||
Schema []struct {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Complexity calls ComplexityFunc.
|
||||
func (mock *ExecutableSchemaMock) Complexity(typeName string, fieldName string, childComplexity int, args map[string]interface{}) (int, bool) {
|
||||
if mock.ComplexityFunc == nil {
|
||||
panic("ExecutableSchemaMock.ComplexityFunc: method is nil but ExecutableSchema.Complexity was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
TypeName string
|
||||
FieldName string
|
||||
ChildComplexity int
|
||||
Args map[string]interface{}
|
||||
}{
|
||||
TypeName: typeName,
|
||||
FieldName: fieldName,
|
||||
ChildComplexity: childComplexity,
|
||||
Args: args,
|
||||
}
|
||||
lockExecutableSchemaMockComplexity.Lock()
|
||||
mock.calls.Complexity = append(mock.calls.Complexity, callInfo)
|
||||
lockExecutableSchemaMockComplexity.Unlock()
|
||||
return mock.ComplexityFunc(typeName, fieldName, childComplexity, args)
|
||||
}
|
||||
|
||||
// ComplexityCalls gets all the calls that were made to Complexity.
|
||||
// Check the length with:
|
||||
// len(mockedExecutableSchema.ComplexityCalls())
|
||||
func (mock *ExecutableSchemaMock) ComplexityCalls() []struct {
|
||||
TypeName string
|
||||
FieldName string
|
||||
ChildComplexity int
|
||||
Args map[string]interface{}
|
||||
} {
|
||||
var calls []struct {
|
||||
TypeName string
|
||||
FieldName string
|
||||
ChildComplexity int
|
||||
Args map[string]interface{}
|
||||
}
|
||||
lockExecutableSchemaMockComplexity.RLock()
|
||||
calls = mock.calls.Complexity
|
||||
lockExecutableSchemaMockComplexity.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// Exec calls ExecFunc.
|
||||
func (mock *ExecutableSchemaMock) Exec(ctx context.Context) ResponseHandler {
|
||||
if mock.ExecFunc == nil {
|
||||
panic("ExecutableSchemaMock.ExecFunc: method is nil but ExecutableSchema.Exec was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
Ctx context.Context
|
||||
}{
|
||||
Ctx: ctx,
|
||||
}
|
||||
lockExecutableSchemaMockExec.Lock()
|
||||
mock.calls.Exec = append(mock.calls.Exec, callInfo)
|
||||
lockExecutableSchemaMockExec.Unlock()
|
||||
return mock.ExecFunc(ctx)
|
||||
}
|
||||
|
||||
// ExecCalls gets all the calls that were made to Exec.
|
||||
// Check the length with:
|
||||
// len(mockedExecutableSchema.ExecCalls())
|
||||
func (mock *ExecutableSchemaMock) ExecCalls() []struct {
|
||||
Ctx context.Context
|
||||
} {
|
||||
var calls []struct {
|
||||
Ctx context.Context
|
||||
}
|
||||
lockExecutableSchemaMockExec.RLock()
|
||||
calls = mock.calls.Exec
|
||||
lockExecutableSchemaMockExec.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// Schema calls SchemaFunc.
|
||||
func (mock *ExecutableSchemaMock) Schema() *ast.Schema {
|
||||
if mock.SchemaFunc == nil {
|
||||
panic("ExecutableSchemaMock.SchemaFunc: method is nil but ExecutableSchema.Schema was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
}{}
|
||||
lockExecutableSchemaMockSchema.Lock()
|
||||
mock.calls.Schema = append(mock.calls.Schema, callInfo)
|
||||
lockExecutableSchemaMockSchema.Unlock()
|
||||
return mock.SchemaFunc()
|
||||
}
|
||||
|
||||
// SchemaCalls gets all the calls that were made to Schema.
|
||||
// Check the length with:
|
||||
// len(mockedExecutableSchema.SchemaCalls())
|
||||
func (mock *ExecutableSchemaMock) SchemaCalls() []struct {
|
||||
} {
|
||||
var calls []struct {
|
||||
}
|
||||
lockExecutableSchemaMockSchema.RLock()
|
||||
calls = mock.calls.Schema
|
||||
lockExecutableSchemaMockSchema.RUnlock()
|
||||
return calls
|
||||
}
|
||||
191
vendor/github.com/99designs/gqlgen/graphql/executor/executor.go
generated
vendored
Normal file
191
vendor/github.com/99designs/gqlgen/graphql/executor/executor.go
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
package executor
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/99designs/gqlgen/graphql/errcode"
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
"github.com/vektah/gqlparser/v2/parser"
|
||||
"github.com/vektah/gqlparser/v2/validator"
|
||||
)
|
||||
|
||||
// Executor executes graphql queries against a schema.
|
||||
type Executor struct {
|
||||
es graphql.ExecutableSchema
|
||||
extensions []graphql.HandlerExtension
|
||||
ext extensions
|
||||
|
||||
errorPresenter graphql.ErrorPresenterFunc
|
||||
recoverFunc graphql.RecoverFunc
|
||||
queryCache graphql.Cache
|
||||
}
|
||||
|
||||
var _ graphql.GraphExecutor = &Executor{}
|
||||
|
||||
// New creates a new Executor with the given schema, and a default error and
|
||||
// recovery callbacks, and no query cache or extensions.
|
||||
func New(es graphql.ExecutableSchema) *Executor {
|
||||
e := &Executor{
|
||||
es: es,
|
||||
errorPresenter: graphql.DefaultErrorPresenter,
|
||||
recoverFunc: graphql.DefaultRecover,
|
||||
queryCache: graphql.NoCache{},
|
||||
ext: processExtensions(nil),
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *Executor) CreateOperationContext(ctx context.Context, params *graphql.RawParams) (*graphql.OperationContext, gqlerror.List) {
|
||||
rc := &graphql.OperationContext{
|
||||
DisableIntrospection: true,
|
||||
Recover: e.recoverFunc,
|
||||
ResolverMiddleware: e.ext.fieldMiddleware,
|
||||
Stats: graphql.Stats{
|
||||
Read: params.ReadTime,
|
||||
OperationStart: graphql.GetStartTime(ctx),
|
||||
},
|
||||
}
|
||||
ctx = graphql.WithOperationContext(ctx, rc)
|
||||
|
||||
for _, p := range e.ext.operationParameterMutators {
|
||||
if err := p.MutateOperationParameters(ctx, params); err != nil {
|
||||
return rc, gqlerror.List{err}
|
||||
}
|
||||
}
|
||||
|
||||
rc.RawQuery = params.Query
|
||||
rc.OperationName = params.OperationName
|
||||
|
||||
var listErr gqlerror.List
|
||||
rc.Doc, listErr = e.parseQuery(ctx, &rc.Stats, params.Query)
|
||||
if len(listErr) != 0 {
|
||||
return rc, listErr
|
||||
}
|
||||
|
||||
rc.Operation = rc.Doc.Operations.ForName(params.OperationName)
|
||||
if rc.Operation == nil {
|
||||
return rc, gqlerror.List{gqlerror.Errorf("operation %s not found", params.OperationName)}
|
||||
}
|
||||
|
||||
var err *gqlerror.Error
|
||||
rc.Variables, err = validator.VariableValues(e.es.Schema(), rc.Operation, params.Variables)
|
||||
if err != nil {
|
||||
errcode.Set(err, errcode.ValidationFailed)
|
||||
return rc, gqlerror.List{err}
|
||||
}
|
||||
rc.Stats.Validation.End = graphql.Now()
|
||||
|
||||
for _, p := range e.ext.operationContextMutators {
|
||||
if err := p.MutateOperationContext(ctx, rc); err != nil {
|
||||
return rc, gqlerror.List{err}
|
||||
}
|
||||
}
|
||||
|
||||
return rc, nil
|
||||
}
|
||||
|
||||
func (e *Executor) DispatchOperation(ctx context.Context, rc *graphql.OperationContext) (graphql.ResponseHandler, context.Context) {
|
||||
ctx = graphql.WithOperationContext(ctx, rc)
|
||||
|
||||
var innerCtx context.Context
|
||||
res := e.ext.operationMiddleware(ctx, func(ctx context.Context) graphql.ResponseHandler {
|
||||
innerCtx = ctx
|
||||
|
||||
tmpResponseContext := graphql.WithResponseContext(ctx, e.errorPresenter, e.recoverFunc)
|
||||
responses := e.es.Exec(tmpResponseContext)
|
||||
if errs := graphql.GetErrors(tmpResponseContext); errs != nil {
|
||||
return graphql.OneShot(&graphql.Response{Errors: errs})
|
||||
}
|
||||
|
||||
return func(ctx context.Context) *graphql.Response {
|
||||
ctx = graphql.WithResponseContext(ctx, e.errorPresenter, e.recoverFunc)
|
||||
resp := e.ext.responseMiddleware(ctx, func(ctx context.Context) *graphql.Response {
|
||||
resp := responses(ctx)
|
||||
if resp == nil {
|
||||
return nil
|
||||
}
|
||||
resp.Errors = append(resp.Errors, graphql.GetErrors(ctx)...)
|
||||
resp.Extensions = graphql.GetExtensions(ctx)
|
||||
return resp
|
||||
})
|
||||
if resp == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return resp
|
||||
}
|
||||
})
|
||||
|
||||
return res, innerCtx
|
||||
}
|
||||
|
||||
func (e *Executor) DispatchError(ctx context.Context, list gqlerror.List) *graphql.Response {
|
||||
ctx = graphql.WithResponseContext(ctx, e.errorPresenter, e.recoverFunc)
|
||||
for _, gErr := range list {
|
||||
graphql.AddError(ctx, gErr)
|
||||
}
|
||||
|
||||
resp := e.ext.responseMiddleware(ctx, func(ctx context.Context) *graphql.Response {
|
||||
resp := &graphql.Response{
|
||||
Errors: list,
|
||||
}
|
||||
resp.Extensions = graphql.GetExtensions(ctx)
|
||||
return resp
|
||||
})
|
||||
|
||||
return resp
|
||||
}
|
||||
|
||||
func (e *Executor) PresentRecoveredError(ctx context.Context, err interface{}) *gqlerror.Error {
|
||||
return e.errorPresenter(ctx, e.recoverFunc(ctx, err))
|
||||
}
|
||||
|
||||
func (e *Executor) SetQueryCache(cache graphql.Cache) {
|
||||
e.queryCache = cache
|
||||
}
|
||||
|
||||
func (e *Executor) SetErrorPresenter(f graphql.ErrorPresenterFunc) {
|
||||
e.errorPresenter = f
|
||||
}
|
||||
|
||||
func (e *Executor) SetRecoverFunc(f graphql.RecoverFunc) {
|
||||
e.recoverFunc = f
|
||||
}
|
||||
|
||||
// parseQuery decodes the incoming query and validates it, pulling from cache if present.
|
||||
//
|
||||
// NOTE: This should NOT look at variables, they will change per request. It should only parse and validate
|
||||
// the raw query string.
|
||||
func (e *Executor) parseQuery(ctx context.Context, stats *graphql.Stats, query string) (*ast.QueryDocument, gqlerror.List) {
|
||||
stats.Parsing.Start = graphql.Now()
|
||||
|
||||
if doc, ok := e.queryCache.Get(ctx, query); ok {
|
||||
now := graphql.Now()
|
||||
|
||||
stats.Parsing.End = now
|
||||
stats.Validation.Start = now
|
||||
return doc.(*ast.QueryDocument), nil
|
||||
}
|
||||
|
||||
doc, err := parser.ParseQuery(&ast.Source{Input: query})
|
||||
if err != nil {
|
||||
errcode.Set(err, errcode.ParseFailed)
|
||||
return nil, gqlerror.List{err}
|
||||
}
|
||||
stats.Parsing.End = graphql.Now()
|
||||
|
||||
stats.Validation.Start = graphql.Now()
|
||||
listErr := validator.Validate(e.es.Schema(), doc)
|
||||
if len(listErr) != 0 {
|
||||
for _, e := range listErr {
|
||||
errcode.Set(e, errcode.ValidationFailed)
|
||||
}
|
||||
return nil, listErr
|
||||
}
|
||||
|
||||
e.queryCache.Add(ctx, query, doc)
|
||||
|
||||
return doc, nil
|
||||
}
|
||||
159
vendor/github.com/99designs/gqlgen/graphql/executor/extensions.go
generated
vendored
Normal file
159
vendor/github.com/99designs/gqlgen/graphql/executor/extensions.go
generated
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
package executor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
)
|
||||
|
||||
// Use adds the given extension to this Executor.
|
||||
func (e *Executor) Use(extension graphql.HandlerExtension) {
|
||||
if err := extension.Validate(e.es); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
switch extension.(type) {
|
||||
case graphql.OperationParameterMutator,
|
||||
graphql.OperationContextMutator,
|
||||
graphql.OperationInterceptor,
|
||||
graphql.FieldInterceptor,
|
||||
graphql.ResponseInterceptor:
|
||||
e.extensions = append(e.extensions, extension)
|
||||
e.ext = processExtensions(e.extensions)
|
||||
|
||||
default:
|
||||
panic(fmt.Errorf("cannot Use %T as a gqlgen handler extension because it does not implement any extension hooks", extension))
|
||||
}
|
||||
}
|
||||
|
||||
// AroundFields is a convenience method for creating an extension that only implements field middleware
|
||||
func (e *Executor) AroundFields(f graphql.FieldMiddleware) {
|
||||
e.Use(aroundFieldFunc(f))
|
||||
}
|
||||
|
||||
// AroundOperations is a convenience method for creating an extension that only implements operation middleware
|
||||
func (e *Executor) AroundOperations(f graphql.OperationMiddleware) {
|
||||
e.Use(aroundOpFunc(f))
|
||||
}
|
||||
|
||||
// AroundResponses is a convenience method for creating an extension that only implements response middleware
|
||||
func (e *Executor) AroundResponses(f graphql.ResponseMiddleware) {
|
||||
e.Use(aroundRespFunc(f))
|
||||
}
|
||||
|
||||
type extensions struct {
|
||||
operationMiddleware graphql.OperationMiddleware
|
||||
responseMiddleware graphql.ResponseMiddleware
|
||||
fieldMiddleware graphql.FieldMiddleware
|
||||
operationParameterMutators []graphql.OperationParameterMutator
|
||||
operationContextMutators []graphql.OperationContextMutator
|
||||
}
|
||||
|
||||
func processExtensions(exts []graphql.HandlerExtension) extensions {
|
||||
e := extensions{
|
||||
operationMiddleware: func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler {
|
||||
return next(ctx)
|
||||
},
|
||||
responseMiddleware: func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
|
||||
return next(ctx)
|
||||
},
|
||||
fieldMiddleware: func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
|
||||
return next(ctx)
|
||||
},
|
||||
}
|
||||
|
||||
// this loop goes backwards so the first extension is the outer most middleware and runs first.
|
||||
for i := len(exts) - 1; i >= 0; i-- {
|
||||
p := exts[i]
|
||||
if p, ok := p.(graphql.OperationInterceptor); ok {
|
||||
previous := e.operationMiddleware
|
||||
e.operationMiddleware = func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler {
|
||||
return p.InterceptOperation(ctx, func(ctx context.Context) graphql.ResponseHandler {
|
||||
return previous(ctx, next)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if p, ok := p.(graphql.ResponseInterceptor); ok {
|
||||
previous := e.responseMiddleware
|
||||
e.responseMiddleware = func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
|
||||
return p.InterceptResponse(ctx, func(ctx context.Context) *graphql.Response {
|
||||
return previous(ctx, next)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if p, ok := p.(graphql.FieldInterceptor); ok {
|
||||
previous := e.fieldMiddleware
|
||||
e.fieldMiddleware = func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
|
||||
return p.InterceptField(ctx, func(ctx context.Context) (res interface{}, err error) {
|
||||
return previous(ctx, next)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, p := range exts {
|
||||
if p, ok := p.(graphql.OperationParameterMutator); ok {
|
||||
e.operationParameterMutators = append(e.operationParameterMutators, p)
|
||||
}
|
||||
|
||||
if p, ok := p.(graphql.OperationContextMutator); ok {
|
||||
e.operationContextMutators = append(e.operationContextMutators, p)
|
||||
}
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
type aroundOpFunc func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler
|
||||
|
||||
func (r aroundOpFunc) ExtensionName() string {
|
||||
return "InlineOperationFunc"
|
||||
}
|
||||
|
||||
func (r aroundOpFunc) Validate(schema graphql.ExecutableSchema) error {
|
||||
if r == nil {
|
||||
return fmt.Errorf("OperationFunc can not be nil")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r aroundOpFunc) InterceptOperation(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler {
|
||||
return r(ctx, next)
|
||||
}
|
||||
|
||||
type aroundRespFunc func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response
|
||||
|
||||
func (r aroundRespFunc) ExtensionName() string {
|
||||
return "InlineResponseFunc"
|
||||
}
|
||||
|
||||
func (r aroundRespFunc) Validate(schema graphql.ExecutableSchema) error {
|
||||
if r == nil {
|
||||
return fmt.Errorf("ResponseFunc can not be nil")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r aroundRespFunc) InterceptResponse(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
|
||||
return r(ctx, next)
|
||||
}
|
||||
|
||||
type aroundFieldFunc func(ctx context.Context, next graphql.Resolver) (res interface{}, err error)
|
||||
|
||||
func (f aroundFieldFunc) ExtensionName() string {
|
||||
return "InlineFieldFunc"
|
||||
}
|
||||
|
||||
func (f aroundFieldFunc) Validate(schema graphql.ExecutableSchema) error {
|
||||
if f == nil {
|
||||
return fmt.Errorf("FieldFunc can not be nil")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f aroundFieldFunc) InterceptField(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
|
||||
return f(ctx, next)
|
||||
}
|
||||
123
vendor/github.com/99designs/gqlgen/graphql/handler.go
generated
vendored
Normal file
123
vendor/github.com/99designs/gqlgen/graphql/handler.go
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
package graphql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
type (
|
||||
OperationMiddleware func(ctx context.Context, next OperationHandler) ResponseHandler
|
||||
OperationHandler func(ctx context.Context) ResponseHandler
|
||||
|
||||
ResponseHandler func(ctx context.Context) *Response
|
||||
ResponseMiddleware func(ctx context.Context, next ResponseHandler) *Response
|
||||
|
||||
Resolver func(ctx context.Context) (res interface{}, err error)
|
||||
FieldMiddleware func(ctx context.Context, next Resolver) (res interface{}, err error)
|
||||
|
||||
RawParams struct {
|
||||
Query string `json:"query"`
|
||||
OperationName string `json:"operationName"`
|
||||
Variables map[string]interface{} `json:"variables"`
|
||||
Extensions map[string]interface{} `json:"extensions"`
|
||||
|
||||
ReadTime TraceTiming `json:"-"`
|
||||
}
|
||||
|
||||
GraphExecutor interface {
|
||||
CreateOperationContext(ctx context.Context, params *RawParams) (*OperationContext, gqlerror.List)
|
||||
DispatchOperation(ctx context.Context, rc *OperationContext) (ResponseHandler, context.Context)
|
||||
DispatchError(ctx context.Context, list gqlerror.List) *Response
|
||||
}
|
||||
|
||||
// HandlerExtension adds functionality to the http handler. See the list of possible hook points below
|
||||
// Its important to understand the lifecycle of a graphql request and the terminology we use in gqlgen
|
||||
// before working with these
|
||||
//
|
||||
// +--- REQUEST POST /graphql --------------------------------------------+
|
||||
// | +- OPERATION query OpName { viewer { name } } -----------------------+ |
|
||||
// | | RESPONSE { "data": { "viewer": { "name": "bob" } } } | |
|
||||
// | +- OPERATION subscription OpName2 { chat { message } } --------------+ |
|
||||
// | | RESPONSE { "data": { "chat": { "message": "hello" } } } | |
|
||||
// | | RESPONSE { "data": { "chat": { "message": "byee" } } } | |
|
||||
// | +--------------------------------------------------------------------+ |
|
||||
// +------------------------------------------------------------------------+
|
||||
HandlerExtension interface {
|
||||
// ExtensionName should be a CamelCase string version of the extension which may be shown in stats and logging.
|
||||
ExtensionName() string
|
||||
// Validate is called when adding an extension to the server, it allows validation against the servers schema.
|
||||
Validate(schema ExecutableSchema) error
|
||||
}
|
||||
|
||||
// OperationParameterMutator is called before creating a request context. allows manipulating the raw query
|
||||
// on the way in.
|
||||
OperationParameterMutator interface {
|
||||
MutateOperationParameters(ctx context.Context, request *RawParams) *gqlerror.Error
|
||||
}
|
||||
|
||||
// OperationContextMutator is called after creating the request context, but before executing the root resolver.
|
||||
OperationContextMutator interface {
|
||||
MutateOperationContext(ctx context.Context, rc *OperationContext) *gqlerror.Error
|
||||
}
|
||||
|
||||
// OperationInterceptor is called for each incoming query, for basic requests the writer will be invoked once,
|
||||
// for subscriptions it will be invoked multiple times.
|
||||
OperationInterceptor interface {
|
||||
InterceptOperation(ctx context.Context, next OperationHandler) ResponseHandler
|
||||
}
|
||||
|
||||
// ResponseInterceptor is called around each graphql operation response. This can be called many times for a single
|
||||
// operation the case of subscriptions.
|
||||
ResponseInterceptor interface {
|
||||
InterceptResponse(ctx context.Context, next ResponseHandler) *Response
|
||||
}
|
||||
|
||||
// FieldInterceptor called around each field
|
||||
FieldInterceptor interface {
|
||||
InterceptField(ctx context.Context, next Resolver) (res interface{}, err error)
|
||||
}
|
||||
|
||||
// Transport provides support for different wire level encodings of graphql requests, eg Form, Get, Post, Websocket
|
||||
Transport interface {
|
||||
Supports(r *http.Request) bool
|
||||
Do(w http.ResponseWriter, r *http.Request, exec GraphExecutor)
|
||||
}
|
||||
)
|
||||
|
||||
type Status int
|
||||
|
||||
func (p *RawParams) AddUpload(upload Upload, key, path string) *gqlerror.Error {
|
||||
if !strings.HasPrefix(path, "variables.") {
|
||||
return gqlerror.Errorf("invalid operations paths for key %s", key)
|
||||
}
|
||||
|
||||
var ptr interface{} = p.Variables
|
||||
parts := strings.Split(path, ".")
|
||||
|
||||
// skip the first part (variables) because we started there
|
||||
for i, p := range parts[1:] {
|
||||
last := i == len(parts)-2
|
||||
if ptr == nil {
|
||||
return gqlerror.Errorf("path is missing \"variables.\" prefix, key: %s, path: %s", key, path)
|
||||
}
|
||||
if index, parseNbrErr := strconv.Atoi(p); parseNbrErr == nil {
|
||||
if last {
|
||||
ptr.([]interface{})[index] = upload
|
||||
} else {
|
||||
ptr = ptr.([]interface{})[index]
|
||||
}
|
||||
} else {
|
||||
if last {
|
||||
ptr.(map[string]interface{})[p] = upload
|
||||
} else {
|
||||
ptr = ptr.(map[string]interface{})[p]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
112
vendor/github.com/99designs/gqlgen/graphql/handler/extension/apq.go
generated
vendored
Normal file
112
vendor/github.com/99designs/gqlgen/graphql/handler/extension/apq.go
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
package extension
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql/errcode"
|
||||
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
)
|
||||
|
||||
const errPersistedQueryNotFound = "PersistedQueryNotFound"
|
||||
const errPersistedQueryNotFoundCode = "PERSISTED_QUERY_NOT_FOUND"
|
||||
|
||||
// AutomaticPersistedQuery saves client upload by optimistically sending only the hashes of queries, if the server
|
||||
// does not yet know what the query is for the hash it will respond telling the client to send the query along with the
|
||||
// hash in the next request.
|
||||
// see https://github.com/apollographql/apollo-link-persisted-queries
|
||||
type AutomaticPersistedQuery struct {
|
||||
Cache graphql.Cache
|
||||
}
|
||||
|
||||
type ApqStats struct {
|
||||
// The hash of the incoming query
|
||||
Hash string
|
||||
|
||||
// SentQuery is true if the incoming request sent the full query
|
||||
SentQuery bool
|
||||
}
|
||||
|
||||
const apqExtension = "APQ"
|
||||
|
||||
var _ interface {
|
||||
graphql.OperationParameterMutator
|
||||
graphql.HandlerExtension
|
||||
} = AutomaticPersistedQuery{}
|
||||
|
||||
func (a AutomaticPersistedQuery) ExtensionName() string {
|
||||
return "AutomaticPersistedQuery"
|
||||
}
|
||||
|
||||
func (a AutomaticPersistedQuery) Validate(schema graphql.ExecutableSchema) error {
|
||||
if a.Cache == nil {
|
||||
return fmt.Errorf("AutomaticPersistedQuery.Cache can not be nil")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a AutomaticPersistedQuery) MutateOperationParameters(ctx context.Context, rawParams *graphql.RawParams) *gqlerror.Error {
|
||||
if rawParams.Extensions["persistedQuery"] == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var extension struct {
|
||||
Sha256 string `mapstructure:"sha256Hash"`
|
||||
Version int64 `mapstructure:"version"`
|
||||
}
|
||||
|
||||
if err := mapstructure.Decode(rawParams.Extensions["persistedQuery"], &extension); err != nil {
|
||||
return gqlerror.Errorf("invalid APQ extension data")
|
||||
}
|
||||
|
||||
if extension.Version != 1 {
|
||||
return gqlerror.Errorf("unsupported APQ version")
|
||||
}
|
||||
|
||||
fullQuery := false
|
||||
if rawParams.Query == "" {
|
||||
// client sent optimistic query hash without query string, get it from the cache
|
||||
query, ok := a.Cache.Get(ctx, extension.Sha256)
|
||||
if !ok {
|
||||
err := gqlerror.Errorf(errPersistedQueryNotFound)
|
||||
errcode.Set(err, errPersistedQueryNotFoundCode)
|
||||
return err
|
||||
}
|
||||
rawParams.Query = query.(string)
|
||||
} else {
|
||||
// client sent optimistic query hash with query string, verify and store it
|
||||
if computeQueryHash(rawParams.Query) != extension.Sha256 {
|
||||
return gqlerror.Errorf("provided APQ hash does not match query")
|
||||
}
|
||||
a.Cache.Add(ctx, extension.Sha256, rawParams.Query)
|
||||
fullQuery = true
|
||||
}
|
||||
|
||||
graphql.GetOperationContext(ctx).Stats.SetExtension(apqExtension, &ApqStats{
|
||||
Hash: extension.Sha256,
|
||||
SentQuery: fullQuery,
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetApqStats(ctx context.Context) *ApqStats {
|
||||
rc := graphql.GetOperationContext(ctx)
|
||||
if rc == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
s, _ := rc.Stats.GetExtension(apqExtension).(*ApqStats)
|
||||
return s
|
||||
}
|
||||
|
||||
func computeQueryHash(query string) string {
|
||||
b := sha256.Sum256([]byte(query))
|
||||
return hex.EncodeToString(b[:])
|
||||
}
|
||||
88
vendor/github.com/99designs/gqlgen/graphql/handler/extension/complexity.go
generated
vendored
Normal file
88
vendor/github.com/99designs/gqlgen/graphql/handler/extension/complexity.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
package extension
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/99designs/gqlgen/complexity"
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/99designs/gqlgen/graphql/errcode"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
const errComplexityLimit = "COMPLEXITY_LIMIT_EXCEEDED"
|
||||
|
||||
// ComplexityLimit allows you to define a limit on query complexity
|
||||
//
|
||||
// If a query is submitted that exceeds the limit, a 422 status code will be returned.
|
||||
type ComplexityLimit struct {
|
||||
Func func(ctx context.Context, rc *graphql.OperationContext) int
|
||||
|
||||
es graphql.ExecutableSchema
|
||||
}
|
||||
|
||||
var _ interface {
|
||||
graphql.OperationContextMutator
|
||||
graphql.HandlerExtension
|
||||
} = &ComplexityLimit{}
|
||||
|
||||
const complexityExtension = "ComplexityLimit"
|
||||
|
||||
type ComplexityStats struct {
|
||||
// The calculated complexity for this request
|
||||
Complexity int
|
||||
|
||||
// The complexity limit for this request returned by the extension func
|
||||
ComplexityLimit int
|
||||
}
|
||||
|
||||
// FixedComplexityLimit sets a complexity limit that does not change
|
||||
func FixedComplexityLimit(limit int) *ComplexityLimit {
|
||||
return &ComplexityLimit{
|
||||
Func: func(ctx context.Context, rc *graphql.OperationContext) int {
|
||||
return limit
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c ComplexityLimit) ExtensionName() string {
|
||||
return complexityExtension
|
||||
}
|
||||
|
||||
func (c *ComplexityLimit) Validate(schema graphql.ExecutableSchema) error {
|
||||
if c.Func == nil {
|
||||
return fmt.Errorf("ComplexityLimit func can not be nil")
|
||||
}
|
||||
c.es = schema
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c ComplexityLimit) MutateOperationContext(ctx context.Context, rc *graphql.OperationContext) *gqlerror.Error {
|
||||
op := rc.Doc.Operations.ForName(rc.OperationName)
|
||||
complexity := complexity.Calculate(c.es, op, rc.Variables)
|
||||
|
||||
limit := c.Func(ctx, rc)
|
||||
|
||||
rc.Stats.SetExtension(complexityExtension, &ComplexityStats{
|
||||
Complexity: complexity,
|
||||
ComplexityLimit: limit,
|
||||
})
|
||||
|
||||
if complexity > limit {
|
||||
err := gqlerror.Errorf("operation has complexity %d, which exceeds the limit of %d", complexity, limit)
|
||||
errcode.Set(err, errComplexityLimit)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetComplexityStats(ctx context.Context) *ComplexityStats {
|
||||
rc := graphql.GetOperationContext(ctx)
|
||||
if rc == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
s, _ := rc.Stats.GetExtension(complexityExtension).(*ComplexityStats)
|
||||
return s
|
||||
}
|
||||
29
vendor/github.com/99designs/gqlgen/graphql/handler/extension/introspection.go
generated
vendored
Normal file
29
vendor/github.com/99designs/gqlgen/graphql/handler/extension/introspection.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
package extension
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
// EnableIntrospection enables clients to reflect all of the types available on the graph.
|
||||
type Introspection struct{}
|
||||
|
||||
var _ interface {
|
||||
graphql.OperationContextMutator
|
||||
graphql.HandlerExtension
|
||||
} = Introspection{}
|
||||
|
||||
func (c Introspection) ExtensionName() string {
|
||||
return "Introspection"
|
||||
}
|
||||
|
||||
func (c Introspection) Validate(schema graphql.ExecutableSchema) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c Introspection) MutateOperationContext(ctx context.Context, rc *graphql.OperationContext) *gqlerror.Error {
|
||||
rc.DisableIntrospection = false
|
||||
return nil
|
||||
}
|
||||
32
vendor/github.com/99designs/gqlgen/graphql/handler/lru/lru.go
generated
vendored
Normal file
32
vendor/github.com/99designs/gqlgen/graphql/handler/lru/lru.go
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
package lru
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
)
|
||||
|
||||
type LRU struct {
|
||||
lru *lru.Cache
|
||||
}
|
||||
|
||||
var _ graphql.Cache = &LRU{}
|
||||
|
||||
func New(size int) *LRU {
|
||||
cache, err := lru.New(size)
|
||||
if err != nil {
|
||||
// An error is only returned for non-positive cache size
|
||||
// and we already checked for that.
|
||||
panic("unexpected error creating cache: " + err.Error())
|
||||
}
|
||||
return &LRU{cache}
|
||||
}
|
||||
|
||||
func (l LRU) Get(ctx context.Context, key string) (value interface{}, ok bool) {
|
||||
return l.lru.Get(key)
|
||||
}
|
||||
|
||||
func (l LRU) Add(ctx context.Context, key string, value interface{}) {
|
||||
l.lru.Add(key, value)
|
||||
}
|
||||
180
vendor/github.com/99designs/gqlgen/graphql/handler/server.go
generated
vendored
Normal file
180
vendor/github.com/99designs/gqlgen/graphql/handler/server.go
generated
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/99designs/gqlgen/graphql/executor"
|
||||
"github.com/99designs/gqlgen/graphql/handler/extension"
|
||||
"github.com/99designs/gqlgen/graphql/handler/lru"
|
||||
"github.com/99designs/gqlgen/graphql/handler/transport"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
type (
|
||||
Server struct {
|
||||
transports []graphql.Transport
|
||||
exec *executor.Executor
|
||||
}
|
||||
)
|
||||
|
||||
func New(es graphql.ExecutableSchema) *Server {
|
||||
return &Server{
|
||||
exec: executor.New(es),
|
||||
}
|
||||
}
|
||||
|
||||
func NewDefaultServer(es graphql.ExecutableSchema) *Server {
|
||||
srv := New(es)
|
||||
|
||||
srv.AddTransport(transport.Websocket{
|
||||
KeepAlivePingInterval: 10 * time.Second,
|
||||
})
|
||||
srv.AddTransport(transport.Options{})
|
||||
srv.AddTransport(transport.GET{})
|
||||
srv.AddTransport(transport.POST{})
|
||||
srv.AddTransport(transport.MultipartForm{})
|
||||
|
||||
srv.SetQueryCache(lru.New(1000))
|
||||
|
||||
srv.Use(extension.Introspection{})
|
||||
srv.Use(extension.AutomaticPersistedQuery{
|
||||
Cache: lru.New(100),
|
||||
})
|
||||
|
||||
return srv
|
||||
}
|
||||
|
||||
func (s *Server) AddTransport(transport graphql.Transport) {
|
||||
s.transports = append(s.transports, transport)
|
||||
}
|
||||
|
||||
func (s *Server) SetErrorPresenter(f graphql.ErrorPresenterFunc) {
|
||||
s.exec.SetErrorPresenter(f)
|
||||
}
|
||||
|
||||
func (s *Server) SetRecoverFunc(f graphql.RecoverFunc) {
|
||||
s.exec.SetRecoverFunc(f)
|
||||
}
|
||||
|
||||
func (s *Server) SetQueryCache(cache graphql.Cache) {
|
||||
s.exec.SetQueryCache(cache)
|
||||
}
|
||||
|
||||
func (s *Server) Use(extension graphql.HandlerExtension) {
|
||||
s.exec.Use(extension)
|
||||
}
|
||||
|
||||
// AroundFields is a convenience method for creating an extension that only implements field middleware
|
||||
func (s *Server) AroundFields(f graphql.FieldMiddleware) {
|
||||
s.exec.AroundFields(f)
|
||||
}
|
||||
|
||||
// AroundOperations is a convenience method for creating an extension that only implements operation middleware
|
||||
func (s *Server) AroundOperations(f graphql.OperationMiddleware) {
|
||||
s.exec.AroundOperations(f)
|
||||
}
|
||||
|
||||
// AroundResponses is a convenience method for creating an extension that only implements response middleware
|
||||
func (s *Server) AroundResponses(f graphql.ResponseMiddleware) {
|
||||
s.exec.AroundResponses(f)
|
||||
}
|
||||
|
||||
func (s *Server) getTransport(r *http.Request) graphql.Transport {
|
||||
for _, t := range s.transports {
|
||||
if t.Supports(r) {
|
||||
return t
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
err := s.exec.PresentRecoveredError(r.Context(), err)
|
||||
resp := &graphql.Response{Errors: []*gqlerror.Error{err}}
|
||||
b, _ := json.Marshal(resp)
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
w.Write(b)
|
||||
}
|
||||
}()
|
||||
|
||||
r = r.WithContext(graphql.StartOperationTrace(r.Context()))
|
||||
|
||||
transport := s.getTransport(r)
|
||||
if transport == nil {
|
||||
sendErrorf(w, http.StatusBadRequest, "transport not supported")
|
||||
return
|
||||
}
|
||||
|
||||
transport.Do(w, r, s.exec)
|
||||
}
|
||||
|
||||
func sendError(w http.ResponseWriter, code int, errors ...*gqlerror.Error) {
|
||||
w.WriteHeader(code)
|
||||
b, err := json.Marshal(&graphql.Response{Errors: errors})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
w.Write(b)
|
||||
}
|
||||
|
||||
func sendErrorf(w http.ResponseWriter, code int, format string, args ...interface{}) {
|
||||
sendError(w, code, &gqlerror.Error{Message: fmt.Sprintf(format, args...)})
|
||||
}
|
||||
|
||||
type OperationFunc func(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler
|
||||
|
||||
func (r OperationFunc) ExtensionName() string {
|
||||
return "InlineOperationFunc"
|
||||
}
|
||||
|
||||
func (r OperationFunc) Validate(schema graphql.ExecutableSchema) error {
|
||||
if r == nil {
|
||||
return fmt.Errorf("OperationFunc can not be nil")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r OperationFunc) InterceptOperation(ctx context.Context, next graphql.OperationHandler) graphql.ResponseHandler {
|
||||
return r(ctx, next)
|
||||
}
|
||||
|
||||
type ResponseFunc func(ctx context.Context, next graphql.ResponseHandler) *graphql.Response
|
||||
|
||||
func (r ResponseFunc) ExtensionName() string {
|
||||
return "InlineResponseFunc"
|
||||
}
|
||||
|
||||
func (r ResponseFunc) Validate(schema graphql.ExecutableSchema) error {
|
||||
if r == nil {
|
||||
return fmt.Errorf("ResponseFunc can not be nil")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r ResponseFunc) InterceptResponse(ctx context.Context, next graphql.ResponseHandler) *graphql.Response {
|
||||
return r(ctx, next)
|
||||
}
|
||||
|
||||
type FieldFunc func(ctx context.Context, next graphql.Resolver) (res interface{}, err error)
|
||||
|
||||
func (f FieldFunc) ExtensionName() string {
|
||||
return "InlineFieldFunc"
|
||||
}
|
||||
|
||||
func (f FieldFunc) Validate(schema graphql.ExecutableSchema) error {
|
||||
if f == nil {
|
||||
return fmt.Errorf("FieldFunc can not be nil")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f FieldFunc) InterceptField(ctx context.Context, next graphql.Resolver) (res interface{}, err error) {
|
||||
return f(ctx, next)
|
||||
}
|
||||
26
vendor/github.com/99designs/gqlgen/graphql/handler/transport/error.go
generated
vendored
Normal file
26
vendor/github.com/99designs/gqlgen/graphql/handler/transport/error.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
// SendError sends a best effort error to a raw response writer. It assumes the client can understand the standard
|
||||
// json error response
|
||||
func SendError(w http.ResponseWriter, code int, errors ...*gqlerror.Error) {
|
||||
w.WriteHeader(code)
|
||||
b, err := json.Marshal(&graphql.Response{Errors: errors})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
w.Write(b)
|
||||
}
|
||||
|
||||
// SendErrorf wraps SendError to add formatted messages
|
||||
func SendErrorf(w http.ResponseWriter, code int, format string, args ...interface{}) {
|
||||
SendError(w, code, &gqlerror.Error{Message: fmt.Sprintf(format, args...)})
|
||||
}
|
||||
208
vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_form.go
generated
vendored
Normal file
208
vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_form.go
generated
vendored
Normal file
@@ -0,0 +1,208 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
)
|
||||
|
||||
// MultipartForm the Multipart request spec https://github.com/jaydenseric/graphql-multipart-request-spec
|
||||
type MultipartForm struct {
|
||||
// MaxUploadSize sets the maximum number of bytes used to parse a request body
|
||||
// as multipart/form-data.
|
||||
MaxUploadSize int64
|
||||
|
||||
// MaxMemory defines the maximum number of bytes used to parse a request body
|
||||
// as multipart/form-data in memory, with the remainder stored on disk in
|
||||
// temporary files.
|
||||
MaxMemory int64
|
||||
}
|
||||
|
||||
var _ graphql.Transport = MultipartForm{}
|
||||
|
||||
func (f MultipartForm) Supports(r *http.Request) bool {
|
||||
if r.Header.Get("Upgrade") != "" {
|
||||
return false
|
||||
}
|
||||
|
||||
mediaType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return r.Method == "POST" && mediaType == "multipart/form-data"
|
||||
}
|
||||
|
||||
func (f MultipartForm) maxUploadSize() int64 {
|
||||
if f.MaxUploadSize == 0 {
|
||||
return 32 << 20
|
||||
}
|
||||
return f.MaxUploadSize
|
||||
}
|
||||
|
||||
func (f MultipartForm) maxMemory() int64 {
|
||||
if f.MaxMemory == 0 {
|
||||
return 32 << 20
|
||||
}
|
||||
return f.MaxMemory
|
||||
}
|
||||
|
||||
func (f MultipartForm) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
start := graphql.Now()
|
||||
|
||||
var err error
|
||||
if r.ContentLength > f.maxUploadSize() {
|
||||
writeJsonError(w, "failed to parse multipart form, request body too large")
|
||||
return
|
||||
}
|
||||
r.Body = http.MaxBytesReader(w, r.Body, f.maxUploadSize())
|
||||
if err = r.ParseMultipartForm(f.maxMemory()); err != nil {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
if strings.Contains(err.Error(), "request body too large") {
|
||||
writeJsonError(w, "failed to parse multipart form, request body too large")
|
||||
return
|
||||
}
|
||||
writeJsonError(w, "failed to parse multipart form")
|
||||
return
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
var params graphql.RawParams
|
||||
|
||||
if err = jsonDecode(strings.NewReader(r.Form.Get("operations")), ¶ms); err != nil {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
writeJsonError(w, "operations form field could not be decoded")
|
||||
return
|
||||
}
|
||||
|
||||
var uploadsMap = map[string][]string{}
|
||||
if err = json.Unmarshal([]byte(r.Form.Get("map")), &uploadsMap); err != nil {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
writeJsonError(w, "map form field could not be decoded")
|
||||
return
|
||||
}
|
||||
|
||||
var upload graphql.Upload
|
||||
for key, paths := range uploadsMap {
|
||||
if len(paths) == 0 {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
writeJsonErrorf(w, "invalid empty operations paths list for key %s", key)
|
||||
return
|
||||
}
|
||||
file, header, err := r.FormFile(key)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
writeJsonErrorf(w, "failed to get key %s from form", key)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
if len(paths) == 1 {
|
||||
upload = graphql.Upload{
|
||||
File: file,
|
||||
Size: header.Size,
|
||||
Filename: header.Filename,
|
||||
ContentType: header.Header.Get("Content-Type"),
|
||||
}
|
||||
|
||||
if err := params.AddUpload(upload, key, paths[0]); err != nil {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
writeJsonGraphqlError(w, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if r.ContentLength < f.maxMemory() {
|
||||
fileBytes, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
writeJsonErrorf(w, "failed to read file for key %s", key)
|
||||
return
|
||||
}
|
||||
for _, path := range paths {
|
||||
upload = graphql.Upload{
|
||||
File: &bytesReader{s: &fileBytes, i: 0, prevRune: -1},
|
||||
Size: header.Size,
|
||||
Filename: header.Filename,
|
||||
ContentType: header.Header.Get("Content-Type"),
|
||||
}
|
||||
|
||||
if err := params.AddUpload(upload, key, path); err != nil {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
writeJsonGraphqlError(w, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tmpFile, err := ioutil.TempFile(os.TempDir(), "gqlgen-")
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
writeJsonErrorf(w, "failed to create temp file for key %s", key)
|
||||
return
|
||||
}
|
||||
tmpName := tmpFile.Name()
|
||||
defer func() {
|
||||
_ = os.Remove(tmpName)
|
||||
}()
|
||||
_, err = io.Copy(tmpFile, file)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
if err := tmpFile.Close(); err != nil {
|
||||
writeJsonErrorf(w, "failed to copy to temp file and close temp file for key %s", key)
|
||||
return
|
||||
}
|
||||
writeJsonErrorf(w, "failed to copy to temp file for key %s", key)
|
||||
return
|
||||
}
|
||||
if err := tmpFile.Close(); err != nil {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
writeJsonErrorf(w, "failed to close temp file for key %s", key)
|
||||
return
|
||||
}
|
||||
for _, path := range paths {
|
||||
pathTmpFile, err := os.Open(tmpName)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
writeJsonErrorf(w, "failed to open temp file for key %s", key)
|
||||
return
|
||||
}
|
||||
defer pathTmpFile.Close()
|
||||
upload = graphql.Upload{
|
||||
File: pathTmpFile,
|
||||
Size: header.Size,
|
||||
Filename: header.Filename,
|
||||
ContentType: header.Header.Get("Content-Type"),
|
||||
}
|
||||
|
||||
if err := params.AddUpload(upload, key, path); err != nil {
|
||||
w.WriteHeader(http.StatusUnprocessableEntity)
|
||||
writeJsonGraphqlError(w, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
params.ReadTime = graphql.TraceTiming{
|
||||
Start: start,
|
||||
End: graphql.Now(),
|
||||
}
|
||||
|
||||
rc, gerr := exec.CreateOperationContext(r.Context(), ¶ms)
|
||||
if gerr != nil {
|
||||
resp := exec.DispatchError(graphql.WithOperationContext(r.Context(), rc), gerr)
|
||||
w.WriteHeader(statusFor(gerr))
|
||||
writeJson(w, resp)
|
||||
return
|
||||
}
|
||||
responses, ctx := exec.DispatchOperation(r.Context(), rc)
|
||||
writeJson(w, responses(ctx))
|
||||
}
|
||||
87
vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_get.go
generated
vendored
Normal file
87
vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_get.go
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/99designs/gqlgen/graphql/errcode"
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
// GET implements the GET side of the default HTTP transport
|
||||
// defined in https://github.com/APIs-guru/graphql-over-http#get
|
||||
type GET struct{}
|
||||
|
||||
var _ graphql.Transport = GET{}
|
||||
|
||||
func (h GET) Supports(r *http.Request) bool {
|
||||
if r.Header.Get("Upgrade") != "" {
|
||||
return false
|
||||
}
|
||||
|
||||
return r.Method == "GET"
|
||||
}
|
||||
|
||||
func (h GET) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
raw := &graphql.RawParams{
|
||||
Query: r.URL.Query().Get("query"),
|
||||
OperationName: r.URL.Query().Get("operationName"),
|
||||
}
|
||||
raw.ReadTime.Start = graphql.Now()
|
||||
|
||||
if variables := r.URL.Query().Get("variables"); variables != "" {
|
||||
if err := jsonDecode(strings.NewReader(variables), &raw.Variables); err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
writeJsonError(w, "variables could not be decoded")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if extensions := r.URL.Query().Get("extensions"); extensions != "" {
|
||||
if err := jsonDecode(strings.NewReader(extensions), &raw.Extensions); err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
writeJsonError(w, "extensions could not be decoded")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
raw.ReadTime.End = graphql.Now()
|
||||
|
||||
rc, err := exec.CreateOperationContext(r.Context(), raw)
|
||||
if err != nil {
|
||||
w.WriteHeader(statusFor(err))
|
||||
resp := exec.DispatchError(graphql.WithOperationContext(r.Context(), rc), err)
|
||||
writeJson(w, resp)
|
||||
return
|
||||
}
|
||||
op := rc.Doc.Operations.ForName(rc.OperationName)
|
||||
if op.Operation != ast.Query {
|
||||
w.WriteHeader(http.StatusNotAcceptable)
|
||||
writeJsonError(w, "GET requests only allow query operations")
|
||||
return
|
||||
}
|
||||
|
||||
responses, ctx := exec.DispatchOperation(r.Context(), rc)
|
||||
writeJson(w, responses(ctx))
|
||||
}
|
||||
|
||||
func jsonDecode(r io.Reader, val interface{}) error {
|
||||
dec := json.NewDecoder(r)
|
||||
dec.UseNumber()
|
||||
return dec.Decode(val)
|
||||
}
|
||||
|
||||
func statusFor(errs gqlerror.List) int {
|
||||
switch errcode.GetErrorKind(errs) {
|
||||
case errcode.KindProtocol:
|
||||
return http.StatusUnprocessableEntity
|
||||
default:
|
||||
return http.StatusOK
|
||||
}
|
||||
}
|
||||
54
vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_post.go
generated
vendored
Normal file
54
vendor/github.com/99designs/gqlgen/graphql/handler/transport/http_post.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"mime"
|
||||
"net/http"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
)
|
||||
|
||||
// POST implements the POST side of the default HTTP transport
|
||||
// defined in https://github.com/APIs-guru/graphql-over-http#post
|
||||
type POST struct{}
|
||||
|
||||
var _ graphql.Transport = POST{}
|
||||
|
||||
func (h POST) Supports(r *http.Request) bool {
|
||||
if r.Header.Get("Upgrade") != "" {
|
||||
return false
|
||||
}
|
||||
|
||||
mediaType, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return r.Method == "POST" && mediaType == "application/json"
|
||||
}
|
||||
|
||||
func (h POST) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
var params *graphql.RawParams
|
||||
start := graphql.Now()
|
||||
if err := jsonDecode(r.Body, ¶ms); err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
writeJsonErrorf(w, "json body could not be decoded: "+err.Error())
|
||||
return
|
||||
}
|
||||
params.ReadTime = graphql.TraceTiming{
|
||||
Start: start,
|
||||
End: graphql.Now(),
|
||||
}
|
||||
|
||||
rc, err := exec.CreateOperationContext(r.Context(), params)
|
||||
if err != nil {
|
||||
w.WriteHeader(statusFor(err))
|
||||
resp := exec.DispatchError(graphql.WithOperationContext(r.Context(), rc), err)
|
||||
writeJson(w, resp)
|
||||
return
|
||||
}
|
||||
ctx := graphql.WithOperationContext(r.Context(), rc)
|
||||
responses, ctx := exec.DispatchOperation(ctx, rc)
|
||||
writeJson(w, responses(ctx))
|
||||
}
|
||||
26
vendor/github.com/99designs/gqlgen/graphql/handler/transport/options.go
generated
vendored
Normal file
26
vendor/github.com/99designs/gqlgen/graphql/handler/transport/options.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
)
|
||||
|
||||
// Options responds to http OPTIONS and HEAD requests
|
||||
type Options struct{}
|
||||
|
||||
var _ graphql.Transport = Options{}
|
||||
|
||||
func (o Options) Supports(r *http.Request) bool {
|
||||
return r.Method == "HEAD" || r.Method == "OPTIONS"
|
||||
}
|
||||
|
||||
func (o Options) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) {
|
||||
switch r.Method {
|
||||
case http.MethodOptions:
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Header().Set("Allow", "OPTIONS, GET, POST")
|
||||
case http.MethodHead:
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
}
|
||||
}
|
||||
25
vendor/github.com/99designs/gqlgen/graphql/handler/transport/reader.go
generated
vendored
Normal file
25
vendor/github.com/99designs/gqlgen/graphql/handler/transport/reader.go
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
type bytesReader struct {
|
||||
s *[]byte
|
||||
i int64 // current reading index
|
||||
prevRune int // index of previous rune; or < 0
|
||||
}
|
||||
|
||||
func (r *bytesReader) Read(b []byte) (n int, err error) {
|
||||
if r.s == nil {
|
||||
return 0, errors.New("byte slice pointer is nil")
|
||||
}
|
||||
if r.i >= int64(len(*r.s)) {
|
||||
return 0, io.EOF
|
||||
}
|
||||
r.prevRune = -1
|
||||
n = copy(b, (*r.s)[r.i:])
|
||||
r.i += int64(n)
|
||||
return
|
||||
}
|
||||
30
vendor/github.com/99designs/gqlgen/graphql/handler/transport/util.go
generated
vendored
Normal file
30
vendor/github.com/99designs/gqlgen/graphql/handler/transport/util.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
func writeJson(w io.Writer, response *graphql.Response) {
|
||||
b, err := json.Marshal(response)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
w.Write(b)
|
||||
}
|
||||
|
||||
func writeJsonError(w io.Writer, msg string) {
|
||||
writeJson(w, &graphql.Response{Errors: gqlerror.List{{Message: msg}}})
|
||||
}
|
||||
|
||||
func writeJsonErrorf(w io.Writer, format string, args ...interface{}) {
|
||||
writeJson(w, &graphql.Response{Errors: gqlerror.List{{Message: fmt.Sprintf(format, args...)}}})
|
||||
}
|
||||
|
||||
func writeJsonGraphqlError(w io.Writer, err ...*gqlerror.Error) {
|
||||
writeJson(w, &graphql.Response{Errors: err})
|
||||
}
|
||||
316
vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket.go
generated
vendored
Normal file
316
vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket.go
generated
vendored
Normal file
@@ -0,0 +1,316 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/99designs/gqlgen/graphql/errcode"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
const (
|
||||
connectionInitMsg = "connection_init" // Client -> Server
|
||||
connectionTerminateMsg = "connection_terminate" // Client -> Server
|
||||
startMsg = "start" // Client -> Server
|
||||
stopMsg = "stop" // Client -> Server
|
||||
connectionAckMsg = "connection_ack" // Server -> Client
|
||||
connectionErrorMsg = "connection_error" // Server -> Client
|
||||
dataMsg = "data" // Server -> Client
|
||||
errorMsg = "error" // Server -> Client
|
||||
completeMsg = "complete" // Server -> Client
|
||||
connectionKeepAliveMsg = "ka" // Server -> Client
|
||||
)
|
||||
|
||||
type (
|
||||
Websocket struct {
|
||||
Upgrader websocket.Upgrader
|
||||
InitFunc WebsocketInitFunc
|
||||
KeepAlivePingInterval time.Duration
|
||||
}
|
||||
wsConnection struct {
|
||||
Websocket
|
||||
ctx context.Context
|
||||
conn *websocket.Conn
|
||||
active map[string]context.CancelFunc
|
||||
mu sync.Mutex
|
||||
keepAliveTicker *time.Ticker
|
||||
exec graphql.GraphExecutor
|
||||
|
||||
initPayload InitPayload
|
||||
}
|
||||
operationMessage struct {
|
||||
Payload json.RawMessage `json:"payload,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
WebsocketInitFunc func(ctx context.Context, initPayload InitPayload) (context.Context, error)
|
||||
)
|
||||
|
||||
var _ graphql.Transport = Websocket{}
|
||||
|
||||
func (t Websocket) Supports(r *http.Request) bool {
|
||||
return r.Header.Get("Upgrade") != ""
|
||||
}
|
||||
|
||||
func (t Websocket) Do(w http.ResponseWriter, r *http.Request, exec graphql.GraphExecutor) {
|
||||
ws, err := t.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{},
|
||||
conn: ws,
|
||||
ctx: r.Context(),
|
||||
exec: exec,
|
||||
Websocket: t,
|
||||
}
|
||||
|
||||
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:
|
||||
if len(message.Payload) > 0 {
|
||||
c.initPayload = make(InitPayload)
|
||||
err := json.Unmarshal(message.Payload, &c.initPayload)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if c.InitFunc != nil {
|
||||
ctx, err := c.InitFunc(c.ctx, c.initPayload)
|
||||
if err != nil {
|
||||
c.sendConnectionError(err.Error())
|
||||
c.close(websocket.CloseNormalClosure, "terminated")
|
||||
return false
|
||||
}
|
||||
c.ctx = ctx
|
||||
}
|
||||
|
||||
c.write(&operationMessage{Type: connectionAckMsg})
|
||||
c.write(&operationMessage{Type: connectionKeepAliveMsg})
|
||||
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() {
|
||||
// We create a cancellation that will shutdown the keep-alive when we leave
|
||||
// this function.
|
||||
ctx, cancel := context.WithCancel(c.ctx)
|
||||
defer func() {
|
||||
cancel()
|
||||
c.close(websocket.CloseAbnormalClosure, "unexpected closure")
|
||||
}()
|
||||
|
||||
// Create a timer that will fire every interval to keep the connection alive.
|
||||
if c.KeepAlivePingInterval != 0 {
|
||||
c.mu.Lock()
|
||||
c.keepAliveTicker = time.NewTicker(c.KeepAlivePingInterval)
|
||||
c.mu.Unlock()
|
||||
|
||||
go c.keepAlive(ctx)
|
||||
}
|
||||
|
||||
for {
|
||||
start := graphql.Now()
|
||||
message := c.readOp()
|
||||
if message == nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch message.Type {
|
||||
case startMsg:
|
||||
c.subscribe(start, message)
|
||||
case stopMsg:
|
||||
c.mu.Lock()
|
||||
closer := c.active[message.ID]
|
||||
c.mu.Unlock()
|
||||
if closer != nil {
|
||||
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) keepAlive(ctx context.Context) {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
c.keepAliveTicker.Stop()
|
||||
return
|
||||
case <-c.keepAliveTicker.C:
|
||||
c.write(&operationMessage{Type: connectionKeepAliveMsg})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *wsConnection) subscribe(start time.Time, message *operationMessage) {
|
||||
ctx := graphql.StartOperationTrace(c.ctx)
|
||||
var params *graphql.RawParams
|
||||
if err := jsonDecode(bytes.NewReader(message.Payload), ¶ms); err != nil {
|
||||
c.sendError(message.ID, &gqlerror.Error{Message: "invalid json"})
|
||||
c.complete(message.ID)
|
||||
return
|
||||
}
|
||||
|
||||
params.ReadTime = graphql.TraceTiming{
|
||||
Start: start,
|
||||
End: graphql.Now(),
|
||||
}
|
||||
|
||||
rc, err := c.exec.CreateOperationContext(ctx, params)
|
||||
if err != nil {
|
||||
resp := c.exec.DispatchError(graphql.WithOperationContext(ctx, rc), err)
|
||||
switch errcode.GetErrorKind(err) {
|
||||
case errcode.KindProtocol:
|
||||
c.sendError(message.ID, resp.Errors...)
|
||||
default:
|
||||
c.sendResponse(message.ID, &graphql.Response{Errors: err})
|
||||
}
|
||||
|
||||
c.complete(message.ID)
|
||||
return
|
||||
}
|
||||
|
||||
ctx = graphql.WithOperationContext(ctx, rc)
|
||||
|
||||
if c.initPayload != nil {
|
||||
ctx = withInitPayload(ctx, c.initPayload)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
c.mu.Lock()
|
||||
c.active[message.ID] = cancel
|
||||
c.mu.Unlock()
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
userErr := rc.Recover(ctx, r)
|
||||
c.sendError(message.ID, &gqlerror.Error{Message: userErr.Error()})
|
||||
}
|
||||
}()
|
||||
responses, ctx := c.exec.DispatchOperation(ctx, rc)
|
||||
for {
|
||||
response := responses(ctx)
|
||||
if response == nil {
|
||||
break
|
||||
}
|
||||
|
||||
c.sendResponse(message.ID, response)
|
||||
}
|
||||
c.complete(message.ID)
|
||||
|
||||
c.mu.Lock()
|
||||
delete(c.active, message.ID)
|
||||
c.mu.Unlock()
|
||||
cancel()
|
||||
}()
|
||||
}
|
||||
|
||||
func (c *wsConnection) sendResponse(id string, response *graphql.Response) {
|
||||
b, err := json.Marshal(response)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
c.write(&operationMessage{
|
||||
Payload: b,
|
||||
ID: id,
|
||||
Type: dataMsg,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *wsConnection) complete(id string) {
|
||||
c.write(&operationMessage{ID: id, Type: completeMsg})
|
||||
}
|
||||
|
||||
func (c *wsConnection) sendError(id string, errors ...*gqlerror.Error) {
|
||||
errs := make([]error, len(errors))
|
||||
for i, err := range errors {
|
||||
errs[i] = err
|
||||
}
|
||||
b, err := json.Marshal(errs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
c.write(&operationMessage{Type: errorMsg, ID: id, Payload: b})
|
||||
}
|
||||
|
||||
func (c *wsConnection) sendConnectionError(format string, args ...interface{}) {
|
||||
b, err := json.Marshal(&gqlerror.Error{Message: fmt.Sprintf(format, args...)})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.write(&operationMessage{Type: connectionErrorMsg, Payload: b})
|
||||
}
|
||||
|
||||
func (c *wsConnection) readOp() *operationMessage {
|
||||
_, r, err := c.conn.NextReader()
|
||||
if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) {
|
||||
return nil
|
||||
} else if err != nil {
|
||||
c.sendConnectionError("invalid json: %T %s", err, err.Error())
|
||||
return nil
|
||||
}
|
||||
message := operationMessage{}
|
||||
if err := jsonDecode(r, &message); err != nil {
|
||||
c.sendConnectionError("invalid json")
|
||||
return nil
|
||||
}
|
||||
|
||||
return &message
|
||||
}
|
||||
|
||||
func (c *wsConnection) close(closeCode int, message string) {
|
||||
c.mu.Lock()
|
||||
_ = c.conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(closeCode, message))
|
||||
c.mu.Unlock()
|
||||
_ = c.conn.Close()
|
||||
}
|
||||
57
vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket_init.go
generated
vendored
Normal file
57
vendor/github.com/99designs/gqlgen/graphql/handler/transport/websocket_init.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
package transport
|
||||
|
||||
import "context"
|
||||
|
||||
type key string
|
||||
|
||||
const (
|
||||
initpayload key = "ws_initpayload_context"
|
||||
)
|
||||
|
||||
// InitPayload is a structure that is parsed from the websocket init message payload. TO use
|
||||
// request headers for non-websocket, instead wrap the graphql handler in a middleware.
|
||||
type InitPayload map[string]interface{}
|
||||
|
||||
// GetString safely gets a string value from the payload. It returns an empty string if the
|
||||
// payload is nil or the value isn't set.
|
||||
func (p InitPayload) GetString(key string) string {
|
||||
if p == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
if value, ok := p[key]; ok {
|
||||
res, _ := value.(string)
|
||||
return res
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
// Authorization is a short hand for getting the Authorization header from the
|
||||
// payload.
|
||||
func (p InitPayload) Authorization() string {
|
||||
if value := p.GetString("Authorization"); value != "" {
|
||||
return value
|
||||
}
|
||||
|
||||
if value := p.GetString("authorization"); value != "" {
|
||||
return value
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func withInitPayload(ctx context.Context, payload InitPayload) context.Context {
|
||||
return context.WithValue(ctx, initpayload, payload)
|
||||
}
|
||||
|
||||
// GetInitPayload gets a map of the data sent with the connection_init message, which is used by
|
||||
// graphql clients as a stand-in for HTTP headers.
|
||||
func GetInitPayload(ctx context.Context) InitPayload {
|
||||
payload, ok := ctx.Value(initpayload).(InitPayload)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return payload
|
||||
}
|
||||
2
vendor/github.com/99designs/gqlgen/graphql/id.go
generated
vendored
2
vendor/github.com/99designs/gqlgen/graphql/id.go
generated
vendored
@@ -20,6 +20,8 @@ func UnmarshalID(v interface{}) (string, error) {
|
||||
return string(v), nil
|
||||
case int:
|
||||
return strconv.Itoa(v), nil
|
||||
case int64:
|
||||
return strconv.FormatInt(v, 10), nil
|
||||
case float64:
|
||||
return fmt.Sprintf("%f", v), nil
|
||||
case bool:
|
||||
|
||||
2
vendor/github.com/99designs/gqlgen/graphql/introspection/introspection.go
generated
vendored
2
vendor/github.com/99designs/gqlgen/graphql/introspection/introspection.go
generated
vendored
@@ -1,7 +1,7 @@
|
||||
// introspection implements the spec defined in https://github.com/facebook/graphql/blob/master/spec/Section%204%20--%20Introspection.md#schema-introspection
|
||||
package introspection
|
||||
|
||||
import "github.com/vektah/gqlparser/ast"
|
||||
import "github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
type (
|
||||
Directive struct {
|
||||
|
||||
20
vendor/github.com/99designs/gqlgen/graphql/introspection/schema.go
generated
vendored
20
vendor/github.com/99designs/gqlgen/graphql/introspection/schema.go
generated
vendored
@@ -3,7 +3,7 @@ package introspection
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/vektah/gqlparser/ast"
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
)
|
||||
|
||||
type Schema struct {
|
||||
@@ -11,7 +11,7 @@ type Schema struct {
|
||||
}
|
||||
|
||||
func (s *Schema) Types() []Type {
|
||||
var types []Type
|
||||
types := make([]Type, 0, len(s.schema.Types))
|
||||
for _, typ := range s.schema.Types {
|
||||
if strings.HasPrefix(typ.Name, "__") {
|
||||
continue
|
||||
@@ -34,7 +34,7 @@ func (s *Schema) SubscriptionType() *Type {
|
||||
}
|
||||
|
||||
func (s *Schema) Directives() []Directive {
|
||||
var res []Directive
|
||||
res := make([]Directive, 0, len(s.schema.Directives))
|
||||
|
||||
for _, d := range s.schema.Directives {
|
||||
res = append(res, s.directiveFromDef(d))
|
||||
@@ -44,19 +44,19 @@ func (s *Schema) Directives() []Directive {
|
||||
}
|
||||
|
||||
func (s *Schema) directiveFromDef(d *ast.DirectiveDefinition) Directive {
|
||||
var locs []string
|
||||
for _, loc := range d.Locations {
|
||||
locs = append(locs, string(loc))
|
||||
locs := make([]string, len(d.Locations))
|
||||
for i, loc := range d.Locations {
|
||||
locs[i] = string(loc)
|
||||
}
|
||||
|
||||
var args []InputValue
|
||||
for _, arg := range d.Arguments {
|
||||
args = append(args, InputValue{
|
||||
args := make([]InputValue, len(d.Arguments))
|
||||
for i, arg := range d.Arguments {
|
||||
args[i] = InputValue{
|
||||
Name: arg.Name,
|
||||
Description: arg.Description,
|
||||
DefaultValue: defaultValue(arg.DefaultValue),
|
||||
Type: WrapTypeFromType(s.schema, arg.Type),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return Directive{
|
||||
|
||||
6
vendor/github.com/99designs/gqlgen/graphql/introspection/type.go
generated
vendored
6
vendor/github.com/99designs/gqlgen/graphql/introspection/type.go
generated
vendored
@@ -3,7 +3,7 @@ package introspection
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/vektah/gqlparser/ast"
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
)
|
||||
|
||||
type Type struct {
|
||||
@@ -152,6 +152,10 @@ func (t *Type) EnumValues(includeDeprecated bool) []EnumValue {
|
||||
|
||||
res := []EnumValue{}
|
||||
for _, val := range t.def.EnumValues {
|
||||
if !includeDeprecated && val.Directives.ForName("deprecated") != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
res = append(res, EnumValue{
|
||||
Name: val.Name,
|
||||
Description: val.Description,
|
||||
|
||||
6
vendor/github.com/99designs/gqlgen/graphql/oneshot.go
generated
vendored
6
vendor/github.com/99designs/gqlgen/graphql/oneshot.go
generated
vendored
@@ -1,9 +1,11 @@
|
||||
package graphql
|
||||
|
||||
func OneShot(resp *Response) func() *Response {
|
||||
import "context"
|
||||
|
||||
func OneShot(resp *Response) ResponseHandler {
|
||||
var oneshot bool
|
||||
|
||||
return func() *Response {
|
||||
return func(context context.Context) *Response {
|
||||
if oneshot {
|
||||
return nil
|
||||
}
|
||||
|
||||
62
vendor/github.com/99designs/gqlgen/graphql/playground/playground.go
generated
vendored
Normal file
62
vendor/github.com/99designs/gqlgen/graphql/playground/playground.go
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
package playground
|
||||
|
||||
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="https://cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/static/css/index.css"
|
||||
integrity="{{ .cssSRI }}" crossorigin="anonymous"/>
|
||||
<link rel="shortcut icon" href="https://cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/favicon.png"
|
||||
integrity="{{ .faviconSRI }}" crossorigin="anonymous"/>
|
||||
<script src="https://cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/static/js/middleware.js"
|
||||
integrity="{{ .jsSRI }}" crossorigin="anonymous"></script>
|
||||
<title>{{.title}}</title>
|
||||
</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 }}',
|
||||
shareEnabled: true,
|
||||
settings: {
|
||||
'request.credentials': 'same-origin'
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`))
|
||||
|
||||
func Handler(title string, endpoint string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Add("Content-Type", "text/html")
|
||||
err := page.Execute(w, map[string]string{
|
||||
"title": title,
|
||||
"endpoint": endpoint,
|
||||
"version": "1.7.20",
|
||||
"cssSRI": "sha256-cS9Vc2OBt9eUf4sykRWukeFYaInL29+myBmFDSa7F/U=",
|
||||
"faviconSRI": "sha256-GhTyE+McTU79R4+pRO6ih+4TfsTOrpPwD8ReKFzb3PM=",
|
||||
"jsSRI": "sha256-4QG1Uza2GgGdlBL3RCBCGtGeZB6bDbsw8OltCMGeJsA=",
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
2
vendor/github.com/99designs/gqlgen/graphql/response.go
generated
vendored
2
vendor/github.com/99designs/gqlgen/graphql/response.go
generated
vendored
@@ -5,7 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/vektah/gqlparser/gqlerror"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
// Errors are intentionally serialized first based on the advice in
|
||||
|
||||
60
vendor/github.com/99designs/gqlgen/graphql/stats.go
generated
vendored
Normal file
60
vendor/github.com/99designs/gqlgen/graphql/stats.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
package graphql
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Stats struct {
|
||||
OperationStart time.Time
|
||||
Read TraceTiming
|
||||
Parsing TraceTiming
|
||||
Validation TraceTiming
|
||||
|
||||
// Stats collected by handler extensions. Dont use directly, the extension should provide a type safe way to
|
||||
// access this.
|
||||
extension map[string]interface{}
|
||||
}
|
||||
|
||||
type TraceTiming struct {
|
||||
Start time.Time
|
||||
End time.Time
|
||||
}
|
||||
|
||||
var ctxTraceStart key = "trace_start"
|
||||
|
||||
// StartOperationTrace captures the current time and stores it in context. This will eventually be added to request
|
||||
// context but we want to grab it as soon as possible. For transports that can only handle a single graphql query
|
||||
// per http requests you dont need to call this at all, the server will do it for you. For transports that handle
|
||||
// multiple (eg batching, subscriptions) this should be called before decoding each request.
|
||||
func StartOperationTrace(ctx context.Context) context.Context {
|
||||
return context.WithValue(ctx, ctxTraceStart, Now())
|
||||
}
|
||||
|
||||
// GetStartTime should only be called by the handler package, it will be set into request context
|
||||
// as Stats.Start
|
||||
func GetStartTime(ctx context.Context) time.Time {
|
||||
t, ok := ctx.Value(ctxTraceStart).(time.Time)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("missing start time: %T", ctx.Value(ctxTraceStart)))
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func (c *Stats) SetExtension(name string, data interface{}) {
|
||||
if c.extension == nil {
|
||||
c.extension = map[string]interface{}{}
|
||||
}
|
||||
c.extension[name] = data
|
||||
}
|
||||
|
||||
func (c *Stats) GetExtension(name string) interface{} {
|
||||
if c.extension == nil {
|
||||
return nil
|
||||
}
|
||||
return c.extension[name]
|
||||
}
|
||||
|
||||
// Now is time.Now, except in tests. Then it can be whatever you want it to be.
|
||||
var Now = time.Now
|
||||
58
vendor/github.com/99designs/gqlgen/graphql/tracer.go
generated
vendored
58
vendor/github.com/99designs/gqlgen/graphql/tracer.go
generated
vendored
@@ -1,58 +0,0 @@
|
||||
package graphql
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
var _ Tracer = (*NopTracer)(nil)
|
||||
|
||||
type Tracer interface {
|
||||
StartOperationParsing(ctx context.Context) context.Context
|
||||
EndOperationParsing(ctx context.Context)
|
||||
StartOperationValidation(ctx context.Context) context.Context
|
||||
EndOperationValidation(ctx context.Context)
|
||||
StartOperationExecution(ctx context.Context) context.Context
|
||||
StartFieldExecution(ctx context.Context, field CollectedField) context.Context
|
||||
StartFieldResolverExecution(ctx context.Context, rc *ResolverContext) context.Context
|
||||
StartFieldChildExecution(ctx context.Context) context.Context
|
||||
EndFieldExecution(ctx context.Context)
|
||||
EndOperationExecution(ctx context.Context)
|
||||
}
|
||||
|
||||
type NopTracer struct{}
|
||||
|
||||
func (NopTracer) StartOperationParsing(ctx context.Context) context.Context {
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (NopTracer) EndOperationParsing(ctx context.Context) {
|
||||
}
|
||||
|
||||
func (NopTracer) StartOperationValidation(ctx context.Context) context.Context {
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (NopTracer) EndOperationValidation(ctx context.Context) {
|
||||
}
|
||||
|
||||
func (NopTracer) StartOperationExecution(ctx context.Context) context.Context {
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (NopTracer) StartFieldExecution(ctx context.Context, field CollectedField) context.Context {
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (NopTracer) StartFieldResolverExecution(ctx context.Context, rc *ResolverContext) context.Context {
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (NopTracer) StartFieldChildExecution(ctx context.Context) context.Context {
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (NopTracer) EndFieldExecution(ctx context.Context) {
|
||||
}
|
||||
|
||||
func (NopTracer) EndOperationExecution(ctx context.Context) {
|
||||
}
|
||||
7
vendor/github.com/99designs/gqlgen/graphql/upload.go
generated
vendored
7
vendor/github.com/99designs/gqlgen/graphql/upload.go
generated
vendored
@@ -6,9 +6,10 @@ import (
|
||||
)
|
||||
|
||||
type Upload struct {
|
||||
File io.Reader
|
||||
Filename string
|
||||
Size int64
|
||||
File io.Reader
|
||||
Filename string
|
||||
Size int64
|
||||
ContentType string
|
||||
}
|
||||
|
||||
func MarshalUpload(f Upload) Marshaler {
|
||||
|
||||
2
vendor/github.com/99designs/gqlgen/graphql/version.go
generated
vendored
2
vendor/github.com/99designs/gqlgen/graphql/version.go
generated
vendored
@@ -1,3 +1,3 @@
|
||||
package graphql
|
||||
|
||||
const Version = "v0.9.0"
|
||||
const Version = "v0.12.2"
|
||||
|
||||
Reference in New Issue
Block a user