Added default schema back without crashing

gql_cataclysm
noah metz 2023-07-26 20:26:41 -06:00
parent 294bcfb518
commit 34082630b2
5 changed files with 237 additions and 248 deletions

129
gql.go

@ -645,61 +645,150 @@ func GQLWSHandler(ctx * Context, server *Node, gql_ext *GQLExt) func(http.Respon
} }
} }
// Map of go types to graphql types type GQLInterface struct {
type ObjTypeMap map[reflect.Type]*graphql.Object Interface *graphql.Interface
Default *graphql.Object
List *graphql.List
Extensions []ExtType
}
func NewGQLInterface(if_name string, default_name string, interfaces []*graphql.Interface, extensions []ExtType, init_1 func(*GQLInterface), init_2 func(*GQLInterface)) *GQLInterface {
var gql GQLInterface
gql.Extensions = extensions
gql.Interface = graphql.NewInterface(graphql.InterfaceConfig{
Name: if_name,
ResolveType: NodeResolver([]ExtType{}, &gql.Default),
Fields: graphql.Fields{},
})
gql.List = graphql.NewList(gql.Interface)
init_1(&gql)
gql.Default = graphql.NewObject(graphql.ObjectConfig{
Name: default_name,
Interfaces: append(interfaces, gql.Interface),
IsTypeOf: GQLNodeHasExtensions([]ExtType{}),
Fields: graphql.Fields{},
})
init_2(&gql)
return &gql
}
// GQL Specific Context information // GQL Specific Context information
type GQLExtContext struct { type GQLExtContext struct {
// Generated GQL schema // Generated GQL schema
Schema graphql.Schema Schema graphql.Schema
// List of GQL types // Custom graphql types, mapped to NodeTypes
TypeList []graphql.Type NodeTypes map[NodeType]*graphql.Object
Interfaces []*GQLInterface
// Interface type maps to map go types of specific interfaces to gql types
ValidNodes ObjTypeMap
ValidLockables ObjTypeMap
ValidThreads ObjTypeMap
BaseNodeType *graphql.Object
BaseLockableType *graphql.Object
BaseThreadType *graphql.Object
// Schema parameters
Types []graphql.Type
Query *graphql.Object Query *graphql.Object
Mutation *graphql.Object Mutation *graphql.Object
Subscription *graphql.Object Subscription *graphql.Object
} }
func BuildSchema(ctx *GQLExtContext) (graphql.Schema, error) {
schemaConfig := graphql.SchemaConfig{
Types: ctx.Types,
Query: ctx.Query,
Mutation: ctx.Mutation,
Subscription: ctx.Subscription,
}
return graphql.NewSchema(schemaConfig)
}
func (ctx *GQLExtContext) AddInterface(i *GQLInterface) error {
if i == nil {
return fmt.Errorf("interface is nil")
}
if i.Interface == nil || i.Extensions == nil || i.Default == nil || i.List == nil {
return fmt.Errorf("invalid interface, contains nil")
}
ctx.Interfaces = append(ctx.Interfaces, i)
ctx.Types = append(ctx.Types, i.Default)
return nil
}
func (ctx *GQLExtContext) RegisterNodeType(node_type NodeType, gql_type *graphql.Object) error {
if gql_type == nil {
return fmt.Errorf("gql_type is nil")
}
_, exists := ctx.NodeTypes[node_type]
if exists == true {
return fmt.Errorf("%s already in GQLExtContext.NodeTypes", node_type)
}
ctx.NodeTypes[node_type] = gql_type
ctx.Types = append(ctx.Types, gql_type)
return nil
}
func NewGQLExtContext() *GQLExtContext { func NewGQLExtContext() *GQLExtContext {
query := graphql.NewObject(graphql.ObjectConfig{ query := graphql.NewObject(graphql.ObjectConfig{
Name: "Query", Name: "Query",
Fields: graphql.Fields{}, Fields: graphql.Fields{},
}) })
query.AddFieldConfig("Self", GQLQuerySelf)
query.AddFieldConfig("User", GQLQueryUser)
mutation := graphql.NewObject(graphql.ObjectConfig{ mutation := graphql.NewObject(graphql.ObjectConfig{
Name: "Mutation", Name: "Mutation",
Fields: graphql.Fields{}, Fields: graphql.Fields{},
}) })
mutation.AddFieldConfig("abort", GQLMutationAbort)
mutation.AddFieldConfig("startChild", GQLMutationStartChild)
subscription := graphql.NewObject(graphql.ObjectConfig{ subscription := graphql.NewObject(graphql.ObjectConfig{
Name: "Subscription", Name: "Subscription",
Fields: graphql.Fields{}, Fields: graphql.Fields{},
}) })
subscription.AddFieldConfig("Self", GQLSubscriptionSelf)
subscription.AddFieldConfig("Update", GQLSubscriptionUpdate)
context := GQLExtContext{ context := GQLExtContext{
Schema: graphql.Schema{}, Schema: graphql.Schema{},
TypeList: []graphql.Type{}, Types: []graphql.Type{},
ValidNodes: ObjTypeMap{},
ValidThreads: ObjTypeMap{},
ValidLockables: ObjTypeMap{},
Query: query, Query: query,
Mutation: mutation, Mutation: mutation,
Subscription: subscription, Subscription: subscription,
BaseNodeType: GQLTypeBaseNode.Type, NodeTypes: map[NodeType]*graphql.Object{},
BaseLockableType: GQLTypeBaseLockable.Type, Interfaces: []*GQLInterface{},
BaseThreadType: GQLTypeBaseThread.Type,
} }
var err error
err = context.AddInterface(GQLInterfaceNode)
if err != nil {
panic(err)
}
err = context.AddInterface(GQLInterfaceLockable)
if err != nil {
panic(err)
}
err = context.AddInterface(GQLInterfaceThread)
if err != nil {
panic(err)
}
schema, err := BuildSchema(&context)
if err != nil {
panic(err)
}
context.Schema = schema
return &context return &context
} }

@ -2,8 +2,6 @@ package graphvent
import ( import (
"github.com/graphql-go/graphql" "github.com/graphql-go/graphql"
"reflect"
"fmt"
) )
func NewField(init func()*graphql.Field) *graphql.Field { func NewField(init func()*graphql.Field) *graphql.Field {
@ -27,146 +25,165 @@ func NewSingleton[K graphql.Type](init func() K, post_init func(K, *graphql.List
} }
} }
func AddNodeInterfaceFields(i *graphql.Interface) { func AddNodeInterfaceFields(gql *GQLInterface) {
i.AddFieldConfig("ID", &graphql.Field{ gql.Interface.AddFieldConfig("ID", &graphql.Field{
Type: graphql.String, Type: graphql.String,
}) })
i.AddFieldConfig("TypeHash", &graphql.Field{ gql.Interface.AddFieldConfig("TypeHash", &graphql.Field{
Type: graphql.String, Type: graphql.String,
}) })
} }
func PrepTypeResolve(p graphql.ResolveTypeParams) (*ResolveContext, error) { func AddNodeFields(gql *GQLInterface) {
resolve_context, ok := p.Context.Value("resolve").(*ResolveContext) gql.Default.AddFieldConfig("ID", &graphql.Field{
if ok == false { Type: graphql.String,
return nil, fmt.Errorf("Bad resolve in params context") Resolve: GQLNodeID,
} })
return resolve_context, nil
gql.Default.AddFieldConfig("TypeHash", &graphql.Field{
Type: graphql.String,
Resolve: GQLNodeTypeHash,
})
} }
var GQLInterfaceNode = NewSingleton(func() *graphql.Interface { func LockableInterfaceFields(gql *GQLInterface) {
i := graphql.NewInterface(graphql.InterfaceConfig{ AddLockableInterfaceFields(gql, gql)
Name: "Node", }
ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object {
ctx, err := PrepTypeResolve(p)
if err != nil {
return nil
}
valid_nodes := ctx.GQLContext.ValidNodes func AddLockableInterfaceFields(gql *GQLInterface, gql_lockable *GQLInterface) {
p_type := reflect.TypeOf(p.Value) AddNodeInterfaceFields(gql)
for key, value := range(valid_nodes) { gql.Interface.AddFieldConfig("Requirements", &graphql.Field{
if p_type == key { Type: gql_lockable.List,
return value })
}
}
_, ok := p.Value.(Node) gql.Interface.AddFieldConfig("Dependencies", &graphql.Field{
if ok == true { Type: gql_lockable.List,
return ctx.GQLContext.BaseNodeType })
}
return nil gql.Interface.AddFieldConfig("Owner", &graphql.Field{
}, Type: gql_lockable.Interface,
Fields: graphql.Fields{},
}) })
}
AddNodeInterfaceFields(i) func LockableFields(gql *GQLInterface) {
AddLockableFields(gql, gql)
}
return i func AddLockableFields(gql *GQLInterface, gql_lockable *GQLInterface) {
}, nil) AddNodeFields(gql)
var GQLInterfaceLockable = NewSingleton(func() *graphql.Interface { gql.Default.AddFieldConfig("Requirements", &graphql.Field{
gql_interface_lockable := graphql.NewInterface(graphql.InterfaceConfig{ Type: gql_lockable.List,
Name: "Lockable", Resolve: GQLLockableRequirements,
ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object { })
ctx, err := PrepTypeResolve(p)
if err != nil {
return nil
}
valid_lockables := ctx.GQLContext.ValidLockables gql.Default.AddFieldConfig("Owner", &graphql.Field{
p_type := reflect.TypeOf(p.Value) Type: gql_lockable.Interface,
Resolve: GQLLockableOwner,
})
for key, value := range(valid_lockables) { gql.Default.AddFieldConfig("Dependencies", &graphql.Field{
if p_type == key { Type: gql_lockable.List,
return value Resolve: GQLLockableDependencies,
} })
} }
_, ok := p.Value.(*Node) func ThreadInterfaceFields(gql *GQLInterface) {
if ok == false { AddThreadInterfaceFields(gql, GQLInterfaceLockable, gql)
return ctx.GQLContext.BaseLockableType }
}
return nil func AddThreadInterfaceFields(gql *GQLInterface, gql_lockable *GQLInterface, gql_thread *GQLInterface) {
}, AddLockableInterfaceFields(gql, gql_lockable)
Fields: graphql.Fields{},
gql.Interface.AddFieldConfig("Children", &graphql.Field{
Type: gql_thread.List,
})
gql.Interface.AddFieldConfig("Parent", &graphql.Field{
Type: gql_thread.Interface,
}) })
}
func ThreadFields(gql *GQLInterface) {
AddThreadFields(gql, GQLInterfaceLockable, gql)
}
return gql_interface_lockable func AddThreadFields(gql *GQLInterface, gql_lockable *GQLInterface, gql_thread *GQLInterface) {
}, func(lockable *graphql.Interface, lockable_list *graphql.List) { AddLockableFields(gql, gql_lockable)
lockable.AddFieldConfig("Requirements", &graphql.Field{
Type: lockable_list, gql.Default.AddFieldConfig("State", &graphql.Field{
Type: graphql.String,
Resolve: GQLThreadState,
}) })
lockable.AddFieldConfig("Dependencies", &graphql.Field{ gql.Default.AddFieldConfig("Children", &graphql.Field{
Type: lockable_list, Type: gql_thread.List,
Resolve: GQLThreadChildren,
}) })
lockable.AddFieldConfig("Owner", &graphql.Field{ gql.Default.AddFieldConfig("Parent", &graphql.Field{
Type: lockable, Type: gql_thread.Interface,
Resolve: GQLThreadParent,
}) })
AddNodeInterfaceFields(lockable) }
})
var GQLInterfaceThread = NewSingleton(func() *graphql.Interface {
gql_interface_thread := graphql.NewInterface(graphql.InterfaceConfig{
Name: "Thread",
ResolveType: func(p graphql.ResolveTypeParams) *graphql.Object {
ctx, err := PrepTypeResolve(p)
if err != nil {
return nil
}
valid_threads := ctx.GQLContext.ValidThreads func NodeHasExtensions(node *Node, extensions []ExtType) bool {
p_type := reflect.TypeOf(p.Value) if node == nil {
return false
}
for key, value := range(valid_threads) { for _, ext := range(extensions) {
if p_type == key { _, has := node.Extensions[ext]
return value if has == false {
} return false
} }
}
node, ok := p.Value.(*Node) return true
if ok == false { }
return nil
}
_, err = GetExt[*ThreadExt](node) func GQLNodeHasExtensions(extensions []ExtType) func(graphql.IsTypeOfParams) bool {
if err == nil { return func(p graphql.IsTypeOfParams) bool {
return ctx.GQLContext.BaseThreadType node, ok := p.Value.(*Node)
} if ok == false {
return false
}
return NodeHasExtensions(node, extensions)
}
}
func NodeResolver(required_extensions []ExtType, default_type **graphql.Object)func(graphql.ResolveTypeParams) *graphql.Object {
return func(p graphql.ResolveTypeParams) *graphql.Object {
ctx, ok := p.Context.Value("resolve").(*ResolveContext)
if ok == false {
return nil return nil
}, }
Fields: graphql.Fields{},
})
return gql_interface_thread node, ok := p.Value.(*Node)
}, func(thread *graphql.Interface, thread_list *graphql.List) { if ok == false {
thread.AddFieldConfig("Children", &graphql.Field{ return nil
Type: thread_list, }
})
gql_type, exists := ctx.GQLContext.NodeTypes[node.Type]
if exists == false {
for _, ext := range(required_extensions) {
_, exists := node.Extensions[ext]
if exists == false {
return nil
}
}
return *default_type
}
thread.AddFieldConfig("Parent", &graphql.Field{ return gql_type
Type: thread, }
}) }
thread.AddFieldConfig("State", &graphql.Field{ var GQLInterfaceNode = NewGQLInterface("Node", "DefaultNode", []*graphql.Interface{}, []ExtType{}, AddNodeInterfaceFields, AddNodeFields)
Type: graphql.String,
}) var GQLInterfaceLockable = NewGQLInterface("Lockable", "DefaultLockable", []*graphql.Interface{GQLInterfaceNode.Interface}, []ExtType{LockableExtType}, LockableInterfaceFields, LockableFields)
AddNodeInterfaceFields(thread) var GQLInterfaceThread = NewGQLInterface("Thread", "DefaultThread", []*graphql.Interface{GQLInterfaceNode.Interface, }, []ExtType{ThreadExtType, LockableExtType}, ThreadInterfaceFields, ThreadFields)
})

@ -4,7 +4,7 @@ import (
) )
var GQLQuerySelf = &graphql.Field{ var GQLQuerySelf = &graphql.Field{
Type: GQLTypeBaseThread.Type, Type: GQLInterfaceThread.Default,
Resolve: func(p graphql.ResolveParams) (interface{}, error) { Resolve: func(p graphql.ResolveParams) (interface{}, error) {
_, ctx, err := PrepResolve(p) _, ctx, err := PrepResolve(p)
if err != nil { if err != nil {
@ -16,7 +16,7 @@ var GQLQuerySelf = &graphql.Field{
} }
var GQLQueryUser = &graphql.Field{ var GQLQueryUser = &graphql.Field{
Type: GQLTypeBaseNode.Type, Type: GQLInterfaceNode.Default,
Resolve: func(p graphql.ResolveParams) (interface{}, error) { Resolve: func(p graphql.ResolveParams) (interface{}, error) {
_, ctx, err := PrepResolve(p) _, ctx, err := PrepResolve(p)
if err != nil { if err != nil {

@ -46,7 +46,7 @@ func GQLSubscribeFn(p graphql.ResolveParams, send_nil bool, fn func(*Context, *N
var GQLSubscriptionSelf = NewField(func()*graphql.Field{ var GQLSubscriptionSelf = NewField(func()*graphql.Field{
gql_subscription_self := &graphql.Field{ gql_subscription_self := &graphql.Field{
Type: GQLTypeBaseThread.Type, Type: GQLInterfaceThread.Default,
Resolve: func(p graphql.ResolveParams) (interface{}, error) { Resolve: func(p graphql.ResolveParams) (interface{}, error) {
return p.Source, nil return p.Source, nil
}, },

@ -4,123 +4,6 @@ import (
"github.com/graphql-go/graphql" "github.com/graphql-go/graphql"
) )
func AddNodeFields(obj *graphql.Object) {
obj.AddFieldConfig("ID", &graphql.Field{
Type: graphql.String,
Resolve: GQLNodeID,
})
obj.AddFieldConfig("TypeHash", &graphql.Field{
Type: graphql.String,
Resolve: GQLNodeTypeHash,
})
}
func AddLockableFields(obj *graphql.Object) {
AddNodeFields(obj)
obj.AddFieldConfig("Requirements", &graphql.Field{
Type: GQLInterfaceLockable.List,
Resolve: GQLLockableRequirements,
})
obj.AddFieldConfig("Owner", &graphql.Field{
Type: GQLInterfaceLockable.Type,
Resolve: GQLLockableOwner,
})
obj.AddFieldConfig("Dependencies", &graphql.Field{
Type: GQLInterfaceLockable.List,
Resolve: GQLLockableDependencies,
})
}
func AddThreadFields(obj *graphql.Object) {
AddNodeFields(obj)
obj.AddFieldConfig("State", &graphql.Field{
Type: graphql.String,
Resolve: GQLThreadState,
})
obj.AddFieldConfig("Children", &graphql.Field{
Type: GQLInterfaceThread.List,
Resolve: GQLThreadChildren,
})
obj.AddFieldConfig("Parent", &graphql.Field{
Type: GQLInterfaceThread.Type,
Resolve: GQLThreadParent,
})
}
var GQLTypeBaseThread = NewSingleton(func() *graphql.Object {
gql_type_simple_thread := graphql.NewObject(graphql.ObjectConfig{
Name: "SimpleThread",
Interfaces: []*graphql.Interface{
GQLInterfaceNode.Type,
GQLInterfaceThread.Type,
GQLInterfaceLockable.Type,
},
IsTypeOf: func(p graphql.IsTypeOfParams) bool {
node, ok := p.Value.(*Node)
if ok == false {
return false
}
_, err := GetExt[*ThreadExt](node)
return err == nil
},
Fields: graphql.Fields{},
})
AddThreadFields(gql_type_simple_thread)
return gql_type_simple_thread
}, nil)
var GQLTypeBaseLockable = NewSingleton(func() *graphql.Object {
gql_type_simple_lockable := graphql.NewObject(graphql.ObjectConfig{
Name: "SimpleLockable",
Interfaces: []*graphql.Interface{
GQLInterfaceNode.Type,
GQLInterfaceLockable.Type,
},
IsTypeOf: func(p graphql.IsTypeOfParams) bool {
node, ok := p.Value.(*Node)
if ok == false {
return false
}
_, err := GetExt[*LockableExt](node)
return err == nil
},
Fields: graphql.Fields{},
})
AddLockableFields(gql_type_simple_lockable)
return gql_type_simple_lockable
}, nil)
var GQLTypeBaseNode = NewSingleton(func() *graphql.Object {
object := graphql.NewObject(graphql.ObjectConfig{
Name: "SimpleNode",
Interfaces: []*graphql.Interface{
GQLInterfaceNode.Type,
},
IsTypeOf: func(p graphql.IsTypeOfParams) bool {
_, ok := p.Value.(*Node)
return ok
},
Fields: graphql.Fields{},
})
AddNodeFields(object)
return object
}, nil)
var GQLTypeSignal = NewSingleton(func() *graphql.Object { var GQLTypeSignal = NewSingleton(func() *graphql.Object {
gql_type_signal := graphql.NewObject(graphql.ObjectConfig{ gql_type_signal := graphql.NewObject(graphql.ObjectConfig{
Name: "Signal", Name: "Signal",