mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 20:34:37 +03:00
Update GQLGen and break up the schema.graphql file
This commit is contained in:
35
vendor/github.com/99designs/gqlgen/graphql/context.go
generated
vendored
35
vendor/github.com/99designs/gqlgen/graphql/context.go
generated
vendored
@@ -12,6 +12,7 @@ import (
|
||||
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
|
||||
@@ -71,12 +72,10 @@ const (
|
||||
)
|
||||
|
||||
func GetRequestContext(ctx context.Context) *RequestContext {
|
||||
val := ctx.Value(request)
|
||||
if val == nil {
|
||||
return nil
|
||||
if val, ok := ctx.Value(request).(*RequestContext); ok {
|
||||
return val
|
||||
}
|
||||
|
||||
return val.(*RequestContext)
|
||||
return nil
|
||||
}
|
||||
|
||||
func WithRequestContext(ctx context.Context, rc *RequestContext) context.Context {
|
||||
@@ -95,6 +94,8 @@ type ResolverContext struct {
|
||||
Index *int
|
||||
// The result object of resolver
|
||||
Result interface{}
|
||||
// IsMethod indicates if the resolver is a method
|
||||
IsMethod bool
|
||||
}
|
||||
|
||||
func (r *ResolverContext) Path() []interface{} {
|
||||
@@ -117,8 +118,10 @@ func (r *ResolverContext) Path() []interface{} {
|
||||
}
|
||||
|
||||
func GetResolverContext(ctx context.Context) *ResolverContext {
|
||||
val, _ := ctx.Value(resolver).(*ResolverContext)
|
||||
return val
|
||||
if val, ok := ctx.Value(resolver).(*ResolverContext); ok {
|
||||
return val
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func WithResolverContext(ctx context.Context, rc *ResolverContext) context.Context {
|
||||
@@ -132,6 +135,24 @@ func CollectFieldsCtx(ctx context.Context, satisfies []string) []CollectedField
|
||||
return CollectFields(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(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()
|
||||
|
||||
4
vendor/github.com/99designs/gqlgen/graphql/error.go
generated
vendored
4
vendor/github.com/99designs/gqlgen/graphql/error.go
generated
vendored
@@ -14,7 +14,9 @@ type ExtendedError interface {
|
||||
|
||||
func DefaultErrorPresenter(ctx context.Context, err error) *gqlerror.Error {
|
||||
if gqlerr, ok := err.(*gqlerror.Error); ok {
|
||||
gqlerr.Path = GetResolverContext(ctx).Path()
|
||||
if gqlerr.Path == nil {
|
||||
gqlerr.Path = GetResolverContext(ctx).Path()
|
||||
}
|
||||
return gqlerr
|
||||
}
|
||||
|
||||
|
||||
10
vendor/github.com/99designs/gqlgen/graphql/exec.go
generated
vendored
10
vendor/github.com/99designs/gqlgen/graphql/exec.go
generated
vendored
@@ -16,6 +16,9 @@ type ExecutableSchema interface {
|
||||
Subscription(ctx context.Context, op *ast.OperationDefinition) func() *Response
|
||||
}
|
||||
|
||||
// CollectFields returns the set of fields from an ast.SelectionSet where all collected fields satisfy at least one of the GraphQL types
|
||||
// passed through satisfies. Providing an empty or nil slice for satisfies will return collect all fields regardless of fragment
|
||||
// type conditions.
|
||||
func CollectFields(ctx context.Context, selSet ast.SelectionSet, satisfies []string) []CollectedField {
|
||||
return collectFields(GetRequestContext(ctx), selSet, satisfies, map[string]bool{})
|
||||
}
|
||||
@@ -35,7 +38,10 @@ func collectFields(reqCtx *RequestContext, selSet ast.SelectionSet, satisfies []
|
||||
|
||||
f.Selections = append(f.Selections, sel.SelectionSet...)
|
||||
case *ast.InlineFragment:
|
||||
if !shouldIncludeNode(sel.Directives, reqCtx.Variables) || !instanceOf(sel.TypeCondition, satisfies) {
|
||||
if !shouldIncludeNode(sel.Directives, reqCtx.Variables) {
|
||||
continue
|
||||
}
|
||||
if len(satisfies) > 0 && !instanceOf(sel.TypeCondition, satisfies) {
|
||||
continue
|
||||
}
|
||||
for _, childField := range collectFields(reqCtx, sel.SelectionSet, satisfies, visited) {
|
||||
@@ -59,7 +65,7 @@ func collectFields(reqCtx *RequestContext, selSet ast.SelectionSet, satisfies []
|
||||
panic(fmt.Errorf("missing fragment %s", fragmentName))
|
||||
}
|
||||
|
||||
if !instanceOf(fragment.TypeCondition, satisfies) {
|
||||
if len(satisfies) > 0 && !instanceOf(fragment.TypeCondition, satisfies) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
21
vendor/github.com/99designs/gqlgen/graphql/id.go
generated
vendored
21
vendor/github.com/99designs/gqlgen/graphql/id.go
generated
vendored
@@ -34,3 +34,24 @@ func UnmarshalID(v interface{}) (string, error) {
|
||||
return "", fmt.Errorf("%T is not a string", v)
|
||||
}
|
||||
}
|
||||
|
||||
func MarshalIntID(i int) Marshaler {
|
||||
return WriterFunc(func(w io.Writer) {
|
||||
writeQuotedString(w, strconv.Itoa(i))
|
||||
})
|
||||
}
|
||||
|
||||
func UnmarshalIntID(v interface{}) (int, error) {
|
||||
switch v := v.(type) {
|
||||
case string:
|
||||
return strconv.Atoi(v)
|
||||
case int:
|
||||
return v, nil
|
||||
case int64:
|
||||
return int(v), nil
|
||||
case json.Number:
|
||||
return strconv.Atoi(string(v))
|
||||
default:
|
||||
return 0, fmt.Errorf("%T is not an int", v)
|
||||
}
|
||||
}
|
||||
|
||||
50
vendor/github.com/99designs/gqlgen/graphql/int.go
generated
vendored
50
vendor/github.com/99designs/gqlgen/graphql/int.go
generated
vendored
@@ -27,3 +27,53 @@ func UnmarshalInt(v interface{}) (int, error) {
|
||||
return 0, fmt.Errorf("%T is not an int", v)
|
||||
}
|
||||
}
|
||||
|
||||
func MarshalInt64(i int64) Marshaler {
|
||||
return WriterFunc(func(w io.Writer) {
|
||||
io.WriteString(w, strconv.FormatInt(i, 10))
|
||||
})
|
||||
}
|
||||
|
||||
func UnmarshalInt64(v interface{}) (int64, error) {
|
||||
switch v := v.(type) {
|
||||
case string:
|
||||
return strconv.ParseInt(v, 10, 64)
|
||||
case int:
|
||||
return int64(v), nil
|
||||
case int64:
|
||||
return v, nil
|
||||
case json.Number:
|
||||
return strconv.ParseInt(string(v), 10, 64)
|
||||
default:
|
||||
return 0, fmt.Errorf("%T is not an int", v)
|
||||
}
|
||||
}
|
||||
|
||||
func MarshalInt32(i int32) Marshaler {
|
||||
return WriterFunc(func(w io.Writer) {
|
||||
io.WriteString(w, strconv.FormatInt(int64(i), 10))
|
||||
})
|
||||
}
|
||||
|
||||
func UnmarshalInt32(v interface{}) (int32, error) {
|
||||
switch v := v.(type) {
|
||||
case string:
|
||||
iv, err := strconv.ParseInt(v, 10, 32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int32(iv), nil
|
||||
case int:
|
||||
return int32(v), nil
|
||||
case int64:
|
||||
return int32(v), nil
|
||||
case json.Number:
|
||||
iv, err := strconv.ParseInt(string(v), 10, 32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int32(iv), nil
|
||||
default:
|
||||
return 0, fmt.Errorf("%T is not an int", v)
|
||||
}
|
||||
}
|
||||
|
||||
20
vendor/github.com/99designs/gqlgen/graphql/introspection/type.go
generated
vendored
20
vendor/github.com/99designs/gqlgen/graphql/introspection/type.go
generated
vendored
@@ -62,9 +62,9 @@ func (t *Type) Description() string {
|
||||
|
||||
func (t *Type) Fields(includeDeprecated bool) []Field {
|
||||
if t.def == nil || (t.def.Kind != ast.Object && t.def.Kind != ast.Interface) {
|
||||
return nil
|
||||
return []Field{}
|
||||
}
|
||||
var fields []Field
|
||||
fields := []Field{}
|
||||
for _, f := range t.def.Fields {
|
||||
if strings.HasPrefix(f.Name, "__") {
|
||||
continue
|
||||
@@ -93,10 +93,10 @@ func (t *Type) Fields(includeDeprecated bool) []Field {
|
||||
|
||||
func (t *Type) InputFields() []InputValue {
|
||||
if t.def == nil || t.def.Kind != ast.InputObject {
|
||||
return nil
|
||||
return []InputValue{}
|
||||
}
|
||||
|
||||
var res []InputValue
|
||||
res := []InputValue{}
|
||||
for _, f := range t.def.Fields {
|
||||
res = append(res, InputValue{
|
||||
Name: f.Name,
|
||||
@@ -118,10 +118,10 @@ func defaultValue(value *ast.Value) *string {
|
||||
|
||||
func (t *Type) Interfaces() []Type {
|
||||
if t.def == nil || t.def.Kind != ast.Object {
|
||||
return nil
|
||||
return []Type{}
|
||||
}
|
||||
|
||||
var res []Type
|
||||
res := []Type{}
|
||||
for _, intf := range t.def.Interfaces {
|
||||
res = append(res, *WrapTypeFromDef(t.schema, t.schema.Types[intf]))
|
||||
}
|
||||
@@ -131,10 +131,10 @@ func (t *Type) Interfaces() []Type {
|
||||
|
||||
func (t *Type) PossibleTypes() []Type {
|
||||
if t.def == nil || (t.def.Kind != ast.Interface && t.def.Kind != ast.Union) {
|
||||
return nil
|
||||
return []Type{}
|
||||
}
|
||||
|
||||
var res []Type
|
||||
res := []Type{}
|
||||
for _, pt := range t.schema.GetPossibleTypes(t.def) {
|
||||
res = append(res, *WrapTypeFromDef(t.schema, pt))
|
||||
}
|
||||
@@ -143,10 +143,10 @@ func (t *Type) PossibleTypes() []Type {
|
||||
|
||||
func (t *Type) EnumValues(includeDeprecated bool) []EnumValue {
|
||||
if t.def == nil || t.def.Kind != ast.Enum {
|
||||
return nil
|
||||
return []EnumValue{}
|
||||
}
|
||||
|
||||
var res []EnumValue
|
||||
res := []EnumValue{}
|
||||
for _, val := range t.def.EnumValues {
|
||||
res = append(res, EnumValue{
|
||||
Name: val.Name,
|
||||
|
||||
7
vendor/github.com/99designs/gqlgen/graphql/root.go
generated
vendored
Normal file
7
vendor/github.com/99designs/gqlgen/graphql/root.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
package graphql
|
||||
|
||||
type Query struct{}
|
||||
|
||||
type Mutation struct{}
|
||||
|
||||
type Subscription struct{}
|
||||
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 = "dev"
|
||||
const Version = "v0.8.2"
|
||||
|
||||
52
vendor/github.com/99designs/gqlgen/handler/graphql.go
generated
vendored
52
vendor/github.com/99designs/gqlgen/handler/graphql.go
generated
vendored
@@ -7,6 +7,7 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/99designs/gqlgen/complexity"
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
@@ -25,15 +26,17 @@ type params struct {
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
cacheSize int
|
||||
upgrader websocket.Upgrader
|
||||
recover graphql.RecoverFunc
|
||||
errorPresenter graphql.ErrorPresenterFunc
|
||||
resolverHook graphql.FieldMiddleware
|
||||
requestHook graphql.RequestMiddleware
|
||||
tracer graphql.Tracer
|
||||
complexityLimit int
|
||||
disableIntrospection bool
|
||||
cacheSize int
|
||||
upgrader websocket.Upgrader
|
||||
recover graphql.RecoverFunc
|
||||
errorPresenter graphql.ErrorPresenterFunc
|
||||
resolverHook graphql.FieldMiddleware
|
||||
requestHook graphql.RequestMiddleware
|
||||
tracer graphql.Tracer
|
||||
complexityLimit int
|
||||
complexityLimitFunc graphql.ComplexityLimitFunc
|
||||
disableIntrospection bool
|
||||
connectionKeepAlivePingInterval time.Duration
|
||||
}
|
||||
|
||||
func (c *Config) newRequestContext(es graphql.ExecutableSchema, doc *ast.QueryDocument, op *ast.OperationDefinition, query string, variables map[string]interface{}) *graphql.RequestContext {
|
||||
@@ -60,7 +63,7 @@ func (c *Config) newRequestContext(es graphql.ExecutableSchema, doc *ast.QueryDo
|
||||
reqCtx.Tracer = hook
|
||||
}
|
||||
|
||||
if c.complexityLimit > 0 {
|
||||
if c.complexityLimit > 0 || c.complexityLimitFunc != nil {
|
||||
reqCtx.ComplexityLimit = c.complexityLimit
|
||||
operationComplexity := complexity.Calculate(es, op, variables)
|
||||
reqCtx.OperationComplexity = operationComplexity
|
||||
@@ -108,6 +111,15 @@ func ComplexityLimit(limit int) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// ComplexityLimitFunc allows you to define a function to dynamically set the maximum query complexity that is allowed
|
||||
// to be executed.
|
||||
// If a query is submitted that exceeds the limit, a 422 status code will be returned.
|
||||
func ComplexityLimitFunc(complexityLimitFunc graphql.ComplexityLimitFunc) Option {
|
||||
return func(cfg *Config) {
|
||||
cfg.complexityLimitFunc = complexityLimitFunc
|
||||
}
|
||||
}
|
||||
|
||||
// ResolverMiddleware allows you to define a function that will be called around every resolver,
|
||||
// useful for logging.
|
||||
func ResolverMiddleware(middleware graphql.FieldMiddleware) Option {
|
||||
@@ -239,11 +251,23 @@ func CacheSize(size int) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WebsocketKeepAliveDuration allows you to reconfigure the keepalive behavior.
|
||||
// By default, keepalive is enabled with a DefaultConnectionKeepAlivePingInterval
|
||||
// duration. Set handler.connectionKeepAlivePingInterval = 0 to disable keepalive
|
||||
// altogether.
|
||||
func WebsocketKeepAliveDuration(duration time.Duration) Option {
|
||||
return func(cfg *Config) {
|
||||
cfg.connectionKeepAlivePingInterval = duration
|
||||
}
|
||||
}
|
||||
|
||||
const DefaultCacheSize = 1000
|
||||
const DefaultConnectionKeepAlivePingInterval = 25 * time.Second
|
||||
|
||||
func GraphQL(exec graphql.ExecutableSchema, options ...Option) http.HandlerFunc {
|
||||
cfg := &Config{
|
||||
cacheSize: DefaultCacheSize,
|
||||
cacheSize: DefaultCacheSize,
|
||||
connectionKeepAlivePingInterval: DefaultConnectionKeepAlivePingInterval,
|
||||
upgrader: websocket.Upgrader{
|
||||
ReadBufferSize: 1024,
|
||||
WriteBufferSize: 1024,
|
||||
@@ -297,6 +321,7 @@ func (gh *graphqlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
var reqParams params
|
||||
switch r.Method {
|
||||
case http.MethodGet:
|
||||
@@ -318,7 +343,6 @@ func (gh *graphqlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
ctx := r.Context()
|
||||
|
||||
@@ -367,6 +391,10 @@ func (gh *graphqlHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}()
|
||||
|
||||
if gh.cfg.complexityLimitFunc != nil {
|
||||
reqCtx.ComplexityLimit = gh.cfg.complexityLimitFunc(ctx)
|
||||
}
|
||||
|
||||
if reqCtx.ComplexityLimit > 0 && reqCtx.OperationComplexity > reqCtx.ComplexityLimit {
|
||||
sendErrorf(w, http.StatusUnprocessableEntity, "operation has complexity %d, which exceeds the limit of %d", reqCtx.OperationComplexity, reqCtx.ComplexityLimit)
|
||||
return
|
||||
|
||||
19
vendor/github.com/99designs/gqlgen/handler/playground.go
generated
vendored
19
vendor/github.com/99designs/gqlgen/handler/playground.go
generated
vendored
@@ -11,9 +11,12 @@ var page = template.Must(template.New("graphiql").Parse(`<!DOCTYPE html>
|
||||
<meta charset=utf-8/>
|
||||
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
|
||||
<link rel="shortcut icon" href="https://graphcool-playground.netlify.com/favicon.png">
|
||||
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/static/css/index.css"/>
|
||||
<link rel="shortcut icon" href="//cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/favicon.png"/>
|
||||
<script src="//cdn.jsdelivr.net/npm/graphql-playground-react@{{ .version }}/build/static/js/middleware.js"></script>
|
||||
<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>
|
||||
@@ -42,10 +45,14 @@ var page = template.Must(template.New("graphiql").Parse(`<!DOCTYPE html>
|
||||
|
||||
func Playground(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.8",
|
||||
"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)
|
||||
|
||||
44
vendor/github.com/99designs/gqlgen/handler/websocket.go
generated
vendored
44
vendor/github.com/99designs/gqlgen/handler/websocket.go
generated
vendored
@@ -8,6 +8,7 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/99designs/gqlgen/graphql"
|
||||
"github.com/gorilla/websocket"
|
||||
@@ -28,7 +29,7 @@ const (
|
||||
dataMsg = "data" // Server -> Client
|
||||
errorMsg = "error" // Server -> Client
|
||||
completeMsg = "complete" // Server -> Client
|
||||
//connectionKeepAliveMsg = "ka" // Server -> Client TODO: keepalives
|
||||
connectionKeepAliveMsg = "ka" // Server -> Client
|
||||
)
|
||||
|
||||
type operationMessage struct {
|
||||
@@ -38,13 +39,14 @@ type operationMessage struct {
|
||||
}
|
||||
|
||||
type wsConnection struct {
|
||||
ctx context.Context
|
||||
conn *websocket.Conn
|
||||
exec graphql.ExecutableSchema
|
||||
active map[string]context.CancelFunc
|
||||
mu sync.Mutex
|
||||
cfg *Config
|
||||
cache *lru.Cache
|
||||
ctx context.Context
|
||||
conn *websocket.Conn
|
||||
exec graphql.ExecutableSchema
|
||||
active map[string]context.CancelFunc
|
||||
mu sync.Mutex
|
||||
cfg *Config
|
||||
cache *lru.Cache
|
||||
keepAliveTicker *time.Ticker
|
||||
|
||||
initPayload InitPayload
|
||||
}
|
||||
@@ -112,6 +114,20 @@ func (c *wsConnection) write(msg *operationMessage) {
|
||||
}
|
||||
|
||||
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 cancel()
|
||||
|
||||
// Create a timer that will fire every interval to keep the connection alive.
|
||||
if c.cfg.connectionKeepAlivePingInterval != 0 {
|
||||
c.mu.Lock()
|
||||
c.keepAliveTicker = time.NewTicker(c.cfg.connectionKeepAlivePingInterval)
|
||||
c.mu.Unlock()
|
||||
|
||||
go c.keepAlive(ctx)
|
||||
}
|
||||
|
||||
for {
|
||||
message := c.readOp()
|
||||
if message == nil {
|
||||
@@ -144,6 +160,18 @@ func (c *wsConnection) run() {
|
||||
}
|
||||
}
|
||||
|
||||
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(message *operationMessage) bool {
|
||||
var reqParams params
|
||||
if err := jsonDecode(bytes.NewReader(message.Payload), &reqParams); err != nil {
|
||||
|
||||
137
vendor/github.com/vektah/gqlparser/validator/schema.go
generated
vendored
137
vendor/github.com/vektah/gqlparser/validator/schema.go
generated
vendored
@@ -184,13 +184,19 @@ func validateDefinition(schema *Schema, def *Definition) *gqlerror.Error {
|
||||
}
|
||||
}
|
||||
|
||||
for _, intf := range def.Interfaces {
|
||||
intDef := schema.Types[intf]
|
||||
if intDef == nil {
|
||||
return gqlerror.ErrorPosf(def.Position, "Undefined type %s.", strconv.Quote(intf))
|
||||
for _, typ := range def.Types {
|
||||
typDef := schema.Types[typ]
|
||||
if typDef == nil {
|
||||
return gqlerror.ErrorPosf(def.Position, "Undefined type %s.", strconv.Quote(typ))
|
||||
}
|
||||
if intDef.Kind != Interface {
|
||||
return gqlerror.ErrorPosf(def.Position, "%s is a non interface type %s.", strconv.Quote(intf), intDef.Kind)
|
||||
if !isValidKind(typDef.Kind, Object) {
|
||||
return gqlerror.ErrorPosf(def.Position, "%s type %s must be %s.", def.Kind, strconv.Quote(typ), kindList(Object))
|
||||
}
|
||||
}
|
||||
|
||||
for _, intf := range def.Interfaces {
|
||||
if err := validateImplements(schema, def, intf); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,6 +205,13 @@ func validateDefinition(schema *Schema, def *Definition) *gqlerror.Error {
|
||||
if len(def.Fields) == 0 {
|
||||
return gqlerror.ErrorPosf(def.Position, "%s must define one or more fields.", def.Kind)
|
||||
}
|
||||
for _, field := range def.Fields {
|
||||
if typ, ok := schema.Types[field.Type.Name()]; ok {
|
||||
if !isValidKind(typ.Kind, Scalar, Object, Interface, Union, Enum) {
|
||||
return gqlerror.ErrorPosf(field.Position, "%s field must be one of %s.", def.Kind, kindList(Scalar, Object, Interface, Union, Enum))
|
||||
}
|
||||
}
|
||||
}
|
||||
case Enum:
|
||||
if len(def.EnumValues) == 0 {
|
||||
return gqlerror.ErrorPosf(def.Position, "%s must define one or more unique enum values.", def.Kind)
|
||||
@@ -207,6 +220,13 @@ func validateDefinition(schema *Schema, def *Definition) *gqlerror.Error {
|
||||
if len(def.Fields) == 0 {
|
||||
return gqlerror.ErrorPosf(def.Position, "%s must define one or more input fields.", def.Kind)
|
||||
}
|
||||
for _, field := range def.Fields {
|
||||
if typ, ok := schema.Types[field.Type.Name()]; ok {
|
||||
if !isValidKind(typ.Kind, Scalar, Enum, InputObject) {
|
||||
return gqlerror.ErrorPosf(field.Position, "%s field must be one of %s.", def.Kind, kindList(Scalar, Enum, InputObject))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for idx, field1 := range def.Fields {
|
||||
@@ -244,6 +264,16 @@ func validateArgs(schema *Schema, args ArgumentDefinitionList, currentDirective
|
||||
if err := validateTypeRef(schema, arg.Type); err != nil {
|
||||
return err
|
||||
}
|
||||
def := schema.Types[arg.Type.Name()]
|
||||
if !def.IsInputType() {
|
||||
return gqlerror.ErrorPosf(
|
||||
arg.Position,
|
||||
"cannot use %s as argument %s because %s is not a valid input type",
|
||||
arg.Type.String(),
|
||||
arg.Name,
|
||||
def.Kind,
|
||||
)
|
||||
}
|
||||
if err := validateDirectives(schema, arg.Directives, currentDirective); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -268,9 +298,104 @@ func validateDirectives(schema *Schema, dirs DirectiveList, currentDirective *Di
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateImplements(schema *Schema, def *Definition, intfName string) *gqlerror.Error {
|
||||
// see validation rules at the bottom of
|
||||
// https://facebook.github.io/graphql/June2018/#sec-Objects
|
||||
intf := schema.Types[intfName]
|
||||
if intf == nil {
|
||||
return gqlerror.ErrorPosf(def.Position, "Undefined type %s.", strconv.Quote(intfName))
|
||||
}
|
||||
if intf.Kind != Interface {
|
||||
return gqlerror.ErrorPosf(def.Position, "%s is a non interface type %s.", strconv.Quote(intfName), intf.Kind)
|
||||
}
|
||||
for _, requiredField := range intf.Fields {
|
||||
foundField := def.Fields.ForName(requiredField.Name)
|
||||
if foundField == nil {
|
||||
return gqlerror.ErrorPosf(def.Position,
|
||||
`For %s to implement %s it must have a field called %s.`,
|
||||
def.Name, intf.Name, requiredField.Name,
|
||||
)
|
||||
}
|
||||
|
||||
if !isCovariant(schema, requiredField.Type, foundField.Type) {
|
||||
return gqlerror.ErrorPosf(foundField.Position,
|
||||
`For %s to implement %s the field %s must have type %s.`,
|
||||
def.Name, intf.Name, requiredField.Name, requiredField.Type.String(),
|
||||
)
|
||||
}
|
||||
|
||||
for _, requiredArg := range requiredField.Arguments {
|
||||
foundArg := foundField.Arguments.ForName(requiredArg.Name)
|
||||
if foundArg == nil {
|
||||
return gqlerror.ErrorPosf(foundField.Position,
|
||||
`For %s to implement %s the field %s must have the same arguments but it is missing %s.`,
|
||||
def.Name, intf.Name, requiredField.Name, requiredArg.Name,
|
||||
)
|
||||
}
|
||||
|
||||
if !requiredArg.Type.IsCompatible(foundArg.Type) {
|
||||
return gqlerror.ErrorPosf(foundArg.Position,
|
||||
`For %s to implement %s the field %s must have the same arguments but %s has the wrong type.`,
|
||||
def.Name, intf.Name, requiredField.Name, requiredArg.Name,
|
||||
)
|
||||
}
|
||||
}
|
||||
for _, foundArgs := range foundField.Arguments {
|
||||
if requiredField.Arguments.ForName(foundArgs.Name) == nil && foundArgs.Type.NonNull && foundArgs.DefaultValue == nil {
|
||||
return gqlerror.ErrorPosf(foundArgs.Position,
|
||||
`For %s to implement %s any additional arguments on %s must be optional or have a default value but %s is required.`,
|
||||
def.Name, intf.Name, foundField.Name, foundArgs.Name,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isCovariant(schema *Schema, required *Type, actual *Type) bool {
|
||||
if required.NonNull && !actual.NonNull {
|
||||
return false
|
||||
}
|
||||
|
||||
if required.NamedType != "" {
|
||||
if required.NamedType == actual.NamedType {
|
||||
return true
|
||||
}
|
||||
for _, pt := range schema.PossibleTypes[required.NamedType] {
|
||||
if pt.Name == actual.NamedType {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
if required.Elem != nil && actual.Elem == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return isCovariant(schema, required.Elem, actual.Elem)
|
||||
}
|
||||
|
||||
func validateName(pos *Position, name string) *gqlerror.Error {
|
||||
if strings.HasPrefix(name, "__") {
|
||||
return gqlerror.ErrorPosf(pos, `Name "%s" must not begin with "__", which is reserved by GraphQL introspection.`, name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isValidKind(kind DefinitionKind, valid ...DefinitionKind) bool {
|
||||
for _, k := range valid {
|
||||
if kind == k {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func kindList(kinds ...DefinitionKind) string {
|
||||
s := make([]string, len(kinds))
|
||||
for i, k := range kinds {
|
||||
s[i] = string(k)
|
||||
}
|
||||
return strings.Join(s, ", ")
|
||||
}
|
||||
|
||||
247
vendor/github.com/vektah/gqlparser/validator/schema_test.yml
generated
vendored
247
vendor/github.com/vektah/gqlparser/validator/schema_test.yml
generated
vendored
@@ -89,6 +89,18 @@ object types:
|
||||
message: 'Name "__bar" must not begin with "__", which is reserved by GraphQL introspection.'
|
||||
locations: [{line: 2, column: 7}]
|
||||
|
||||
- name: must not allow input object as field type
|
||||
input: |
|
||||
input Input {
|
||||
id: ID
|
||||
}
|
||||
type Query {
|
||||
input: Input!
|
||||
}
|
||||
error:
|
||||
message: 'OBJECT field must be one of SCALAR, OBJECT, INTERFACE, UNION, ENUM.'
|
||||
locations: [{line: 5, column: 3}]
|
||||
|
||||
interfaces:
|
||||
- name: must exist
|
||||
input: |
|
||||
@@ -148,6 +160,121 @@ interfaces:
|
||||
message: 'Name "__FooBar" must not begin with "__", which is reserved by GraphQL introspection.'
|
||||
locations: [{line: 1, column: 11}]
|
||||
|
||||
- name: must not allow input object as field type
|
||||
input: |
|
||||
input Input {
|
||||
id: ID
|
||||
}
|
||||
type Query {
|
||||
foo: Foo!
|
||||
}
|
||||
interface Foo {
|
||||
input: Input!
|
||||
}
|
||||
error:
|
||||
message: 'INTERFACE field must be one of SCALAR, OBJECT, INTERFACE, UNION, ENUM.'
|
||||
locations: [{line: 8, column: 3}]
|
||||
|
||||
- name: must have all fields from interface
|
||||
input: |
|
||||
type Bar implements BarInterface {
|
||||
someField: Int!
|
||||
}
|
||||
|
||||
interface BarInterface {
|
||||
id: ID!
|
||||
}
|
||||
error:
|
||||
message: 'For Bar to implement BarInterface it must have a field called id.'
|
||||
locations: [{line: 1, column: 6}]
|
||||
|
||||
- name: must have same type of fields
|
||||
input: |
|
||||
type Bar implements BarInterface {
|
||||
id: Int!
|
||||
}
|
||||
|
||||
interface BarInterface {
|
||||
id: ID!
|
||||
}
|
||||
error:
|
||||
message: 'For Bar to implement BarInterface the field id must have type ID!.'
|
||||
locations: [{line: 2, column: 5}]
|
||||
|
||||
- name: must have all required arguments
|
||||
input: |
|
||||
type Bar implements BarInterface {
|
||||
id: ID!
|
||||
}
|
||||
|
||||
interface BarInterface {
|
||||
id(ff: Int!): ID!
|
||||
}
|
||||
error:
|
||||
message: 'For Bar to implement BarInterface the field id must have the same arguments but it is missing ff.'
|
||||
locations: [{line: 2, column: 5}]
|
||||
|
||||
- name: must have same argument types
|
||||
input: |
|
||||
type Bar implements BarInterface {
|
||||
id(ff: ID!): ID!
|
||||
}
|
||||
|
||||
interface BarInterface {
|
||||
id(ff: Int!): ID!
|
||||
}
|
||||
error:
|
||||
message: 'For Bar to implement BarInterface the field id must have the same arguments but ff has the wrong type.'
|
||||
locations: [{line: 2, column: 8}]
|
||||
|
||||
- name: may defined additional nullable arguments
|
||||
input: |
|
||||
type Bar implements BarInterface {
|
||||
id(opt: Int): ID!
|
||||
}
|
||||
|
||||
interface BarInterface {
|
||||
id: ID!
|
||||
}
|
||||
|
||||
- name: may defined additional required arguments with defaults
|
||||
input: |
|
||||
type Bar implements BarInterface {
|
||||
id(opt: Int! = 1): ID!
|
||||
}
|
||||
|
||||
interface BarInterface {
|
||||
id: ID!
|
||||
}
|
||||
|
||||
- name: must not define additional required arguments without defaults
|
||||
input: |
|
||||
type Bar implements BarInterface {
|
||||
id(opt: Int!): ID!
|
||||
}
|
||||
|
||||
interface BarInterface {
|
||||
id: ID!
|
||||
}
|
||||
error:
|
||||
message: 'For Bar to implement BarInterface any additional arguments on id must be optional or have a default value but opt is required.'
|
||||
locations: [{line: 2, column: 8}]
|
||||
|
||||
- name: can have covariant argument types
|
||||
input: |
|
||||
union U = A|B
|
||||
|
||||
type A { name: String }
|
||||
type B { name: String }
|
||||
|
||||
type Bar implements BarInterface {
|
||||
f: A!
|
||||
}
|
||||
|
||||
interface BarInterface {
|
||||
f: U!
|
||||
}
|
||||
|
||||
inputs:
|
||||
- name: must define one or more input fields
|
||||
input: |
|
||||
@@ -177,6 +304,70 @@ inputs:
|
||||
message: 'Name "__FooBar" must not begin with "__", which is reserved by GraphQL introspection.'
|
||||
locations: [{line: 1, column: 7}]
|
||||
|
||||
- name: fields cannot be Objects
|
||||
input: |
|
||||
type Object { id: ID }
|
||||
input Foo { a: Object! }
|
||||
error:
|
||||
message: INPUT_OBJECT field must be one of SCALAR, ENUM, INPUT_OBJECT.
|
||||
locations: [{line: 2, column: 13}]
|
||||
|
||||
- name: fields cannot be Interfaces
|
||||
input: |
|
||||
interface Interface { id: ID! }
|
||||
input Foo { a: Interface! }
|
||||
error:
|
||||
message: INPUT_OBJECT field must be one of SCALAR, ENUM, INPUT_OBJECT.
|
||||
locations: [{line: 2, column: 13}]
|
||||
|
||||
- name: fields cannot be Unions
|
||||
input: |
|
||||
type Object { id: ID }
|
||||
union Union = Object
|
||||
input Foo { a: Union! }
|
||||
error:
|
||||
message: INPUT_OBJECT field must be one of SCALAR, ENUM, INPUT_OBJECT.
|
||||
locations: [{line: 3, column: 13}]
|
||||
|
||||
args:
|
||||
- name: Valid arg types
|
||||
input: |
|
||||
input Input { id: ID }
|
||||
enum Enum { A }
|
||||
scalar Scalar
|
||||
|
||||
type Query {
|
||||
f(a: Input, b: Scalar, c: Enum): Boolean!
|
||||
}
|
||||
|
||||
- name: Objects not allowed
|
||||
input: |
|
||||
type Object { id: ID }
|
||||
type Query { f(a: Object): Boolean! }
|
||||
|
||||
error:
|
||||
message: 'cannot use Object as argument a because OBJECT is not a valid input type'
|
||||
locations: [{line: 2, column: 16}]
|
||||
|
||||
- name: Union not allowed
|
||||
input: |
|
||||
type Object { id: ID }
|
||||
union Union = Object
|
||||
type Query { f(a: Union): Boolean! }
|
||||
|
||||
error:
|
||||
message: 'cannot use Union as argument a because UNION is not a valid input type'
|
||||
locations: [{line: 3, column: 16}]
|
||||
|
||||
- name: Interface not allowed
|
||||
input: |
|
||||
interface Interface { id: ID }
|
||||
type Query { f(a: Interface): Boolean! }
|
||||
|
||||
error:
|
||||
message: 'cannot use Interface as argument a because INTERFACE is not a valid input type'
|
||||
locations: [{line: 2, column: 16}]
|
||||
|
||||
enums:
|
||||
- name: must define one or more unique enum values
|
||||
input: |
|
||||
@@ -207,6 +398,26 @@ enums:
|
||||
message: 'Name "__FooBar" must not begin with "__", which is reserved by GraphQL introspection.'
|
||||
locations: [{line: 1, column: 6}]
|
||||
|
||||
unions:
|
||||
- name: union types must be defined
|
||||
input: |
|
||||
union Foo = Bar | Baz
|
||||
type Bar {
|
||||
id: ID
|
||||
}
|
||||
error:
|
||||
message: "Undefined type \"Baz\"."
|
||||
locations: [{line: 1, column: 7}]
|
||||
- name: union types must be objects
|
||||
input: |
|
||||
union Foo = Baz
|
||||
interface Baz {
|
||||
id: ID
|
||||
}
|
||||
error:
|
||||
message: "UNION type \"Baz\" must be OBJECT."
|
||||
locations: [{line: 1, column: 7}]
|
||||
|
||||
type extensions:
|
||||
- name: cannot extend non existant types
|
||||
input: |
|
||||
@@ -258,6 +469,42 @@ directives:
|
||||
message: 'Name "__A" must not begin with "__", which is reserved by GraphQL introspection.'
|
||||
locations: [{line: 1, column: 12}]
|
||||
|
||||
- name: Valid arg types
|
||||
input: |
|
||||
input Input { id: ID }
|
||||
enum Enum { A }
|
||||
scalar Scalar
|
||||
|
||||
directive @A(a: Input, b: Scalar, c: Enum) on FIELD_DEFINITION
|
||||
|
||||
- name: Objects not allowed
|
||||
input: |
|
||||
type Object { id: ID }
|
||||
directive @A(a: Object) on FIELD_DEFINITION
|
||||
|
||||
error:
|
||||
message: 'cannot use Object as argument a because OBJECT is not a valid input type'
|
||||
locations: [{line: 2, column: 14}]
|
||||
|
||||
- name: Union not allowed
|
||||
input: |
|
||||
type Object { id: ID }
|
||||
union Union = Object
|
||||
directive @A(a: Union) on FIELD_DEFINITION
|
||||
|
||||
error:
|
||||
message: 'cannot use Union as argument a because UNION is not a valid input type'
|
||||
locations: [{line: 3, column: 14}]
|
||||
|
||||
- name: Interface not allowed
|
||||
input: |
|
||||
interface Interface { id: ID }
|
||||
directive @A(a: Interface) on FIELD_DEFINITION
|
||||
|
||||
error:
|
||||
message: 'cannot use Interface as argument a because INTERFACE is not a valid input type'
|
||||
locations: [{line: 2, column: 14}]
|
||||
|
||||
entry points:
|
||||
- name: multiple schema entry points
|
||||
input: |
|
||||
|
||||
Reference in New Issue
Block a user