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 ObjTypeMap map[reflect.Type]*graphql.Object
type GQLInterface struct {
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
type GQLExtContext struct {
// Generated GQL schema
Schema graphql.Schema
// List of GQL types
TypeList []graphql.Type
// 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
// Custom graphql types, mapped to NodeTypes
NodeTypes map[NodeType]*graphql.Object
Interfaces []*GQLInterface
// Schema parameters
Types []graphql.Type
Query *graphql.Object
Mutation *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 {
query := graphql.NewObject(graphql.ObjectConfig{
Name: "Query",
Fields: graphql.Fields{},
})
query.AddFieldConfig("Self", GQLQuerySelf)
query.AddFieldConfig("User", GQLQueryUser)
mutation := graphql.NewObject(graphql.ObjectConfig{
Name: "Mutation",
Fields: graphql.Fields{},
})
mutation.AddFieldConfig("abort", GQLMutationAbort)
mutation.AddFieldConfig("startChild", GQLMutationStartChild)
subscription := graphql.NewObject(graphql.ObjectConfig{
Name: "Subscription",
Fields: graphql.Fields{},
})
subscription.AddFieldConfig("Self", GQLSubscriptionSelf)
subscription.AddFieldConfig("Update", GQLSubscriptionUpdate)
context := GQLExtContext{
Schema: graphql.Schema{},
TypeList: []graphql.Type{},
ValidNodes: ObjTypeMap{},
ValidThreads: ObjTypeMap{},
ValidLockables: ObjTypeMap{},
Types: []graphql.Type{},
Query: query,
Mutation: mutation,
Subscription: subscription,
BaseNodeType: GQLTypeBaseNode.Type,
BaseLockableType: GQLTypeBaseLockable.Type,
BaseThreadType: GQLTypeBaseThread.Type,
NodeTypes: map[NodeType]*graphql.Object{},
Interfaces: []*GQLInterface{},
}
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
}

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

@ -4,123 +4,6 @@ import (
"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 {
gql_type_signal := graphql.NewObject(graphql.ObjectConfig{
Name: "Signal",