Simplified gql resolution a bit, need to work on subscriptions

gql_cataclysm
noah metz 2023-09-13 16:27:55 -06:00
parent eb30b477d5
commit ecaf35f05d
5 changed files with 97 additions and 81 deletions

111
gql.go

@ -543,7 +543,7 @@ func BuildSchema(ctx *GQLExtContext) (graphql.Schema, error) {
return graphql.NewSchema(schemaConfig) return graphql.NewSchema(schemaConfig)
} }
func (ctx *GQLExtContext) RegisterField(gql_type graphql.Type, gql_name string, ext_type ExtType, acl_name string, resolve_fn func(graphql.ResolveParams, SerializedValue)(interface{}, error)) error { func (ctx *GQLExtContext) RegisterField(gql_type graphql.Type, gql_name string, ext_type ExtType, gv_tag string, resolve_fn func(graphql.ResolveParams, *ResolveContext, reflect.Value)(interface{}, error)) error {
if ctx == nil { if ctx == nil {
return fmt.Errorf("ctx is nil") return fmt.Errorf("ctx is nil")
} }
@ -557,27 +557,45 @@ func (ctx *GQLExtContext) RegisterField(gql_type graphql.Type, gql_name string,
return fmt.Errorf("%s is already a field in the context, cannot add again", gql_name) return fmt.Errorf("%s is already a field in the context, cannot add again", gql_name)
} }
// Resolver has p.Source.(NodeResult) = read result of current node
resolver := func(p graphql.ResolveParams)(interface{}, error) { resolver := func(p graphql.ResolveParams)(interface{}, error) {
return ResolveNodeResult(p, func(p graphql.ResolveParams, result NodeResult) (interface{}, error) { ctx, err := PrepResolve(p)
ext, exists := result.Result.Extensions[ext_type] if err != nil {
if exists == false { return nil, err
}
node, ok := p.Source.(NodeResult)
if ok == false {
return nil, fmt.Errorf("p.Value is not NodeResult")
}
ext, ext_exists := node.Result.Extensions[ext_type]
if ext_exists == false {
return nil, fmt.Errorf("%+v is not in the extensions of the result", ext_type) return nil, fmt.Errorf("%+v is not in the extensions of the result", ext_type)
} }
val_ser, exists := ext[acl_name] val_ser, field_exists := ext[gv_tag]
if exists == false { if field_exists == false {
return nil, fmt.Errorf("%s is not in the fields of %+v in the result", acl_name, ext_type) return nil, fmt.Errorf("%s is not in the fields of %+v in the result", gv_tag, ext_type)
} }
if val_ser.TypeStack[0] == ErrorType { if val_ser.TypeStack[0] == ErrorType {
return nil, fmt.Errorf(string(val_ser.Data)) return nil, fmt.Errorf(string(val_ser.Data))
} }
return resolve_fn(p, val_ser) field_type, field_value, _, err := DeserializeValue(ctx.Context, val_ser)
}) if err != nil {
return nil, err
}
if field_value == nil {
return nil, fmt.Errorf("%s returned a nil value of %+v type", gv_tag, field_type)
}
return resolve_fn(p, ctx, *field_value)
} }
ctx.Fields[gql_name] = Field{ext_type, acl_name, &graphql.Field{ ctx.Fields[gql_name] = Field{ext_type, gv_tag, &graphql.Field{
Type: gql_type, Type: gql_type,
Resolve: resolver, Resolve: resolver,
}} }}
@ -635,13 +653,13 @@ type NodeResult struct {
type ListField struct { type ListField struct {
ACLName string ACLName string
Extension ExtType Extension ExtType
ResolveFn func(graphql.ResolveParams, interface{}) ([]NodeID, error) ResolveFn func(graphql.ResolveParams, *ResolveContext, reflect.Value) ([]NodeID, error)
} }
type SelfField struct { type SelfField struct {
ACLName string ACLName string
Extension ExtType Extension ExtType
ResolveFn func(graphql.ResolveParams, interface{}) (*NodeID, error) ResolveFn func(graphql.ResolveParams, *ResolveContext, reflect.Value) (*NodeID, error)
} }
func (ctx *GQLExtContext) RegisterInterface(name string, default_name string, interfaces []string, fields []string, self_fields map[string]SelfField, list_fields map[string]ListField) error { func (ctx *GQLExtContext) RegisterInterface(name string, default_name string, interfaces []string, fields []string, self_fields map[string]SelfField, list_fields map[string]ListField) error {
@ -680,13 +698,8 @@ func (ctx *GQLExtContext) RegisterInterface(name string, default_name string, in
for field_name, field := range(self_fields) { for field_name, field := range(self_fields) {
self_field := field self_field := field
err := ctx.RegisterField(ctx_interface.Interface, field_name, self_field.Extension, self_field.ACLName, err := ctx.RegisterField(ctx_interface.Interface, field_name, self_field.Extension, self_field.ACLName,
func(p graphql.ResolveParams, val SerializedValue)(interface{}, error) { func(p graphql.ResolveParams, ctx *ResolveContext, value reflect.Value)(interface{}, error) {
ctx, err := PrepResolve(p) id, err := self_field.ResolveFn(p, ctx, value)
if err != nil {
return nil, err
}
id, err := self_field.ResolveFn(p, val)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -713,14 +726,9 @@ func (ctx *GQLExtContext) RegisterInterface(name string, default_name string, in
for field_name, field := range(list_fields) { for field_name, field := range(list_fields) {
list_field := field list_field := field
resolve_fn := func(p graphql.ResolveParams, val SerializedValue)(interface{}, error) { resolve_fn := func(p graphql.ResolveParams, ctx *ResolveContext, value reflect.Value)(interface{}, error) {
ctx, err := PrepResolve(p)
if err != nil {
return nil, err
}
var zero NodeID var zero NodeID
ids, err := list_field.ResolveFn(p, val) ids, err := list_field.ResolveFn(p, ctx, value)
if err != nil { if err != nil {
return zero, err return zero, err
} }
@ -829,19 +837,18 @@ func NewGQLExtContext() *GQLExtContext {
} }
err = context.RegisterField(context.Interfaces["Node"].List, "Members", GroupExtType, "members", err = context.RegisterField(context.Interfaces["Node"].List, "Members", GroupExtType, "members",
func(p graphql.ResolveParams, val SerializedValue)(interface{}, error) { func(p graphql.ResolveParams, ctx *ResolveContext, value reflect.Value)(interface{}, error) {
ctx, err := PrepResolve(p) node_map, ok := value.Interface().(map[NodeID]string)
if err != nil { if ok == false {
return nil, err return nil, fmt.Errorf("value is %+v, not map[NodeID]string", value.Type())
} }
/*node_list := make([]NodeID, len(val)) node_list := []NodeID{}
i := 0 i := 0
for id, _ := range(val) { for id, _ := range(node_map) {
node_list[i] = id node_list = append(node_list, id)
i += 1 i += 1
} }
*/
node_list := []NodeID{}
nodes, err := ResolveNodes(ctx, p, node_list) nodes, err := ResolveNodes(ctx, p, node_list)
if err != nil { if err != nil {
return nil, err return nil, err
@ -862,10 +869,10 @@ func NewGQLExtContext() *GQLExtContext {
"Owner": SelfField{ "Owner": SelfField{
"owner", "owner",
LockableExtType, LockableExtType,
func(p graphql.ResolveParams, val interface{}) (*NodeID, error) { func(p graphql.ResolveParams, ctx *ResolveContext, value reflect.Value) (*NodeID, error) {
id, ok := val.(*NodeID) id, ok := value.Interface().(*NodeID)
if ok == false { if ok == false {
return nil, fmt.Errorf("can't parse %+v as *NodeID", val) return nil, fmt.Errorf("can't parse %+v as *NodeID", value.Type())
} }
return id, nil return id, nil
@ -875,14 +882,14 @@ func NewGQLExtContext() *GQLExtContext {
"Requirements": ListField{ "Requirements": ListField{
"requirements", "requirements",
LockableExtType, LockableExtType,
func(p graphql.ResolveParams, val interface{}) ([]NodeID, error) { func(p graphql.ResolveParams, ctx *ResolveContext, value reflect.Value) ([]NodeID, error) {
id_strs, ok := val.(map[NodeID]ReqState) id_strs, ok := value.Interface().(map[NodeID]ReqState)
if ok == false { if ok == false {
return nil, fmt.Errorf("can't parse requirements %+v as map[NodeID]ReqState, %s", val, reflect.TypeOf(val)) return nil, fmt.Errorf("can't parse requirements %+v as map[NodeID]ReqState", value.Type())
} }
ids := []NodeID{} ids := []NodeID{}
for id, _ := range(id_strs) { for id := range(id_strs) {
ids = append(ids, id) ids = append(ids, id)
} }
return ids, nil return ids, nil
@ -894,8 +901,8 @@ func NewGQLExtContext() *GQLExtContext {
panic(err) panic(err)
} }
err = context.RegisterField(graphql.String, "Listen", GQLExtType, "listen", func(p graphql.ResolveParams, listen SerializedValue) (interface{}, error) { err = context.RegisterField(graphql.String, "Listen", GQLExtType, "listen", func(p graphql.ResolveParams, ctx *ResolveContext, value reflect.Value) (interface{}, error) {
return listen, nil return value.String(), nil
}) })
if err != nil { if err != nil {
panic(err) panic(err)
@ -986,17 +993,17 @@ func NewGQLExtContext() *GQLExtContext {
} }
type GQLExt struct { type GQLExt struct {
tcp_listener net.Listener `json:"-"` tcp_listener net.Listener
http_server *http.Server `json:"-"` http_server *http.Server
http_done sync.WaitGroup `json:"-"` http_done sync.WaitGroup
// map of read request IDs to response channels // map of read request IDs to response channels
resolver_response map[uuid.UUID]chan Signal `json:"-"` resolver_response map[uuid.UUID]chan Signal
resolver_response_lock sync.RWMutex `json:"-"` resolver_response_lock sync.RWMutex
TLSKey []byte `json:"tls_key"` TLSKey []byte `gv:"tls_key"`
TLSCert []byte `json:"tls_cert"` TLSCert []byte `gv:"tls_cert"`
Listen string `json:"listen"` Listen string `gv:"listen"`
} }
func (ext *GQLExt) FindResponseChannel(req_id uuid.UUID) chan Signal { func (ext *GQLExt) FindResponseChannel(req_id uuid.UUID) chan Signal {

@ -64,23 +64,20 @@ func ExtractID(p graphql.ResolveParams, name string) (NodeID, error) {
return id, nil return id, nil
} }
func ResolveNodeResult(p graphql.ResolveParams, resolve_fn func(graphql.ResolveParams, NodeResult)(interface{}, error)) (interface{}, error) { func ResolveNodeID(p graphql.ResolveParams) (interface{}, error) {
node, ok := p.Source.(NodeResult) node, ok := p.Source.(NodeResult)
if ok == false { if ok == false {
return nil, fmt.Errorf("p.Value is not NodeResult") return nil, fmt.Errorf("Can't get NodeID from %+v", reflect.TypeOf(p.Source))
} }
return resolve_fn(p, node)
}
func ResolveNodeID(p graphql.ResolveParams) (interface{}, error) {
return ResolveNodeResult(p, func(p graphql.ResolveParams, node NodeResult) (interface{}, error) {
return node.ID, nil return node.ID, nil
})
} }
func ResolveNodeTypeHash(p graphql.ResolveParams) (interface{}, error) { func ResolveNodeTypeHash(p graphql.ResolveParams) (interface{}, error) {
return ResolveNodeResult(p, func(p graphql.ResolveParams, node NodeResult) (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 return uint64(node.Result.NodeType), nil
})
} }

@ -5,7 +5,7 @@ import (
) )
type GroupExt struct { type GroupExt struct {
Members map[NodeID]string `gv:"0"` Members map[NodeID]string `gv:"members"`
} }
func (ext *GroupExt) Type() ExtType { func (ext *GroupExt) Type() ExtType {

@ -16,9 +16,9 @@ const (
type LockableExt struct{ type LockableExt struct{
State ReqState `gv:"state"` State ReqState `gv:"state"`
ReqID *uuid.UUID `gv:"req_id"` ReqID *uuid.UUID `gv:"req_id"`
Owner *NodeID Owner *NodeID `gv:"owner"`
PendingOwner *NodeID PendingOwner *NodeID `gv:"pending_owner"`
Requirements map[NodeID]ReqState Requirements map[NodeID]ReqState `gv:"requirements"`
} }
func (ext *LockableExt) Type() ExtType { func (ext *LockableExt) Type() ExtType {

@ -635,17 +635,29 @@ func SerializeValue(ctx *Context, t reflect.Type, value *reflect.Value) (Seriali
return serialized_value, err return serialized_value, err
} }
func SerializeField(ctx *Context, ext Extension, field_name string) (SerializedValue, error) { func ExtField(ctx *Context, ext Extension, field_name string) (reflect.Value, error) {
if ext == nil { if ext == nil {
return SerializedValue{}, fmt.Errorf("Cannot get fields on nil Extension") return reflect.Value{}, fmt.Errorf("Cannot get fields on nil Extension")
} }
ext_value := reflect.ValueOf(ext).Elem() ext_value := reflect.ValueOf(ext).Elem()
field := ext_value.FieldByName(field_name) for _, field := range(reflect.VisibleFields(ext_value.Type())) {
if field.IsValid() == false { gv_tag, tagged := field.Tag.Lookup("gv")
return SerializedValue{}, fmt.Errorf("%s is not a field in %+v", field_name, ext) if tagged == true && gv_tag == field_name {
} else { return ext_value.FieldByIndex(field.Index), nil
return SerializeValue(ctx, field.Type(), &field) }
}
return reflect.Value{}, fmt.Errorf("%s is not a field in %+v", field_name, reflect.TypeOf(ext))
}
func SerializeField(ctx *Context, ext Extension, field_name string) (SerializedValue, error) {
field_value, err := ExtField(ctx, ext, field_name)
if err != nil {
return SerializedValue{}, err
} }
return SerializeValue(ctx, field_value.Type(), &field_value)
} }
func (value SerializedValue) MarshalBinary() ([]byte, error) { func (value SerializedValue) MarshalBinary() ([]byte, error) {