From 9ffa9d6cb2ff2163771109f3952bfc048cdf3d76 Mon Sep 17 00:00:00 2001 From: Noah Metz Date: Mon, 18 Sep 2023 11:15:58 -0600 Subject: [PATCH] Reorganized GQL files, and moved from modifying the GQL library to using a NodeCache in ResolveContext --- go.mod | 4 +- go.sum | 2 + gql.go | 137 +++++++++++++++++++++++++++++++++++- gql_interfaces.go | 98 -------------------------- gql_mutation.go | 4 -- gql_query.go => gql_node.go | 19 +++++ gql_resolvers.go | 83 ---------------------- gql_subscribe.go | 4 -- gql_test.go | 2 +- gql_types.go | 37 ---------- graphql | 1 - 11 files changed, 158 insertions(+), 233 deletions(-) delete mode 100644 gql_interfaces.go delete mode 100644 gql_mutation.go rename gql_query.go => gql_node.go (83%) delete mode 100644 gql_resolvers.go delete mode 100644 gql_subscribe.go delete mode 100644 gql_types.go delete mode 160000 graphql diff --git a/go.mod b/go.mod index db9aa2c..2b2dcd2 100644 --- a/go.mod +++ b/go.mod @@ -4,14 +4,11 @@ go 1.21.0 replace github.com/mekkanized/graphvent/signal v0.0.0 => ./signal -replace github.com/graphql-go/graphql v0.0.0 => ./graphql - require ( capnproto.org/go/capnp/v3 v3.0.0-alpha-29 github.com/dgraph-io/badger/v3 v3.2103.5 github.com/gobwas/ws v1.2.1 github.com/google/uuid v1.3.0 - github.com/graphql-go/graphql v0.0.0 github.com/mekkanized/graphvent/signal v0.0.0 github.com/rs/zerolog v1.29.1 golang.org/x/net v0.7.0 @@ -30,6 +27,7 @@ require ( github.com/golang/protobuf v1.3.1 // indirect github.com/golang/snappy v0.0.3 // indirect github.com/google/flatbuffers v1.12.1 // indirect + github.com/graphql-go/graphql v0.8.1 // indirect github.com/klauspost/compress v1.12.3 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect diff --git a/go.sum b/go.sum index 1a9334c..53e47b6 100644 --- a/go.sum +++ b/go.sum @@ -53,6 +53,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/graphql-go/graphql v0.8.1 h1:p7/Ou/WpmulocJeEx7wjQy611rtXGQaAcXGqanuMMgc= +github.com/graphql-go/graphql v0.8.1/go.mod h1:nKiHzRM0qopJEwCITUuIsxk9PlVlwIiiI8pnJEhordQ= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= diff --git a/gql.go b/gql.go index 8257578..a74560a 100644 --- a/gql.go +++ b/gql.go @@ -31,6 +31,137 @@ import ( "github.com/google/uuid" ) +func NodeInterfaceDefaultIsType(required_extensions []ExtType) func(graphql.IsTypeOfParams) bool { + return func(p graphql.IsTypeOfParams) bool { + ctx, ok := p.Context.Value("resolve").(*ResolveContext) + if ok == false { + return false + } + node, ok := p.Value.(NodeResult) + if ok == false { + return false + } + + node_type_def, exists := ctx.Context.Nodes[node.Result.NodeType] + if exists == false { + return false + } else { + for _, ext := range(required_extensions) { + found := false + for _, e := range(node_type_def.Extensions) { + if e == ext { + found = true + break + } + } + if found == false { + return false + } + } + } + + return true + } +} + +func NodeInterfaceResolveType(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 + } + + node, ok := p.Value.(NodeResult) + if ok == false { + return nil + } + + gql_type, exists := ctx.GQLContext.NodeTypes[node.Result.NodeType] + ctx.Context.Log.Logf("gql", "GQL_INTERFACE_RESOLVE_TYPE(%+v): %+v - %t - %+v - %+v", node, gql_type, exists, required_extensions, *default_type) + if exists == false { + node_type_def, exists := ctx.Context.Nodes[node.Result.NodeType] + if exists == false { + return nil + } else { + for _, ext := range(required_extensions) { + found := false + for _, e := range(node_type_def.Extensions) { + if e == ext { + found = true + break + } + } + if found == false { + return nil + } + } + } + return *default_type + } + + return gql_type + } +} + +func PrepResolve(p graphql.ResolveParams) (*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 +} + +// TODO: Make composabe by checkinf if K is a slice, then recursing in the same way that ExtractList does +func ExtractParam[K interface{}](p graphql.ResolveParams, name string) (K, error) { + var zero K + arg_if, ok := p.Args[name] + if ok == false { + return zero, fmt.Errorf("No Arg of name %s", name) + } + + arg, ok := arg_if.(K) + if ok == false { + return zero, fmt.Errorf("Failed to cast arg %s(%+v) to %+v", name, arg_if, reflect.TypeOf(zero)) + } + + return arg, nil +} + +func ExtractList[K interface{}](p graphql.ResolveParams, name string) ([]K, error) { + var zero K + + arg_list, err := ExtractParam[[]interface{}](p, name) + if err != nil { + return nil, err + } + + ret := make([]K, len(arg_list)) + for i, val := range(arg_list) { + val_conv, ok := arg_list[i].(K) + if ok == false { + return nil, fmt.Errorf("Failed to cast arg %s[%d](%+v) to %+v", name, i, val, reflect.TypeOf(zero)) + } + ret[i] = val_conv + } + + return ret, nil +} + +func ExtractID(p graphql.ResolveParams, name string) (NodeID, error) { + id_str, err := ExtractParam[string](p, name) + if err != nil { + return ZeroID, err + } + + id, err := ParseID(id_str) + if err != nil { + return ZeroID, err + } + + return id, nil +} + func GraphiQLHandler() func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r * http.Request) { graphiql_string := fmt.Sprintf(` @@ -185,6 +316,9 @@ type ResolveContext struct { // ID of the user that made this request User NodeID + // Cache of resolved nodes + NodeCache map[NodeID]interface{} + // Key for the user that made this request, to sign resolver requests // TODO: figure out some way to use a generated key so that the server can't impersonate the user afterwards Key ed25519.PrivateKey @@ -949,9 +1083,8 @@ func NewGQLExtContext() *GQLExtContext { switch source := p.Source.(type) { case NodeResult: self_result = source - ctx.Context.Log.Logf("gql", "FIRST_RESULT_RECEIVED") + ctx.Context.Log.Logf("gql_subscribe", "SUBSCRIBE_FIRST_RESULT: %+v", self_result) case StatusSignal: - // Look for Source in p.Execution.LastResult and delete references default: return nil, fmt.Errorf("Don't know how to handle %+v", source) } diff --git a/gql_interfaces.go b/gql_interfaces.go deleted file mode 100644 index d213d2f..0000000 --- a/gql_interfaces.go +++ /dev/null @@ -1,98 +0,0 @@ -package graphvent - -import ( - "github.com/graphql-go/graphql" -) - -func NewField(init func()*graphql.Field) *graphql.Field { - return init() -} - -type Singleton[K graphql.Type] struct { - Type K - List *graphql.List -} - -func NewSingleton[K graphql.Type](init func() K, post_init func(K, *graphql.List)) *Singleton[K] { - val := init() - list := graphql.NewList(val) - if post_init != nil { - post_init(val, list) - } - return &Singleton[K]{ - Type: val, - List: list, - } -} - -func NodeInterfaceDefaultIsType(required_extensions []ExtType) func(graphql.IsTypeOfParams) bool { - return func(p graphql.IsTypeOfParams) bool { - ctx, ok := p.Context.Value("resolve").(*ResolveContext) - if ok == false { - return false - } - node, ok := p.Value.(NodeResult) - if ok == false { - return false - } - - node_type_def, exists := ctx.Context.Nodes[node.Result.NodeType] - if exists == false { - return false - } else { - for _, ext := range(required_extensions) { - found := false - for _, e := range(node_type_def.Extensions) { - if e == ext { - found = true - break - } - } - if found == false { - return false - } - } - } - - return true - } -} - -func NodeInterfaceResolveType(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 - } - - node, ok := p.Value.(NodeResult) - if ok == false { - return nil - } - - gql_type, exists := ctx.GQLContext.NodeTypes[node.Result.NodeType] - ctx.Context.Log.Logf("gql", "GQL_INTERFACE_RESOLVE_TYPE(%+v): %+v - %t - %+v - %+v", node, gql_type, exists, required_extensions, *default_type) - if exists == false { - node_type_def, exists := ctx.Context.Nodes[node.Result.NodeType] - if exists == false { - return nil - } else { - for _, ext := range(required_extensions) { - found := false - for _, e := range(node_type_def.Extensions) { - if e == ext { - found = true - break - } - } - if found == false { - return nil - } - } - } - return *default_type - } - - return gql_type - } -} diff --git a/gql_mutation.go b/gql_mutation.go deleted file mode 100644 index 948021c..0000000 --- a/gql_mutation.go +++ /dev/null @@ -1,4 +0,0 @@ -package graphvent -import ( -) - diff --git a/gql_query.go b/gql_node.go similarity index 83% rename from gql_query.go rename to gql_node.go index 6482dc0..9c0d8ee 100644 --- a/gql_query.go +++ b/gql_node.go @@ -2,11 +2,30 @@ package graphvent import ( "time" "reflect" + "fmt" "github.com/graphql-go/graphql" "github.com/graphql-go/graphql/language/ast" "github.com/google/uuid" ) +func ResolveNodeID(p graphql.ResolveParams) (interface{}, error) { + node, ok := p.Source.(NodeResult) + if ok == false { + return nil, fmt.Errorf("Can't get NodeID from %+v", reflect.TypeOf(p.Source)) + } + + return node.ID, nil +} + +func ResolveNodeTypeHash(p graphql.ResolveParams) (interface{}, error) { + node, ok := p.Source.(NodeResult) + if ok == false { + return nil, fmt.Errorf("Can't get TypeHash from %+v", reflect.TypeOf(p.Source)) + } + + return uint64(node.Result.NodeType), nil +} + func GetFieldNames(ctx *Context, selection_set *ast.SelectionSet) []string { names := []string{} if selection_set == nil { diff --git a/gql_resolvers.go b/gql_resolvers.go deleted file mode 100644 index cacc0a7..0000000 --- a/gql_resolvers.go +++ /dev/null @@ -1,83 +0,0 @@ -package graphvent -import ( - "fmt" - "reflect" - "github.com/graphql-go/graphql" -) - -func PrepResolve(p graphql.ResolveParams) (*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 -} - -// TODO: Make composabe by checkinf if K is a slice, then recursing in the same way that ExtractList does -func ExtractParam[K interface{}](p graphql.ResolveParams, name string) (K, error) { - var zero K - arg_if, ok := p.Args[name] - if ok == false { - return zero, fmt.Errorf("No Arg of name %s", name) - } - - arg, ok := arg_if.(K) - if ok == false { - return zero, fmt.Errorf("Failed to cast arg %s(%+v) to %+v", name, arg_if, reflect.TypeOf(zero)) - } - - return arg, nil -} - -func ExtractList[K interface{}](p graphql.ResolveParams, name string) ([]K, error) { - var zero K - - arg_list, err := ExtractParam[[]interface{}](p, name) - if err != nil { - return nil, err - } - - ret := make([]K, len(arg_list)) - for i, val := range(arg_list) { - val_conv, ok := arg_list[i].(K) - if ok == false { - return nil, fmt.Errorf("Failed to cast arg %s[%d](%+v) to %+v", name, i, val, reflect.TypeOf(zero)) - } - ret[i] = val_conv - } - - return ret, nil -} - -func ExtractID(p graphql.ResolveParams, name string) (NodeID, error) { - id_str, err := ExtractParam[string](p, name) - if err != nil { - return ZeroID, err - } - - id, err := ParseID(id_str) - if err != nil { - return ZeroID, err - } - - return id, nil -} - -func ResolveNodeID(p graphql.ResolveParams) (interface{}, error) { - node, ok := p.Source.(NodeResult) - if ok == false { - return nil, fmt.Errorf("Can't get NodeID from %+v", reflect.TypeOf(p.Source)) - } - - return node.ID, nil -} - -func ResolveNodeTypeHash(p graphql.ResolveParams) (interface{}, error) { - node, ok := p.Source.(NodeResult) - if ok == false { - return nil, fmt.Errorf("Can't get TypeHash from %+v", reflect.TypeOf(p.Source)) - } - - return uint64(node.Result.NodeType), nil -} diff --git a/gql_subscribe.go b/gql_subscribe.go deleted file mode 100644 index 948021c..0000000 --- a/gql_subscribe.go +++ /dev/null @@ -1,4 +0,0 @@ -package graphvent -import ( -) - diff --git a/gql_test.go b/gql_test.go index 0c579aa..4b10e03 100644 --- a/gql_test.go +++ b/gql_test.go @@ -19,7 +19,7 @@ import ( ) func TestGQLServer(t *testing.T) { - ctx := logTestContext(t, []string{"test"}) + ctx := logTestContext(t, []string{"test", "gql_subscribe"}) TestNodeType := NewNodeType("TEST") err := ctx.RegisterNodeType(TestNodeType, []ExtType{LockableExtType}) diff --git a/gql_types.go b/gql_types.go deleted file mode 100644 index 38ae233..0000000 --- a/gql_types.go +++ /dev/null @@ -1,37 +0,0 @@ -package graphvent - -import ( - "github.com/graphql-go/graphql" -) - -func AddNodeFields(object *graphql.Object) { - object.AddFieldConfig("ID", &graphql.Field{ - Type: graphql.String, - Resolve: ResolveNodeID, - }) - - object.AddFieldConfig("TypeHash", &graphql.Field{ - Type: graphql.String, - Resolve: ResolveNodeTypeHash, - }) -} - -func NewGQLNodeType(gql_name string, node_type NodeType, interfaces []*graphql.Interface, init func(*Type)) *Type { - var gql Type - gql.Type = graphql.NewObject(graphql.ObjectConfig{ - Name: gql_name, - Interfaces: interfaces, - IsTypeOf: func(p graphql.IsTypeOfParams) bool { - node, ok := p.Value.(NodeResult) - if ok == false { - return false - } - return node.Result.NodeType == node_type - }, - Fields: graphql.Fields{}, - }) - gql.List = graphql.NewList(gql.Type) - - init(&gql) - return &gql -} diff --git a/graphql b/graphql deleted file mode 160000 index dd82b0a..0000000 --- a/graphql +++ /dev/null @@ -1 +0,0 @@ -Subproject commit dd82b0abca1e9a52fba07e8935da2164e2c3f565