Skip to content

Commit

Permalink
Adding mutation operation
Browse files Browse the repository at this point in the history
  • Loading branch information
kellrott committed Jan 5, 2025
1 parent d6626b2 commit 135f1ac
Show file tree
Hide file tree
Showing 4 changed files with 179 additions and 52 deletions.
4 changes: 3 additions & 1 deletion cmd/grip-graphql-proxy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ var gripServer = "localhost:8202"
var serverPort = "8080"
var configFile = "config.js"
var graph = "test-db"
var writable = false

func main() {

Expand All @@ -23,10 +24,11 @@ func main() {
pflag.StringVar(&serverPort, "port", serverPort, "Proxy port")
pflag.StringVar(&configFile, "config", configFile, "Config")
pflag.StringVar(&graph, "graph", graph, "Graph")
pflag.BoolVar(&writable, "write", writable, "Allow Write")

pflag.Parse()

client, err := gripql.Connect(rpc.ConfigWithDefaults(gripServer), false)
client, err := gripql.Connect(rpc.ConfigWithDefaults(gripServer), writable)
if err != nil {
log.Errorf("Error: %s", err)
}
Expand Down
32 changes: 32 additions & 0 deletions config/read_write.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
endpoint.add({
name: "Prompts",
//cached: true,
schema: [{
id: "String",
prompt: "String"
}],
args: {
offset: "Int",
limit: "Int",
},
defaults: {
offset: 0,
limit: 100
},
handler: (G, args) => {
return G.V().hasLabel('Prompt').skip(args.offset).limit(args.limit).render({"id":"$._gid", "prompt":"$.prompt"}).toList()
}
})

endpoint.addMutation({
name: "AddPrompt",
schema: {
id: "String"
},
args: {
prompt: "String"
},
handler: (G, args) => {
return { "id" : G.addVertex(null, "Prompt", {"prompt" : args.prompt} ) }
}
})
147 changes: 96 additions & 51 deletions gripgraphql/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ var sandBox = `
</script>`

type QueryField struct {
name string
field *graphql.Field
handler func(goja.FunctionCall) goja.Value
}
Expand All @@ -50,10 +51,11 @@ type GraphQLJS struct {
}

type Endpoint struct {
client gripql.Client
vm *goja.Runtime
cw *JSClientWrapper
queryNodes map[string]QueryField
client gripql.Client
vm *goja.Runtime
cw *JSClientWrapper
queryNodes map[string]QueryField
mutationNodes map[string]QueryField
}

func parseField(name string, x any) (*graphql.Field, error) {
Expand Down Expand Up @@ -108,25 +110,23 @@ func parseObject(name string, x map[string]any) (*graphql.Object, error) {
}), nil
}

func (e *Endpoint) Add(x map[string]any) {
func (e *Endpoint) parseJSHandler(x map[string]any) (QueryField, error) {
name := ""
if nameA, ok := x["name"]; ok {
if nameStr, ok := nameA.(string); ok {
name = nameStr
}
}
if name == "" {
log.Errorf("Name not defined")
return
return QueryField{}, fmt.Errorf("name not defined")
}

var jHandler func(goja.FunctionCall) goja.Value
if handlerA, ok := x["handler"]; ok {
if handler, ok := handlerA.(func(goja.FunctionCall) goja.Value); ok {
jHandler = handler
} else {
log.Errorf("Unknown handler type: %#T\n", handlerA)
return
return QueryField{}, fmt.Errorf("unknown handler type: %#T", handlerA)
}
}

Expand All @@ -148,7 +148,7 @@ func (e *Endpoint) Add(x map[string]any) {
}
}

log.Infof("Loading query %s", name)
log.Infof("Loading handler %s", name)
if schemaA, ok := x["schema"]; ok {
objField, err := parseField(name, schemaA)
if err == nil {
Expand Down Expand Up @@ -198,16 +198,38 @@ func (e *Endpoint) Add(x map[string]any) {
}
objField.Args = args
}
e.queryNodes[name] = QueryField{
objField, jHandler,
}
log.Infof("Added GraphQL query node : %s", name)
return QueryField{
name: name,
field: objField,
handler: jHandler,
}, nil
} else {
log.Errorf("Parse Error: %s", err)
return QueryField{}, fmt.Errorf("parse error: %s", err)
}
} else {
log.Errorf("Schema not found for %s", name)
return QueryField{}, fmt.Errorf("schema not found for %s", name)
}
}

func (e *Endpoint) Add(x map[string]any) {
o, err := e.parseJSHandler(x)
if err == nil {
e.queryNodes[o.name] = o
log.Infof("Added GraphQL query node : %s", o.name)
} else {
log.Errorf("Query 'add' error: %s", err)
}
}

func (e *Endpoint) AddMutation(x map[string]any) {
o, err := e.parseJSHandler(x)
if err == nil {
e.mutationNodes[o.name] = o
log.Infof("Added GraphQL mutation node : %s", o.name)
} else {
log.Errorf("Query 'addMutation' error: %s", err)
}

}

func jsExport(val goja.Value) any {
Expand All @@ -216,13 +238,23 @@ func jsExport(val goja.Value) any {
out := []any{}
for _, i := range oList {
if ov, ok := i.(goja.Value); ok {
out = append(out, ov.Export())
out = append(out, jsExport(ov))
} else {
out = append(out, i)
}
}
return out
}
if oMap, ok := o.(map[string]any); ok {
out := map[string]any{}
for k, v := range oMap {
if ov, ok := v.(goja.Value); ok {
out[k] = jsExport(ov)
} else {
out[k] = v
}
}
}
return o
}

Expand All @@ -239,13 +271,59 @@ func (e *Endpoint) Build() (*graphql.Schema, error) {
Query: queryObj,
}

if len(e.mutationNodes) > 0 {
mf := graphql.Fields{}
for k, v := range e.mutationNodes {
//log.Infof("fields: %+v", v.field)
mf[k] = v.field
}
mutationObj := graphql.NewObject(graphql.ObjectConfig{Name: "Mutation", Fields: mf})
schemaConfig.Mutation = mutationObj
}

gqlSchema, err := graphql.NewSchema(schemaConfig)
if err != nil {
return nil, fmt.Errorf("graphql.NewSchema error: %v", err)
}
return &gqlSchema, nil
}

func NewGraphQLJS(graph string, auth bool, client gripql.Client, code string) *GraphQLJS {
vm := goja.New()
vm.SetFieldNameMapper(JSRenamer{})
jsClient, err := GetJSClient(graph, client, vm, auth)
if err != nil {
log.Infof("js error: %s\n", err)
}

e := &Endpoint{queryNodes: map[string]QueryField{}, mutationNodes: map[string]QueryField{}, client: client, vm: vm, cw: jsClient}
vm.Set("endpoint", map[string]any{
"add": e.Add,
"addMutation": e.AddMutation,
"String": "String",
"Int": "Int",
"Float": "Float",
"Boolean": "Boolean",
})

vm.Set("print", fmt.Printf) //Adding print statement for debugging. This may need to be removed/updated

_, err = vm.RunString(code)
if err != nil {
log.Errorf("Error running data config %s", err)
}

schema, err := e.Build()
if err != nil {
log.Errorf("Error building Handler: %s", err)
}
var hnd *handler.Handler = handler.New(&handler.Config{
Schema: schema,
})
gh := &GraphQLJS{client: client, gjHandler: hnd, cw: jsClient, auth: auth}
return gh
}

/*
var Pool sync.Pool
var poolInited bool
Expand All @@ -272,43 +350,10 @@ func NewHTTPHandler(client gripql.Client, config map[string]string) (http.Handle
if err != nil {
return nil, err
}
var hnd *handler.Handler

log.Infof("Creating new pool ==============================================================")
Pool := sync.Pool{
New: func() any {
vm := goja.New()
vm.SetFieldNameMapper(JSRenamer{})
jsClient, err := GetJSClient(graph, client, vm, auth)
if err != nil {
log.Infof("js error: %s\n", err)
}

e := &Endpoint{queryNodes: map[string]QueryField{}, client: client, vm: vm, cw: jsClient}
vm.Set("endpoint", map[string]any{
"add": e.Add,
"String": "String",
"Int": "Int",
"Float": "Float",
"Boolean": "Boolean",
})

vm.Set("print", fmt.Printf) //Adding print statement for debugging. This may need to be removed/updated

_, err = vm.RunString(string(data))
if err != nil {
log.Errorf("Error running data config %s", err)
}

schema, err := e.Build()
if err != nil {
log.Errorf("Error building Handler: %s", err)
}
hnd = handler.New(&handler.Config{
Schema: schema,
})
gh := &GraphQLJS{client: client, gjHandler: hnd, cw: jsClient, auth: auth}
return gh
return NewGraphQLJS(graph, auth, client, string(data))
},
}
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
Expand Down
48 changes: 48 additions & 0 deletions gripgraphql/js_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/bmeg/grip/gripql"
"github.com/bmeg/grip/gripql/inspect"
"github.com/google/uuid"

//"github.com/bmeg/grip-graphql/middleware"
//"github.com/bmeg/grip/jobstorage"
Expand Down Expand Up @@ -82,6 +83,9 @@ func (cw *JSClientWrapper) ToList(args goja.Value) goja.Value {

query := gripql.GraphQuery{}
err = protojson.Unmarshal(queryJSON, &query)
if err != nil {
log.Errorf("unmarshal error: %s", err)
}
query.Graph = cw.graph

var ctx context.Context
Expand Down Expand Up @@ -176,6 +180,50 @@ func (cw *JSClientWrapper) V(args goja.Value) goja.Value {
return out
}

func (cw *JSClientWrapper) AddVertex(args ...goja.Value) goja.Value {
log.Infof("addVertex %s", args)

gid := ""
if args[0] != nil {
g := args[0].Export()
if gstr, ok := g.(string); ok {
gid = gstr
}
}
if gid == "" {
gid = uuid.New().String()
}

log.Info("getting label")
label := ""
l := args[1].Export()
if lstr, ok := l.(string); ok {
label = lstr
}

vData := map[string]any{}
data := jsExport(args[2])
if data != nil {
if jData, ok := data.(map[string]any); ok {
vData = jData
}
}

vertex := &gripql.Vertex{
Gid: gid,
Label: label,
}
vertex.SetDataMap(vData)

log.Infof("adding vertex: %s", vertex)
err := cw.client.AddVertex(cw.graph, vertex)
if err != nil {
log.Errorf("error adding vertex: %s", err)
}
log.Infof("Added vertex")
return cw.vm.ToValue(gid)
}

func (cw *JSClientWrapper) toValue() goja.Value {
return cw.vm.ToValue(cw)
}
Expand Down

0 comments on commit 135f1ac

Please sign in to comment.