From 394e9da4a9745ea72e4f2b875a62e7f8bc17a3e2 Mon Sep 17 00:00:00 2001 From: Kyle Ellrott Date: Fri, 2 Feb 2024 15:34:56 -0800 Subject: [PATCH 01/23] Working on Pebble BulkLoad stutter --- benchmark/kv-query-profile/main.go | 5 ++--- cmd/server/main.go | 2 ++ config/config.go | 6 ++++++ go.mod | 4 ++-- go.sum | 4 ++-- grids/new.go | 24 +++++++++++++++++------- kvi/pebbledb/pebble_store.go | 24 ++++++++++++++++++++---- 7 files changed, 51 insertions(+), 18 deletions(-) diff --git a/benchmark/kv-query-profile/main.go b/benchmark/kv-query-profile/main.go index 234b3577..c982e861 100644 --- a/benchmark/kv-query-profile/main.go +++ b/benchmark/kv-query-profile/main.go @@ -8,7 +8,6 @@ import ( "log" "os" "runtime/pprof" - "strings" "time" "github.com/bmeg/grip/engine/pipeline" @@ -17,7 +16,7 @@ import ( "github.com/bmeg/grip/kvgraph" "github.com/bmeg/grip/kvi" "github.com/dop251/goja" - "github.com/golang/protobuf/jsonpb" + "google.golang.org/protobuf/encoding/protojson" gripqljs "github.com/bmeg/grip/gripql/javascript" @@ -76,7 +75,7 @@ func main() { } query := gripql.GraphQuery{} - err = jsonpb.Unmarshal(strings.NewReader(string(queryJSON)), &query) + err = protojson.Unmarshal(queryJSON, &query) if err != nil { log.Printf("%s", err) return diff --git a/cmd/server/main.go b/cmd/server/main.go index 6707f0b3..8f0c7ddf 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -81,6 +81,8 @@ var Cmd = &cobra.Command{ dconf.AddPebbleDefault() } else if driver == "mongo" { dconf.AddMongoDefault() + } else if driver == "grids" { + dconf.AddGridsDefault() } } if pluginDir != "" { diff --git a/config/config.go b/config/config.go index d6c0da97..08f68eca 100644 --- a/config/config.go +++ b/config/config.go @@ -101,6 +101,12 @@ func (conf *Config) AddMongoDefault() { conf.Default = "mongo" } +func (conf *Config) AddGridsDefault() { + n := "grip-grids.db" + conf.Drivers["grids"] = DriverConfig{Grids: &n} + conf.Default = "grids" +} + // TestifyConfig randomizes ports and database paths/names func TestifyConfig(c *Config) { rand := strings.ToLower(util.RandomString(6)) diff --git a/go.mod b/go.mod index 0b5f1556..d2981c8b 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/Shopify/sarama v1.22.1 github.com/Workiva/go-datastructures v1.0.52 - github.com/akrylysov/pogreb v0.8.1 + github.com/akrylysov/pogreb v0.10.2 github.com/akuity/grpc-gateway-client v0.0.0-20230321170839-38ca1b4b439c github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 github.com/bmeg/jsonpath v0.0.0-20210207014051-cca5355553ad @@ -17,7 +17,6 @@ require ( github.com/dop251/goja v0.0.0-20190429205339-8d6ee3d16611 github.com/felixge/httpsnoop v1.0.1 github.com/go-sql-driver/mysql v1.5.0 - github.com/golang/protobuf v1.5.2 github.com/graphql-go/graphql v0.8.0 github.com/graphql-go/handler v0.2.3 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 @@ -82,6 +81,7 @@ require ( github.com/go-sourcemap/sourcemap v2.1.2+incompatible // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect + github.com/golang/protobuf v1.5.2 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/uuid v1.3.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect diff --git a/go.sum b/go.sum index ace137e9..66993410 100644 --- a/go.sum +++ b/go.sum @@ -63,8 +63,8 @@ github.com/Workiva/go-datastructures v1.0.52 h1:PLSK6pwn8mYdaoaCZEMsXBpBotr4HHn9 github.com/Workiva/go-datastructures v1.0.52/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/akrylysov/pogreb v0.8.1 h1:PvNdy6Xnw6WQYDo//ruRNN6uZIxLnSI2tpm0/xr7HFE= -github.com/akrylysov/pogreb v0.8.1/go.mod h1:pNs6QmpQ1UlTJKDezuRWmaqkgUE2TuU0YTWyqJZ7+lI= +github.com/akrylysov/pogreb v0.10.2 h1:e6PxmeyEhWyi2AKOBIJzAEi4HkiC+lKyCocRGlnDi78= +github.com/akrylysov/pogreb v0.10.2/go.mod h1:pNs6QmpQ1UlTJKDezuRWmaqkgUE2TuU0YTWyqJZ7+lI= github.com/akuity/grpc-gateway-client v0.0.0-20230321170839-38ca1b4b439c h1:+TGlC7RoqCnRm7F6jvyxsnIaMM8VfsbDsDWVVifgxS4= github.com/akuity/grpc-gateway-client v0.0.0-20230321170839-38ca1b4b439c/go.mod h1:2LXcIC4bAFvsZitqz5qtaTfYS5vCbz4BTA/BgkJLM0g= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= diff --git a/grids/new.go b/grids/new.go index 50e06906..2d97a7b9 100644 --- a/grids/new.go +++ b/grids/new.go @@ -5,6 +5,8 @@ import ( "os" "path/filepath" + "github.com/cockroachdb/pebble" + "github.com/akrylysov/pogreb" "github.com/bmeg/grip/gripql" "github.com/bmeg/grip/kvi" @@ -19,10 +21,11 @@ type Graph struct { graphID string graphKey uint64 - keyMap *KeyMap - keykv pogreb.DB - graphkv kvi.KVInterface - indexkv kvi.KVInterface + keyMap *KeyMap + keykv pogreb.DB + + graphkv kvi.KVInterface // *pebble.DB + indexkv kvi.KVInterface // *pebble.DB idx *kvindex.KVIndex ts *timestamp.Timestamp } @@ -65,16 +68,23 @@ func newGraph(baseDir, name string) (*Graph, error) { if err != nil { return nil, err } - graphkv, err := pebbledb.NewKVInterface(graphkvPath, kvi.Options{}) + graphkv, err := pebble.Open(graphkvPath, &pebble.Options{}) if err != nil { return nil, err } - indexkv, err := pebbledb.NewKVInterface(indexkvPath, kvi.Options{}) + indexkv, err := pebble.Open(indexkvPath, &pebble.Options{}) if err != nil { return nil, err } ts := timestamp.NewTimestamp() - o := &Graph{keyMap: NewKeyMap(keykv), graphkv: graphkv, indexkv: indexkv, ts: &ts, idx: kvindex.NewIndex(indexkv)} + + o := &Graph{ + keyMap: NewKeyMap(keykv), + graphkv: pebbledb.WrapPebble(graphkv), + indexkv: pebbledb.WrapPebble(indexkv), + ts: &ts, + idx: kvindex.NewIndex(pebbledb.WrapPebble(indexkv)), + } return o, nil } diff --git a/kvi/pebbledb/pebble_store.go b/kvi/pebbledb/pebble_store.go index 09e6a1e3..78b61986 100644 --- a/kvi/pebbledb/pebble_store.go +++ b/kvi/pebbledb/pebble_store.go @@ -21,7 +21,9 @@ var loaded = kvi.AddKVDriver("pebble", NewKVInterface) // PebbleKV is an implementation of the KVStore for badger type PebbleKV struct { - db *pebble.DB + db *pebble.DB + insertCount uint32 + compactLimit uint32 } // NewKVInterface creates new BoltDB backed KVInterface at `path` @@ -33,6 +35,14 @@ func NewKVInterface(path string, kopts kvi.Options) (kvi.KVInterface, error) { return &PebbleKV{db: db}, nil } +func WrapPebble(db *pebble.DB) kvi.KVInterface { + return &PebbleKV{ + db: db, + insertCount: 0, + compactLimit: 10000, + } +} + // Close closes the badger connection func (pdb *PebbleKV) Close() error { log.Info("Closing PebbleDB") @@ -224,6 +234,7 @@ type pebbleBulkWrite struct { batch *pebble.Batch highest, lowest []byte curSize int + totalInserts uint32 } const ( @@ -232,6 +243,7 @@ const ( func (pbw *pebbleBulkWrite) Set(id []byte, val []byte) error { pbw.curSize += len(id) + len(val) + pbw.totalInserts++ if pbw.highest == nil || bytes.Compare(id, pbw.highest) > 0 { pbw.highest = copyBytes(id) } @@ -250,12 +262,16 @@ func (pbw *pebbleBulkWrite) Set(id []byte, val []byte) error { // BulkWrite is a replication of the regular update, no special code for bulk writes func (pdb *PebbleKV) BulkWrite(u func(tx kvi.KVBulkWrite) error) error { batch := pdb.db.NewBatch() - ptx := &pebbleBulkWrite{pdb.db, batch, nil, nil, 0} + ptx := &pebbleBulkWrite{pdb.db, batch, nil, nil, 0, 0} err := u(ptx) batch.Commit(nil) batch.Close() - if ptx.lowest != nil && ptx.highest != nil { - pdb.db.Compact(ptx.lowest, ptx.highest, true) + + pdb.insertCount += ptx.totalInserts + if pdb.insertCount > pdb.compactLimit { + //pdb.db.Compact(ptx.lowest, ptx.highest, true) + pdb.db.Compact([]byte{0x00}, []byte{0xFF}, true) + pdb.insertCount = 0 } return err } From b2a5c07f6a1440117294db4bb5da8a43b87f5412 Mon Sep 17 00:00:00 2001 From: Kyle Ellrott Date: Wed, 7 Feb 2024 07:40:01 -0800 Subject: [PATCH 02/23] Starting to abstract structures in GDBI to better support different data loading/processing strategies --- elastic/graph.go | 13 +- engine/core/compile.go | 286 +--------------------------- engine/core/optimize.go | 6 +- engine/core/processors.go | 68 ++++--- engine/core/processors_extra.go | 20 +- engine/core/statement_compiler.go | 250 ++++++++++++++++++++++++ engine/inspect/haslabel.go | 59 ------ engine/inspect/inspect.go | 172 ----------------- engine/logic/jump.go | 5 +- engine/logic/match.go | 3 +- engine/pipeline/pipes.go | 15 +- engine/queue/queue.go | 74 ------- gdbi/interface.go | 46 +++-- {jsonpath => gdbi}/jsonpath.go | 107 +++-------- {jsonpath => gdbi}/jsonpath_test.go | 90 ++++----- gdbi/pipeline.go | 39 ++++ gdbi/queue.go | 72 +++++++ {engine/pipeline => gdbi}/state.go | 18 +- gdbi/statement_processor.go | 237 +++++++++++++++++++++++ gdbi/traveler.go | 38 ++-- grids/new.go | 101 +--------- grids/{ => old}/compiler.go | 5 +- grids/old/config.go | 5 + grids/{ => old}/graph.go | 0 grids/old/graph_lite.go | 1 + grids/{ => old}/graphdb.go | 0 grids/{ => old}/index.go | 14 +- grids/{ => old}/keymap.go | 0 grids/{ => old}/keys.go | 0 grids/old/new.go | 105 ++++++++++ grids/{ => old}/raw_graph.go | 0 grids/{ => old}/raw_processors.go | 0 grids/{ => old}/schema.go | 0 grids/old/statement_compiler.go | 250 ++++++++++++++++++++++++ grids/{ => old}/traveler.go | 4 +- gripper/optimize.go | 2 +- jobstorage/serializer_test.go | 2 +- kvgraph/index.go | 14 +- kvgraph/schema.go | 6 +- mongo/compile.go | 30 +-- mongo/compile_test.go | 8 +- mongo/has_evaluator.go | 4 +- mongo/index.go | 6 +- mongo/processor.go | 2 +- test/inspect_test.go | 2 +- travelerpath/jsonpath.go | 55 ++++++ 46 files changed, 1275 insertions(+), 959 deletions(-) create mode 100644 engine/core/statement_compiler.go delete mode 100644 engine/inspect/haslabel.go delete mode 100644 engine/inspect/inspect.go delete mode 100644 engine/queue/queue.go rename {jsonpath => gdbi}/jsonpath.go (70%) rename {jsonpath => gdbi}/jsonpath_test.go (71%) create mode 100644 gdbi/queue.go rename {engine/pipeline => gdbi}/state.go (67%) create mode 100644 gdbi/statement_processor.go rename grids/{ => old}/compiler.go (96%) create mode 100644 grids/old/config.go rename grids/{ => old}/graph.go (100%) create mode 100644 grids/old/graph_lite.go rename grids/{ => old}/graphdb.go (100%) rename grids/{ => old}/index.go (89%) rename grids/{ => old}/keymap.go (100%) rename grids/{ => old}/keys.go (100%) create mode 100644 grids/old/new.go rename grids/{ => old}/raw_graph.go (100%) rename grids/{ => old}/raw_processors.go (100%) rename grids/{ => old}/schema.go (100%) create mode 100644 grids/old/statement_compiler.go rename grids/{ => old}/traveler.go (97%) create mode 100644 travelerpath/jsonpath.go diff --git a/elastic/graph.go b/elastic/graph.go index d0832684..bbd9e1bb 100644 --- a/elastic/graph.go +++ b/elastic/graph.go @@ -373,7 +373,6 @@ func (es *Graph) GetVertexChannel(ctx context.Context, req chan gdbi.ElementLook r := batchMap[vertex.Gid] for _, ri := range r { ri.Vertex = gdbi.NewElementFromVertex(vertex) - ri.Vertex.Loaded = load o <- ri } } @@ -484,8 +483,8 @@ func (es *Graph) GetOutChannel(ctx context.Context, req chan gdbi.ElementLookup, signals = append(signals, batch[i]) } else { if batch[i].Vertex != nil { - idBatch = append(idBatch, batch[i].Vertex.ID) - batchMap[batch[i].Vertex.ID] = append(batchMap[batch[i].Vertex.ID], batch[i]) + idBatch = append(idBatch, batch[i].Vertex.Get().ID) + batchMap[batch[i].Vertex.Get().ID] = append(batchMap[batch[i].Vertex.Get().ID], batch[i]) } else if emitNull { o <- batch[i] } @@ -509,7 +508,6 @@ func (es *Graph) GetOutChannel(ctx context.Context, req chan gdbi.ElementLookup, r := batchMap[vertex.Gid] for _, ri := range r { ri.Vertex = gdbi.NewElementFromVertex(vertex) - ri.Vertex.Loaded = load o <- ri } } @@ -620,8 +618,8 @@ func (es *Graph) GetInChannel(ctx context.Context, req chan gdbi.ElementLookup, signals = append(signals, batch[i]) } else { if batch[i].Vertex != nil { - idBatch = append(idBatch, batch[i].Vertex.ID) - batchMap[batch[i].Vertex.ID] = append(batchMap[batch[i].Vertex.ID], batch[i]) + idBatch = append(idBatch, batch[i].Vertex.Get().ID) + batchMap[batch[i].Vertex.Get().ID] = append(batchMap[batch[i].Vertex.Get().ID], batch[i]) } else if emitNull { o <- batch[i] } @@ -645,7 +643,6 @@ func (es *Graph) GetInChannel(ctx context.Context, req chan gdbi.ElementLookup, r := batchMap[vertex.Gid] for _, ri := range r { ri.Vertex = gdbi.NewElementFromVertex(vertex) - ri.Vertex.Loaded = load o <- ri } } @@ -720,7 +717,6 @@ func (es *Graph) GetOutEdgeChannel(ctx context.Context, req chan gdbi.ElementLoo batchMapReturnCount[edge.From]++ for _, ri := range r { ri.Edge = gdbi.NewElementFromEdge(edge) - ri.Edge.Loaded = load o <- ri } } @@ -807,7 +803,6 @@ func (es *Graph) GetInEdgeChannel(ctx context.Context, req chan gdbi.ElementLook batchMapReturnCount[edge.To]++ for _, ri := range r { ri.Edge = gdbi.NewElementFromEdge(edge) - ri.Edge.Loaded = load o <- ri } } diff --git a/engine/core/compile.go b/engine/core/compile.go index d83454fc..54bf1204 100644 --- a/engine/core/compile.go +++ b/engine/core/compile.go @@ -3,12 +3,8 @@ package core import ( "fmt" - "github.com/bmeg/grip/engine/logic" - "github.com/bmeg/grip/engine/pipeline" "github.com/bmeg/grip/gdbi" "github.com/bmeg/grip/gripql" - "github.com/bmeg/grip/jsonpath" - "github.com/bmeg/grip/util/protoutil" ) // DefaultPipeline a set of runnable query operations @@ -19,7 +15,7 @@ type DefaultPipeline struct { markTypes map[string]gdbi.DataType } -func NewPipeline(graph gdbi.GraphInterface, procs []gdbi.Processor, ps *pipeline.State) *DefaultPipeline { +func NewPipeline(graph gdbi.GraphInterface, procs []gdbi.Processor, ps *gdbi.State) *DefaultPipeline { return &DefaultPipeline{graph, procs, ps.LastType, ps.MarkTypes} } @@ -70,7 +66,7 @@ func (comp DefaultCompiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.C stmts = o(stmts) } - ps := pipeline.NewPipelineState(stmts) + ps := gdbi.NewPipelineState(stmts) if opts != nil { ps.LastType = opts.PipelineExtension ps.MarkTypes = opts.ExtensionMarkTypes @@ -78,9 +74,11 @@ func (comp DefaultCompiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.C procs := make([]gdbi.Processor, 0, len(stmts)) + sproc := &DefaultStmtCompiler{comp.db} + for i, gs := range stmts { ps.SetCurStatment(i) - p, err := StatementProcessor(gs, comp.db, ps) + p, err := gdbi.StatementProcessor(sproc, gs, comp.db, ps) if err != nil { return &DefaultPipeline{}, err } @@ -90,280 +88,6 @@ func (comp DefaultCompiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.C return &DefaultPipeline{comp.db, procs, ps.LastType, ps.MarkTypes}, nil } -func StatementProcessor(gs *gripql.GraphStatement, db gdbi.GraphInterface, ps *pipeline.State) (gdbi.Processor, error) { - switch stmt := gs.GetStatement().(type) { - - case *gripql.GraphStatement_V: - if ps.LastType != gdbi.NoData { - return nil, fmt.Errorf(`"V" statement is only valid at the beginning of the traversal`) - } - ids := protoutil.AsStringList(stmt.V) - ps.LastType = gdbi.VertexData - return &LookupVerts{db: db, ids: ids, loadData: ps.StepLoadData()}, nil - - case *gripql.GraphStatement_E: - if ps.LastType != gdbi.NoData { - return nil, fmt.Errorf(`"E" statement is only valid at the beginning of the traversal`) - } - ids := protoutil.AsStringList(stmt.E) - ps.LastType = gdbi.EdgeData - return &LookupEdges{db: db, ids: ids, loadData: ps.StepLoadData()}, nil - - case *gripql.GraphStatement_In: - labels := protoutil.AsStringList(gs.GetIn()) - if ps.LastType == gdbi.VertexData { - ps.LastType = gdbi.VertexData - return &LookupVertexAdjIn{db: db, labels: labels, loadData: ps.StepLoadData()}, nil - } else if ps.LastType == gdbi.EdgeData { - ps.LastType = gdbi.VertexData - return &LookupEdgeAdjIn{db: db, labels: labels, loadData: ps.StepLoadData()}, nil - } else { - return nil, fmt.Errorf(`"in" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) - } - - case *gripql.GraphStatement_InNull: - labels := protoutil.AsStringList(gs.GetInNull()) - if ps.LastType == gdbi.VertexData { - ps.LastType = gdbi.VertexData - return &LookupVertexAdjIn{db: db, labels: labels, loadData: ps.StepLoadData(), emitNull: true}, nil - } else if ps.LastType == gdbi.EdgeData { - ps.LastType = gdbi.VertexData - return &LookupEdgeAdjIn{db: db, labels: labels, loadData: ps.StepLoadData()}, nil - } else { - return nil, fmt.Errorf(`"in" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) - } - - case *gripql.GraphStatement_Out: - labels := protoutil.AsStringList(gs.GetOut()) - if ps.LastType == gdbi.VertexData { - ps.LastType = gdbi.VertexData - return &LookupVertexAdjOut{db: db, labels: labels, loadData: ps.StepLoadData()}, nil - } else if ps.LastType == gdbi.EdgeData { - ps.LastType = gdbi.VertexData - return &LookupEdgeAdjOut{db: db, labels: labels, loadData: ps.StepLoadData()}, nil - } else { - return nil, fmt.Errorf(`"out" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) - } - - case *gripql.GraphStatement_OutNull: - labels := protoutil.AsStringList(gs.GetOutNull()) - if ps.LastType == gdbi.VertexData { - ps.LastType = gdbi.VertexData - return &LookupVertexAdjOut{db: db, labels: labels, loadData: ps.StepLoadData(), emitNull: true}, nil - } else if ps.LastType == gdbi.EdgeData { - ps.LastType = gdbi.VertexData - return &LookupEdgeAdjOut{db: db, labels: labels, loadData: ps.StepLoadData()}, nil - } else { - return nil, fmt.Errorf(`"out" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) - } - - case *gripql.GraphStatement_Both: - labels := protoutil.AsStringList(gs.GetBoth()) - if ps.LastType == gdbi.VertexData { - ps.LastType = gdbi.VertexData - return &both{db: db, labels: labels, lastType: gdbi.VertexData, toType: gdbi.VertexData, loadData: ps.StepLoadData()}, nil - } else if ps.LastType == gdbi.EdgeData { - ps.LastType = gdbi.VertexData - return &both{db: db, labels: labels, lastType: gdbi.EdgeData, toType: gdbi.VertexData, loadData: ps.StepLoadData()}, nil - } else { - return nil, fmt.Errorf(`"both" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) - } - - case *gripql.GraphStatement_InE: - if ps.LastType != gdbi.VertexData { - return nil, fmt.Errorf(`"inEdge" statement is only valid for the vertex type not: %s`, ps.LastType.String()) - } - labels := protoutil.AsStringList(stmt.InE) - ps.LastType = gdbi.EdgeData - return &InE{db: db, labels: labels, loadData: ps.StepLoadData()}, nil - - case *gripql.GraphStatement_InENull: - if ps.LastType != gdbi.VertexData { - return nil, fmt.Errorf(`"inEdge" statement is only valid for the vertex type not: %s`, ps.LastType.String()) - } - labels := protoutil.AsStringList(stmt.InENull) - ps.LastType = gdbi.EdgeData - return &InE{db: db, labels: labels, loadData: ps.StepLoadData(), emitNull: true}, nil - - case *gripql.GraphStatement_OutE: - if ps.LastType != gdbi.VertexData { - return nil, fmt.Errorf(`"outEdgeNull" statement is only valid for the vertex type not: %s`, ps.LastType.String()) - } - labels := protoutil.AsStringList(stmt.OutE) - ps.LastType = gdbi.EdgeData - return &OutE{db: db, labels: labels, loadData: ps.StepLoadData()}, nil - - case *gripql.GraphStatement_OutENull: - if ps.LastType != gdbi.VertexData { - return nil, fmt.Errorf(`"outEdgeNull" statement is only valid for the vertex type not: %s`, ps.LastType.String()) - } - labels := protoutil.AsStringList(stmt.OutENull) - ps.LastType = gdbi.EdgeData - return &OutE{db: db, labels: labels, loadData: ps.StepLoadData(), emitNull: true}, nil - - case *gripql.GraphStatement_BothE: - if ps.LastType != gdbi.VertexData { - return nil, fmt.Errorf(`"bothEdge" statement is only valid for the vertex type not: %s`, ps.LastType.String()) - } - labels := protoutil.AsStringList(stmt.BothE) - ps.LastType = gdbi.EdgeData - return &both{db: db, labels: labels, lastType: gdbi.VertexData, toType: gdbi.EdgeData, loadData: ps.StepLoadData()}, nil - - case *gripql.GraphStatement_Has: - if ps.LastType != gdbi.VertexData && ps.LastType != gdbi.EdgeData { - return nil, fmt.Errorf(`"Has" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) - } - return &Has{stmt.Has}, nil - - case *gripql.GraphStatement_HasLabel: - if ps.LastType != gdbi.VertexData && ps.LastType != gdbi.EdgeData { - return nil, fmt.Errorf(`"HasLabel" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) - } - labels := protoutil.AsStringList(stmt.HasLabel) - if len(labels) == 0 { - return nil, fmt.Errorf(`no labels provided to "HasLabel" statement`) - } - return &HasLabel{labels}, nil - - case *gripql.GraphStatement_HasKey: - if ps.LastType != gdbi.VertexData && ps.LastType != gdbi.EdgeData { - return nil, fmt.Errorf(`"HasKey" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) - } - keys := protoutil.AsStringList(stmt.HasKey) - if len(keys) == 0 { - return nil, fmt.Errorf(`no keys provided to "HasKey" statement`) - } - return &HasKey{keys}, nil - - case *gripql.GraphStatement_HasId: - if ps.LastType != gdbi.VertexData && ps.LastType != gdbi.EdgeData { - return nil, fmt.Errorf(`"HasId" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) - } - ids := protoutil.AsStringList(stmt.HasId) - if len(ids) == 0 { - return nil, fmt.Errorf(`no ids provided to "HasId" statement`) - } - return &HasID{ids}, nil - - case *gripql.GraphStatement_Limit: - return &Limit{stmt.Limit}, nil - - case *gripql.GraphStatement_Skip: - return &Skip{stmt.Skip}, nil - - case *gripql.GraphStatement_Range: - return &Range{start: stmt.Range.Start, stop: stmt.Range.Stop}, nil - - case *gripql.GraphStatement_Count: - ps.LastType = gdbi.CountData - return &Count{}, nil - - case *gripql.GraphStatement_Distinct: - if ps.LastType != gdbi.VertexData && ps.LastType != gdbi.EdgeData { - return nil, fmt.Errorf(`"distinct" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) - } - fields := protoutil.AsStringList(stmt.Distinct) - if len(fields) == 0 { - fields = append(fields, "_gid") - } - return &Distinct{fields}, nil - - case *gripql.GraphStatement_As: - if ps.LastType == gdbi.NoData { - return nil, fmt.Errorf(`"mark" statement is not valid at the beginning of a traversal`) - } - if stmt.As == "" { - return nil, fmt.Errorf(`"mark" statement cannot have an empty name`) - } - if err := gripql.ValidateFieldName(stmt.As); err != nil { - return nil, fmt.Errorf(`"mark" statement invalid; %v`, err) - } - if stmt.As == jsonpath.Current { - return nil, fmt.Errorf(`"mark" statement invalid; uses reserved name %s`, jsonpath.Current) - } - ps.MarkTypes[stmt.As] = ps.LastType - return &Marker{stmt.As}, nil - - case *gripql.GraphStatement_Set: - return &ValueSet{key: stmt.Set.Key, value: stmt.Set.Value.AsInterface()}, nil - - case *gripql.GraphStatement_Increment: - return &ValueIncrement{key: stmt.Increment.Key, value: stmt.Increment.Value}, nil - - case *gripql.GraphStatement_Mark: - return &logic.JumpMark{Name: stmt.Mark}, nil - - case *gripql.GraphStatement_Jump: - j := &logic.Jump{Mark: stmt.Jump.Mark, Stmt: stmt.Jump.Expression, Emit: stmt.Jump.Emit} - return j, nil - - case *gripql.GraphStatement_Select: - if ps.LastType != gdbi.VertexData && ps.LastType != gdbi.EdgeData { - return nil, fmt.Errorf(`"select" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) - } - switch len(stmt.Select.Marks) { - case 0: - return nil, fmt.Errorf(`"select" statement has an empty list of mark names`) - case 1: - ps.LastType = ps.MarkTypes[stmt.Select.Marks[0]] - return &MarkSelect{stmt.Select.Marks[0]}, nil - default: - ps.LastType = gdbi.SelectionData - return &Selector{stmt.Select.Marks}, nil - } - - case *gripql.GraphStatement_Render: - if ps.LastType != gdbi.VertexData && ps.LastType != gdbi.EdgeData { - return nil, fmt.Errorf(`"render" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) - } - ps.LastType = gdbi.RenderData - return &Render{stmt.Render.AsInterface()}, nil - - case *gripql.GraphStatement_Path: - if ps.LastType != gdbi.VertexData && ps.LastType != gdbi.EdgeData { - return nil, fmt.Errorf(`"path" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) - } - ps.LastType = gdbi.PathData - return &Path{stmt.Path.AsSlice()}, nil - - case *gripql.GraphStatement_Unwind: - return &Unwind{stmt.Unwind}, nil - - case *gripql.GraphStatement_Fields: - if ps.LastType != gdbi.VertexData && ps.LastType != gdbi.EdgeData { - return nil, fmt.Errorf(`"fields" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) - } - fields := protoutil.AsStringList(stmt.Fields) - return &Fields{fields}, nil - - case *gripql.GraphStatement_Aggregate: - if ps.LastType != gdbi.VertexData && ps.LastType != gdbi.EdgeData { - return nil, fmt.Errorf(`"aggregate" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) - } - aggs := make(map[string]interface{}) - for _, a := range stmt.Aggregate.Aggregations { - if _, ok := aggs[a.Name]; ok { - return nil, fmt.Errorf("duplicate aggregation name '%s' found; all aggregations must have a unique name", a.Name) - } - } - ps.LastType = gdbi.AggregationData - return &aggregate{stmt.Aggregate.Aggregations}, nil - - //Custom graph statements - case *gripql.GraphStatement_LookupVertsIndex: - ps.LastType = gdbi.VertexData - return &LookupVertsIndex{db: db, labels: stmt.Labels, loadData: ps.StepLoadData()}, nil - - case *gripql.GraphStatement_EngineCustom: - proc := stmt.Custom.(gdbi.CustomProcGen) - ps.LastType = proc.GetType() - return proc.GetProcessor(db, ps) - - default: - return nil, fmt.Errorf("grip compile: unknown statement type: %s", gs.GetStatement()) - } -} - // Validate checks pipeline for chains of statements that won't work func Validate(stmts []*gripql.GraphStatement, opts *gdbi.CompileOptions) error { for i, gs := range stmts { diff --git a/engine/core/optimize.go b/engine/core/optimize.go index 260eb1c5..afac7981 100644 --- a/engine/core/optimize.go +++ b/engine/core/optimize.go @@ -2,11 +2,11 @@ package core import ( "github.com/bmeg/grip/gripql" - "github.com/bmeg/grip/jsonpath" + "github.com/bmeg/grip/travelerpath" "github.com/bmeg/grip/util/protoutil" ) -//IndexStartOptimize looks at processor pipeline for queries like +// IndexStartOptimize looks at processor pipeline for queries like // V().Has(Eq("$.label", "Person")) and V().Has(Eq("$.gid", "1")), // streamline into a single index lookup func IndexStartOptimize(pipe []*gripql.GraphStatement) []*gripql.GraphStatement { @@ -47,7 +47,7 @@ func IndexStartOptimize(pipe []*gripql.GraphStatement) []*gripql.GraphStatement return IndexStartOptimize(newPipe) } if cond := s.Has.GetCondition(); cond != nil { - path := jsonpath.GetJSONPath(cond.Key) + path := travelerpath.GetJSONPath(cond.Key) switch path { case "$.gid": hasIDIdx = append(hasIDIdx, i) diff --git a/engine/core/processors.go b/engine/core/processors.go index b37947d2..baa31243 100644 --- a/engine/core/processors.go +++ b/engine/core/processors.go @@ -11,7 +11,6 @@ import ( "github.com/bmeg/grip/engine/logic" "github.com/bmeg/grip/gdbi" "github.com/bmeg/grip/gripql" - "github.com/bmeg/grip/jsonpath" "github.com/bmeg/grip/log" "github.com/bmeg/grip/util/copy" "github.com/influxdata/tdigest" @@ -94,12 +93,7 @@ func (l *LookupVertsIndex) Process(ctx context.Context, man gdbi.Manager, in gdb defer close(out) for v := range l.db.GetVertexChannel(ctx, queryChan, l.loadData) { i := v.Ref - out <- i.AddCurrent(&gdbi.DataElement{ - ID: v.Vertex.ID, - Label: v.Vertex.Label, - Data: v.Vertex.Data, - Loaded: v.Vertex.Loaded, - }) + out <- i.AddCurrent(v.Vertex.Copy()) } }() return ctx @@ -215,7 +209,7 @@ func (l *LookupEdgeAdjOut) Process(ctx context.Context, man gdbi.Manager, in gdb queryChan <- gdbi.ElementLookup{Ref: t} } else { queryChan <- gdbi.ElementLookup{ - ID: t.GetCurrent().To, + ID: t.GetCurrent().Get().To, Ref: t, } } @@ -294,7 +288,7 @@ func (l *LookupEdgeAdjIn) Process(ctx context.Context, man gdbi.Manager, in gdbi queryChan <- gdbi.ElementLookup{Ref: t} } else { queryChan <- gdbi.ElementLookup{ - ID: t.GetCurrent().From, + ID: t.GetCurrent().Get().From, Ref: t, } } @@ -406,7 +400,7 @@ func (f *Fields) Process(ctx context.Context, man gdbi.Manager, in gdbi.InPipe, out <- t continue } - o := jsonpath.SelectTravelerFields(t, f.keys...) + o := gdbi.SelectTravelerFields(t, f.keys...) out <- o } }() @@ -429,7 +423,7 @@ func (r *Render) Process(ctx context.Context, man gdbi.Manager, in gdbi.InPipe, out <- t continue } - v := jsonpath.RenderTraveler(t, r.Template) + v := gdbi.RenderTraveler(t, r.Template) out <- &gdbi.BaseTraveler{Render: v} } }() @@ -474,27 +468,39 @@ func (r *Unwind) Process(ctx context.Context, man gdbi.Manager, in gdbi.InPipe, out <- t continue } - v := jsonpath.TravelerPathLookup(t, r.Field) + v := gdbi.TravelerPathLookup(t, r.Field) if a, ok := v.([]interface{}); ok { cur := t.GetCurrent() if len(a) > 0 { for _, i := range a { - o := gdbi.DataElement{ID: cur.ID, Label: cur.Label, From: cur.From, To: cur.To, Data: copy.DeepCopy(cur.Data).(map[string]interface{}), Loaded: true} + o := gdbi.DataElement{ + ID: cur.Get().ID, + Label: cur.Get().Label, + From: cur.Get().From, + To: cur.Get().To, + Data: copy.DeepCopy(cur.Get().Data).(map[string]interface{}), Loaded: true, + } n := t.AddCurrent(&o) - jsonpath.TravelerSetValue(n, r.Field, i) + gdbi.TravelerSetValue(n, r.Field, i) out <- n } } else { - o := gdbi.DataElement{ID: cur.ID, Label: cur.Label, From: cur.From, To: cur.To, Data: copy.DeepCopy(cur.Data).(map[string]interface{}), Loaded: true} + o := gdbi.DataElement{ID: cur.Get().ID, Label: cur.Get().Label, From: cur.Get().From, To: cur.Get().To, Data: copy.DeepCopy(cur.Get().Data).(map[string]interface{}), Loaded: true} n := t.AddCurrent(&o) - jsonpath.TravelerSetValue(n, r.Field, nil) + gdbi.TravelerSetValue(n, r.Field, nil) out <- n } } else { cur := t.GetCurrent() - o := gdbi.DataElement{ID: cur.ID, Label: cur.Label, From: cur.From, To: cur.To, Data: copy.DeepCopy(cur.Data).(map[string]interface{}), Loaded: true} + o := gdbi.DataElement{ + ID: cur.Get().ID, + Label: cur.Get().Label, + From: cur.Get().From, + To: cur.Get().To, + Data: copy.DeepCopy(cur.Get().Data).(map[string]interface{}), Loaded: true, + } n := t.AddCurrent(&o) - jsonpath.TravelerSetValue(n, r.Field, nil) + gdbi.TravelerSetValue(n, r.Field, nil) out <- n } } @@ -543,7 +549,7 @@ func (h *HasLabel) Process(ctx context.Context, man gdbi.Manager, in gdbi.InPipe out <- t continue } - if contains(labels, t.GetCurrent().Label) { + if contains(labels, t.GetCurrent().Get().Label) { out <- t } } @@ -570,7 +576,7 @@ func (h *HasKey) Process(ctx context.Context, man gdbi.Manager, in gdbi.InPipe, } found := true for _, key := range keys { - if !jsonpath.TravelerPathExists(t, key) { + if !gdbi.TravelerPathExists(t, key) { found = false } } @@ -737,8 +743,8 @@ func (g *Distinct) Process(ctx context.Context, man gdbi.Manager, in gdbi.InPipe s := make([][]byte, len(g.vals)) found := true for i, v := range g.vals { - if jsonpath.TravelerPathExists(t, v) { - s[i] = []byte(fmt.Sprintf("%#v", jsonpath.TravelerPathLookup(t, v))) + if gdbi.TravelerPathExists(t, v) { + s[i] = []byte(fmt.Sprintf("%#v", gdbi.TravelerPathLookup(t, v))) } else { found = false } @@ -793,7 +799,7 @@ func (s *Selector) Process(ctx context.Context, man gdbi.Manager, in gdbi.InPipe out <- t continue } - res := map[string]*gdbi.DataElement{} + res := map[string]gdbi.DataRef{} for _, mark := range s.marks { val := t.GetMark(mark) if val == nil { @@ -822,7 +828,7 @@ func (s *ValueSet) Process(ctx context.Context, man gdbi.Manager, in gdbi.InPipe out <- t continue } - jsonpath.TravelerSetValue(t, s.key, s.value) + gdbi.TravelerSetValue(t, s.key, s.value) out <- t } }() @@ -842,10 +848,10 @@ func (s *ValueIncrement) Process(ctx context.Context, man gdbi.Manager, in gdbi. out <- t continue } - v := jsonpath.TravelerPathLookup(t, s.key) + v := gdbi.TravelerPathLookup(t, s.key) i := cast.ToInt(v) + int(s.value) o := t.Copy() - jsonpath.TravelerSetValue(o, s.key, i) + gdbi.TravelerSetValue(o, s.key, i) out <- o } }() @@ -996,7 +1002,7 @@ func (agg *aggregate) Process(ctx context.Context, man gdbi.Manager, in gdbi.InP if len(fieldTermCounts) > maxTerms { outErr = fmt.Errorf("term aggreagtion: collected more unique terms (%v) than allowed (%v)", len(fieldTermCounts), maxTerms) } else { - val := jsonpath.TravelerPathLookup(t, tagg.Field) + val := gdbi.TravelerPathLookup(t, tagg.Field) if val != nil { k := reflect.TypeOf(val).Kind() if k != reflect.Array && k != reflect.Slice && k != reflect.Map { @@ -1034,7 +1040,7 @@ func (agg *aggregate) Process(ctx context.Context, man gdbi.Manager, in gdbi.InP // If we return error before fully emptying channel, upstream processes will lock var outErr error for t := range aChans[a.Name] { - val := jsonpath.TravelerPathLookup(t, hagg.Field) + val := gdbi.TravelerPathLookup(t, hagg.Field) if val != nil { fval, err := cast.ToFloat64E(val) if err != nil { @@ -1073,7 +1079,7 @@ func (agg *aggregate) Process(ctx context.Context, man gdbi.Manager, in gdbi.InP var outErr error td := tdigest.New() for t := range aChans[a.Name] { - val := jsonpath.TravelerPathLookup(t, pagg.Field) + val := gdbi.TravelerPathLookup(t, pagg.Field) fval, err := cast.ToFloat64E(val) if err != nil { outErr = fmt.Errorf("percentile aggregation: can't convert %v to float64", val) @@ -1095,7 +1101,7 @@ func (agg *aggregate) Process(ctx context.Context, man gdbi.Manager, in gdbi.InP fa := a.GetField() fieldCounts := map[interface{}]int{} for t := range aChans[a.Name] { - val := jsonpath.TravelerPathLookup(t, fa.Field) + val := gdbi.TravelerPathLookup(t, fa.Field) if m, ok := val.(map[string]interface{}); ok { for k := range m { fieldCounts[k]++ @@ -1113,7 +1119,7 @@ func (agg *aggregate) Process(ctx context.Context, man gdbi.Manager, in gdbi.InP fa := a.GetType() fieldTypes := map[string]int{} for t := range aChans[a.Name] { - val := jsonpath.TravelerPathLookup(t, fa.Field) + val := gdbi.TravelerPathLookup(t, fa.Field) tname := gripql.GetFieldType(val) fieldTypes[tname]++ } diff --git a/engine/core/processors_extra.go b/engine/core/processors_extra.go index a78a6730..ac85838a 100644 --- a/engine/core/processors_extra.go +++ b/engine/core/processors_extra.go @@ -7,9 +7,9 @@ import ( "strings" "github.com/bmeg/grip/gripql" - "github.com/bmeg/grip/jsonpath" "github.com/bmeg/grip/kvi" "github.com/bmeg/grip/kvindex" + "github.com/bmeg/grip/travelerpath" "github.com/influxdata/tdigest" "golang.org/x/sync/errgroup" @@ -61,8 +61,8 @@ func (agg *aggregateDisk) Process(ctx context.Context, man gdbi.Manager, in gdbi kv := man.GetTempKV() idx := kvindex.NewIndex(kv) - namespace := jsonpath.GetNamespace(tagg.Field) - field := jsonpath.GetJSONPath(tagg.Field) + namespace := travelerpath.GetNamespace(tagg.Field) + field := travelerpath.GetJSONPath(tagg.Field) field = strings.TrimPrefix(field, "$.") idx.AddField(field) @@ -70,7 +70,7 @@ func (agg *aggregateDisk) Process(ctx context.Context, man gdbi.Manager, in gdbi for batch := range aChans[a.Name] { err := kv.Update(func(tx kvi.KVTransaction) error { for _, t := range batch { - doc := jsonpath.GetDoc(t, namespace) + doc := gdbi.GetDoc(t, namespace) err := idx.AddDocTx(tx, fmt.Sprintf("%d", tid), doc) tid++ if err != nil { @@ -107,8 +107,8 @@ func (agg *aggregateDisk) Process(ctx context.Context, man gdbi.Manager, in gdbi kv := man.GetTempKV() idx := kvindex.NewIndex(kv) - namespace := jsonpath.GetNamespace(hagg.Field) - field := jsonpath.GetJSONPath(hagg.Field) + namespace := travelerpath.GetNamespace(hagg.Field) + field := travelerpath.GetJSONPath(hagg.Field) field = strings.TrimPrefix(field, "$.") idx.AddField(field) @@ -116,7 +116,7 @@ func (agg *aggregateDisk) Process(ctx context.Context, man gdbi.Manager, in gdbi for batch := range aChans[a.Name] { err := kv.Update(func(tx kvi.KVTransaction) error { for _, t := range batch { - doc := jsonpath.GetDoc(t, namespace) + doc := gdbi.GetDoc(t, namespace) err := idx.AddDocTx(tx, fmt.Sprintf("%d", tid), doc) tid++ if err != nil { @@ -152,8 +152,8 @@ func (agg *aggregateDisk) Process(ctx context.Context, man gdbi.Manager, in gdbi kv := man.GetTempKV() idx := kvindex.NewIndex(kv) - namespace := jsonpath.GetNamespace(pagg.Field) - field := jsonpath.GetJSONPath(pagg.Field) + namespace := travelerpath.GetNamespace(pagg.Field) + field := travelerpath.GetJSONPath(pagg.Field) field = strings.TrimPrefix(field, "$.") idx.AddField(field) @@ -161,7 +161,7 @@ func (agg *aggregateDisk) Process(ctx context.Context, man gdbi.Manager, in gdbi for batch := range aChans[a.Name] { err := kv.Update(func(tx kvi.KVTransaction) error { for _, t := range batch { - doc := jsonpath.GetDoc(t, namespace) + doc := gdbi.GetDoc(t, namespace) err := idx.AddDocTx(tx, fmt.Sprintf("%d", tid), doc) tid++ if err != nil { diff --git a/engine/core/statement_compiler.go b/engine/core/statement_compiler.go new file mode 100644 index 00000000..015c7f0a --- /dev/null +++ b/engine/core/statement_compiler.go @@ -0,0 +1,250 @@ +package core + +import ( + "fmt" + + "github.com/bmeg/grip/engine/logic" + "github.com/bmeg/grip/gdbi" + "github.com/bmeg/grip/gripql" + "github.com/bmeg/grip/travelerpath" + "github.com/bmeg/grip/util/protoutil" +) + +type DefaultStmtCompiler struct { + db gdbi.GraphInterface +} + +func (sc *DefaultStmtCompiler) V(stmt *gripql.GraphStatement_V, ps *gdbi.State) (gdbi.Processor, error) { + ids := protoutil.AsStringList(stmt.V) + return &LookupVerts{db: sc.db, ids: ids, loadData: ps.StepLoadData()}, nil +} + +func (sc *DefaultStmtCompiler) E(stmt *gripql.GraphStatement_E, ps *gdbi.State) (gdbi.Processor, error) { + ids := protoutil.AsStringList(stmt.E) + return &LookupEdges{db: sc.db, ids: ids, loadData: ps.StepLoadData()}, nil +} + +func (sc *DefaultStmtCompiler) In(stmt *gripql.GraphStatement_In, ps *gdbi.State) (gdbi.Processor, error) { + labels := protoutil.AsStringList(stmt.In) + if ps.LastType == gdbi.VertexData { + return &LookupVertexAdjIn{db: sc.db, labels: labels, loadData: ps.StepLoadData()}, nil + } else if ps.LastType == gdbi.EdgeData { + return &LookupEdgeAdjIn{db: sc.db, labels: labels, loadData: ps.StepLoadData()}, nil + } else { + return nil, fmt.Errorf(`"in" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } +} + +func (sc *DefaultStmtCompiler) InNull(stmt *gripql.GraphStatement_InNull, ps *gdbi.State) (gdbi.Processor, error) { + labels := protoutil.AsStringList(stmt.InNull) + if ps.LastType == gdbi.VertexData { + return &LookupVertexAdjIn{db: sc.db, labels: labels, loadData: ps.StepLoadData(), emitNull: true}, nil + } else if ps.LastType == gdbi.EdgeData { + return &LookupEdgeAdjIn{db: sc.db, labels: labels, loadData: ps.StepLoadData()}, nil + } else { + return nil, fmt.Errorf(`"in" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } +} +func (sc *DefaultStmtCompiler) Out(stmt *gripql.GraphStatement_Out, ps *gdbi.State) (gdbi.Processor, error) { + labels := protoutil.AsStringList(stmt.Out) + if ps.LastType == gdbi.VertexData { + return &LookupVertexAdjOut{db: sc.db, labels: labels, loadData: ps.StepLoadData()}, nil + } else if ps.LastType == gdbi.EdgeData { + return &LookupEdgeAdjOut{db: sc.db, labels: labels, loadData: ps.StepLoadData()}, nil + } else { + return nil, fmt.Errorf(`"out" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } +} + +func (sc *DefaultStmtCompiler) OutNull(stmt *gripql.GraphStatement_OutNull, ps *gdbi.State) (gdbi.Processor, error) { + labels := protoutil.AsStringList(stmt.OutNull) + if ps.LastType == gdbi.VertexData { + return &LookupVertexAdjOut{db: sc.db, labels: labels, loadData: ps.StepLoadData(), emitNull: true}, nil + } else if ps.LastType == gdbi.EdgeData { + return &LookupEdgeAdjOut{db: sc.db, labels: labels, loadData: ps.StepLoadData()}, nil + } else { + return nil, fmt.Errorf(`"out" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } +} + +func (sc *DefaultStmtCompiler) Both(stmt *gripql.GraphStatement_Both, ps *gdbi.State) (gdbi.Processor, error) { + labels := protoutil.AsStringList(stmt.Both) + if ps.LastType == gdbi.VertexData { + return &both{db: sc.db, labels: labels, lastType: gdbi.VertexData, toType: gdbi.VertexData, loadData: ps.StepLoadData()}, nil + } else if ps.LastType == gdbi.EdgeData { + return &both{db: sc.db, labels: labels, lastType: gdbi.EdgeData, toType: gdbi.VertexData, loadData: ps.StepLoadData()}, nil + } else { + return nil, fmt.Errorf(`"both" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } +} + +func (sc *DefaultStmtCompiler) InE(stmt *gripql.GraphStatement_InE, ps *gdbi.State) (gdbi.Processor, error) { + labels := protoutil.AsStringList(stmt.InE) + return &InE{db: sc.db, labels: labels, loadData: ps.StepLoadData()}, nil +} + +func (sc *DefaultStmtCompiler) InENull(stmt *gripql.GraphStatement_InENull, ps *gdbi.State) (gdbi.Processor, error) { + labels := protoutil.AsStringList(stmt.InENull) + ps.LastType = gdbi.EdgeData + return &InE{db: sc.db, labels: labels, loadData: ps.StepLoadData(), emitNull: true}, nil +} + +func (sc *DefaultStmtCompiler) OutE(stmt *gripql.GraphStatement_OutE, ps *gdbi.State) (gdbi.Processor, error) { + labels := protoutil.AsStringList(stmt.OutE) + ps.LastType = gdbi.EdgeData + return &OutE{db: sc.db, labels: labels, loadData: ps.StepLoadData()}, nil +} + +func (sc *DefaultStmtCompiler) OutENull(stmt *gripql.GraphStatement_OutENull, ps *gdbi.State) (gdbi.Processor, error) { + labels := protoutil.AsStringList(stmt.OutENull) + ps.LastType = gdbi.EdgeData + return &OutE{db: sc.db, labels: labels, loadData: ps.StepLoadData(), emitNull: true}, nil +} + +func (sc *DefaultStmtCompiler) BothE(stmt *gripql.GraphStatement_BothE, ps *gdbi.State) (gdbi.Processor, error) { + labels := protoutil.AsStringList(stmt.BothE) + ps.LastType = gdbi.EdgeData + return &both{db: sc.db, labels: labels, lastType: gdbi.VertexData, toType: gdbi.EdgeData, loadData: ps.StepLoadData()}, nil +} + +func (sc *DefaultStmtCompiler) Has(stmt *gripql.GraphStatement_Has, ps *gdbi.State) (gdbi.Processor, error) { + return &Has{stmt.Has}, nil +} + +func (sc *DefaultStmtCompiler) HasLabel(stmt *gripql.GraphStatement_HasLabel, ps *gdbi.State) (gdbi.Processor, error) { + labels := protoutil.AsStringList(stmt.HasLabel) + if len(labels) == 0 { + return nil, fmt.Errorf(`no labels provided to "HasLabel" statement`) + } + return &HasLabel{labels}, nil +} + +func (sc *DefaultStmtCompiler) HasKey(stmt *gripql.GraphStatement_HasKey, ps *gdbi.State) (gdbi.Processor, error) { + keys := protoutil.AsStringList(stmt.HasKey) + if len(keys) == 0 { + return nil, fmt.Errorf(`no keys provided to "HasKey" statement`) + } + return &HasKey{keys}, nil +} + +func (sc *DefaultStmtCompiler) HasID(stmt *gripql.GraphStatement_HasId, ps *gdbi.State) (gdbi.Processor, error) { + ids := protoutil.AsStringList(stmt.HasId) + if len(ids) == 0 { + return nil, fmt.Errorf(`no ids provided to "HasId" statement`) + } + return &HasID{ids}, nil +} + +func (sc *DefaultStmtCompiler) Limit(stmt *gripql.GraphStatement_Limit, ps *gdbi.State) (gdbi.Processor, error) { + return &Limit{stmt.Limit}, nil +} + +func (sc *DefaultStmtCompiler) Skip(stmt *gripql.GraphStatement_Skip, ps *gdbi.State) (gdbi.Processor, error) { + return &Skip{stmt.Skip}, nil +} + +func (sc *DefaultStmtCompiler) Range(stmt *gripql.GraphStatement_Range, ps *gdbi.State) (gdbi.Processor, error) { + return &Range{start: stmt.Range.Start, stop: stmt.Range.Stop}, nil +} + +func (sc *DefaultStmtCompiler) Count(stmt *gripql.GraphStatement_Count, ps *gdbi.State) (gdbi.Processor, error) { + return &Count{}, nil +} + +func (sc *DefaultStmtCompiler) Distinct(stmt *gripql.GraphStatement_Distinct, ps *gdbi.State) (gdbi.Processor, error) { + fields := protoutil.AsStringList(stmt.Distinct) + if len(fields) == 0 { + fields = append(fields, "_gid") + } + return &Distinct{fields}, nil +} + +func (sc *DefaultStmtCompiler) As(stmt *gripql.GraphStatement_As, ps *gdbi.State) (gdbi.Processor, error) { + if stmt.As == "" { + return nil, fmt.Errorf(`"mark" statement cannot have an empty name`) + } + if err := gripql.ValidateFieldName(stmt.As); err != nil { + return nil, fmt.Errorf(`"mark" statement invalid; %v`, err) + } + if stmt.As == travelerpath.Current { + return nil, fmt.Errorf(`"mark" statement invalid; uses reserved name %s`, travelerpath.Current) + } + ps.MarkTypes[stmt.As] = ps.LastType + return &Marker{stmt.As}, nil +} + +func (sc *DefaultStmtCompiler) Set(stmt *gripql.GraphStatement_Set, ps *gdbi.State) (gdbi.Processor, error) { + return &ValueSet{key: stmt.Set.Key, value: stmt.Set.Value.AsInterface()}, nil +} + +func (sc *DefaultStmtCompiler) Increment(stmt *gripql.GraphStatement_Increment, ps *gdbi.State) (gdbi.Processor, error) { + return &ValueIncrement{key: stmt.Increment.Key, value: stmt.Increment.Value}, nil +} + +func (sc *DefaultStmtCompiler) Mark(stmt *gripql.GraphStatement_Mark, ps *gdbi.State) (gdbi.Processor, error) { + return &logic.JumpMark{Name: stmt.Mark}, nil +} + +func (sc *DefaultStmtCompiler) Jump(stmt *gripql.GraphStatement_Jump, ps *gdbi.State) (gdbi.Processor, error) { + return &logic.Jump{Mark: stmt.Jump.Mark, Stmt: stmt.Jump.Expression, Emit: stmt.Jump.Emit}, nil +} + +func (sc *DefaultStmtCompiler) Select(stmt *gripql.GraphStatement_Select, ps *gdbi.State) (gdbi.Processor, error) { + switch len(stmt.Select.Marks) { + case 0: + return nil, fmt.Errorf(`"select" statement has an empty list of mark names`) + case 1: + ps.LastType = ps.MarkTypes[stmt.Select.Marks[0]] + return &MarkSelect{stmt.Select.Marks[0]}, nil + default: + ps.LastType = gdbi.SelectionData + return &Selector{stmt.Select.Marks}, nil + } +} + +func (sc *DefaultStmtCompiler) Render(stmt *gripql.GraphStatement_Render, ps *gdbi.State) (gdbi.Processor, error) { + return &Render{stmt.Render.AsInterface()}, nil +} + +func (sc *DefaultStmtCompiler) Path(stmt *gripql.GraphStatement_Path, ps *gdbi.State) (gdbi.Processor, error) { + return &Path{stmt.Path.AsSlice()}, nil +} + +func (sc *DefaultStmtCompiler) Unwind(stmt *gripql.GraphStatement_Unwind, ps *gdbi.State) (gdbi.Processor, error) { + return &Unwind{stmt.Unwind}, nil +} + +func (sc *DefaultStmtCompiler) Fields(stmt *gripql.GraphStatement_Fields, ps *gdbi.State) (gdbi.Processor, error) { + fields := protoutil.AsStringList(stmt.Fields) + return &Fields{fields}, nil +} + +func (sc *DefaultStmtCompiler) Aggregate(stmt *gripql.GraphStatement_Aggregate, ps *gdbi.State) (gdbi.Processor, error) { + aggs := make(map[string]interface{}) + for _, a := range stmt.Aggregate.Aggregations { + if _, ok := aggs[a.Name]; ok { + return nil, fmt.Errorf("duplicate aggregation name '%s' found; all aggregations must have a unique name", a.Name) + } + } + return &aggregate{stmt.Aggregate.Aggregations}, nil +} + +func (sc *DefaultStmtCompiler) Custom(gs *gripql.GraphStatement, ps *gdbi.State) (gdbi.Processor, error) { + + switch stmt := gs.GetStatement().(type) { + + //Custom graph statements + case *gripql.GraphStatement_LookupVertsIndex: + ps.LastType = gdbi.VertexData + return &LookupVertsIndex{db: sc.db, labels: stmt.Labels, loadData: ps.StepLoadData()}, nil + + case *gripql.GraphStatement_EngineCustom: + proc := stmt.Custom.(gdbi.CustomProcGen) + ps.LastType = proc.GetType() + return proc.GetProcessor(sc.db, ps) + + default: + return nil, fmt.Errorf("grip compile: unknown statement type: %s", gs.GetStatement()) + } + +} diff --git a/engine/inspect/haslabel.go b/engine/inspect/haslabel.go deleted file mode 100644 index fa9abdcc..00000000 --- a/engine/inspect/haslabel.go +++ /dev/null @@ -1,59 +0,0 @@ -package inspect - -import ( - "github.com/bmeg/grip/gripql" - "github.com/bmeg/grip/util/protoutil" -) - -func FindVertexHasLabelStart(pipe []*gripql.GraphStatement) ([]string, []*gripql.GraphStatement) { - hasLabelLen := 0 - labels := []string{} - isDone := false - for i, step := range pipe { - if isDone { - break - } - if i == 0 { - if _, ok := step.GetStatement().(*gripql.GraphStatement_V); ok { - //lookupV = lv - } else { - break - } - continue - } - switch s := step.GetStatement().(type) { - case *gripql.GraphStatement_HasLabel: - labels = protoutil.AsStringList(s.HasLabel) - hasLabelLen = i + 1 - default: - isDone = true - } - } - return labels, pipe[hasLabelLen:] -} - -func FindEdgeHasLabelStart(pipe []*gripql.GraphStatement) ([]string, []*gripql.GraphStatement) { - hasLabelLen := 0 - labels := []string{} - isDone := false - for i, step := range pipe { - if isDone { - break - } - if i == 0 { - if _, ok := step.GetStatement().(*gripql.GraphStatement_E); ok { - } else { - break - } - continue - } - switch s := step.GetStatement().(type) { - case *gripql.GraphStatement_HasLabel: - labels = protoutil.AsStringList(s.HasLabel) - hasLabelLen = i + 1 - default: - isDone = true - } - } - return labels, pipe[hasLabelLen:] -} diff --git a/engine/inspect/inspect.go b/engine/inspect/inspect.go deleted file mode 100644 index 41190909..00000000 --- a/engine/inspect/inspect.go +++ /dev/null @@ -1,172 +0,0 @@ -package inspect - -import ( - "fmt" - - "github.com/bmeg/grip/gripql" - "github.com/bmeg/grip/jsonpath" - "github.com/bmeg/grip/log" - "github.com/bmeg/grip/util/protoutil" -) - -func arrayEq(a, b []string) bool { - if len(a) != len(b) { - return false - } - for i := range a { - if a[i] != b[i] { - return false - } - } - return true -} - -func contains(a []string, n string) bool { - for _, c := range a { - if c == n { - return true - } - } - return false -} - -// PipelineSteps create an array, the same length at stmts that labels the -// step id for each of the GraphStatements -func PipelineSteps(stmts []*gripql.GraphStatement) []string { - out := []string{} - curState := 0 - for _, gs := range stmts { - switch gs.GetStatement().(type) { - //These commands all change the position of the traveler. When that happens, - //we go to the next 'step' of the traversal - case *gripql.GraphStatement_V, *gripql.GraphStatement_E, *gripql.GraphStatement_Out, - *gripql.GraphStatement_In, *gripql.GraphStatement_OutE, *gripql.GraphStatement_InE, - *gripql.GraphStatement_Both, *gripql.GraphStatement_BothE, *gripql.GraphStatement_Select, - *gripql.GraphStatement_InNull, *gripql.GraphStatement_OutNull, - *gripql.GraphStatement_InENull, *gripql.GraphStatement_OutENull: - curState++ - case *gripql.GraphStatement_Limit, *gripql.GraphStatement_As, *gripql.GraphStatement_Has, - *gripql.GraphStatement_HasId, *gripql.GraphStatement_HasKey, *gripql.GraphStatement_HasLabel, - *gripql.GraphStatement_Count, *gripql.GraphStatement_Skip, *gripql.GraphStatement_Distinct, - *gripql.GraphStatement_Range, *gripql.GraphStatement_Aggregate, *gripql.GraphStatement_Render, - *gripql.GraphStatement_Fields, *gripql.GraphStatement_Unwind, *gripql.GraphStatement_Path, - *gripql.GraphStatement_Set, *gripql.GraphStatement_Increment, - *gripql.GraphStatement_Mark, *gripql.GraphStatement_Jump: - case *gripql.GraphStatement_LookupVertsIndex, *gripql.GraphStatement_EngineCustom: - default: - log.Errorf("Unknown Graph Statement: %T", gs.GetStatement()) - } - out = append(out, fmt.Sprintf("%d", curState)) - } - return out -} - -// PipelineSteps identify the variable names each step can be aliasesed using -// the as_ operation -func PipelineAsSteps(stmts []*gripql.GraphStatement) map[string]string { - out := map[string]string{} - steps := PipelineSteps(stmts) - - for i, gs := range stmts { - switch stmt := gs.GetStatement().(type) { - case *gripql.GraphStatement_As: - out[stmt.As] = steps[i] - } - } - return out -} - -// PipelineStepOutputs identify the required outputs for each step in the traversal -func PipelineStepOutputs(stmts []*gripql.GraphStatement) map[string][]string { - - steps := PipelineSteps(stmts) - asMap := PipelineAsSteps(stmts) - onLast := true - out := map[string][]string{} - for i := len(stmts) - 1; i >= 0; i-- { - gs := stmts[i] - switch gs.GetStatement().(type) { - case *gripql.GraphStatement_Count: - onLast = false - case *gripql.GraphStatement_Select: - if onLast { - sel := gs.GetSelect().Marks - for _, s := range sel { - if a, ok := asMap[s]; ok { - out[a] = []string{"*"} - } - } - onLast = false - } - case *gripql.GraphStatement_Distinct: - //if there is a distinct step, we need to load data, but only for requested fields - fields := protoutil.AsStringList(gs.GetDistinct()) - for _, f := range fields { - n := jsonpath.GetNamespace(f) - if n == "__current__" { - out[steps[i]] = []string{"*"} - } - if a, ok := asMap[n]; ok { - out[a] = []string{"*"} - } - } - case *gripql.GraphStatement_V, *gripql.GraphStatement_E, - *gripql.GraphStatement_Out, *gripql.GraphStatement_In, - *gripql.GraphStatement_OutE, *gripql.GraphStatement_InE, - *gripql.GraphStatement_Both, *gripql.GraphStatement_BothE: - if onLast { - out[steps[i]] = []string{"*"} - } - onLast = false - case *gripql.GraphStatement_LookupVertsIndex: - if onLast { - out[steps[i]] = []string{"*"} - } - onLast = false - - case *gripql.GraphStatement_HasLabel: - if x, ok := out[steps[i]]; ok { - out[steps[i]] = append(x, "_label") - } else { - out[steps[i]] = []string{"_label"} - } - case *gripql.GraphStatement_Has: - out[steps[i]] = []string{"*"} - } - } - return out -} - -// PipelineNoLoadPath identifies 'paths' which are groups of statements that move -// travelers across multiple steps, and don't require data (other then the label) -// to be loaded -func PipelineNoLoadPath(stmts []*gripql.GraphStatement, minLen int) [][]int { - out := [][]int{} - - steps := PipelineSteps(stmts) - outputs := PipelineStepOutputs(stmts) - curPath := []int{} - for i := range steps { - switch stmts[i].GetStatement().(type) { - case *gripql.GraphStatement_In, *gripql.GraphStatement_Out, - *gripql.GraphStatement_InE, *gripql.GraphStatement_OutE, - *gripql.GraphStatement_HasLabel: - if s, ok := outputs[steps[i]]; !ok { - curPath = append(curPath, i) - } else { - if arrayEq(s, []string{"_label"}) { - curPath = append(curPath, i) - } else { - if len(curPath) >= minLen { - out = append(out, curPath) - } - curPath = []int{} - } - } - } - } - if len(curPath) >= minLen { - out = append(out, curPath) - } - return out -} diff --git a/engine/logic/jump.go b/engine/logic/jump.go index 8b7c297d..dc4f0d35 100644 --- a/engine/logic/jump.go +++ b/engine/logic/jump.go @@ -5,7 +5,6 @@ import ( "fmt" "time" - "github.com/bmeg/grip/engine/queue" "github.com/bmeg/grip/gdbi" "github.com/bmeg/grip/gripql" ) @@ -139,11 +138,11 @@ type Jump struct { Stmt *gripql.HasExpression Emit bool jumpers chan gdbi.Traveler - queue queue.Queue + queue gdbi.Queue } func (s *Jump) Init() { - q := queue.New() + q := gdbi.NewQueue() s.jumpers = q.GetInput() s.queue = q } diff --git a/engine/logic/match.go b/engine/logic/match.go index 99c21fe4..63dde0f3 100644 --- a/engine/logic/match.go +++ b/engine/logic/match.go @@ -7,14 +7,13 @@ import ( "github.com/bmeg/grip/gdbi" "github.com/bmeg/grip/gripql" - "github.com/bmeg/grip/jsonpath" "github.com/bmeg/grip/log" ) func MatchesCondition(trav gdbi.Traveler, cond *gripql.HasCondition) bool { var val interface{} var condVal interface{} - val = jsonpath.TravelerPathLookup(trav, cond.Key) + val = gdbi.TravelerPathLookup(trav, cond.Key) condVal = cond.Value.AsInterface() switch cond.Condition { diff --git a/engine/pipeline/pipes.go b/engine/pipeline/pipes.go index e286c552..3756f54d 100644 --- a/engine/pipeline/pipes.go +++ b/engine/pipeline/pipes.go @@ -118,7 +118,7 @@ func Resume(ctx context.Context, pipe gdbi.Pipeline, workdir string, input gdbi. func Convert(graph gdbi.GraphInterface, dataType gdbi.DataType, markTypes map[string]gdbi.DataType, t gdbi.Traveler) *gripql.QueryResult { switch dataType { case gdbi.VertexData: - ve := t.GetCurrent() + ve := t.GetCurrent().Get() if ve != nil { if !ve.Loaded { //log.Infof("Loading output vertex: %s", ve.ID) @@ -136,7 +136,7 @@ func Convert(graph gdbi.GraphInterface, dataType gdbi.DataType, markTypes map[st } case gdbi.EdgeData: - ee := t.GetCurrent() + ee := t.GetCurrent().Get() if ee != nil { if !ee.Loaded { ee = graph.GetEdge(ee.ID, true) @@ -160,13 +160,14 @@ func Convert(graph gdbi.GraphInterface, dataType gdbi.DataType, markTypes map[st case gdbi.SelectionData: selections := map[string]*gripql.Selection{} for k, v := range t.GetSelections() { + vd := v.Get() switch markTypes[k] { case gdbi.VertexData: var ve *gripql.Vertex - if !v.Loaded { - ve = graph.GetVertex(v.ID, true).ToVertex() + if !vd.Loaded { + ve = graph.GetVertex(vd.ID, true).ToVertex() } else { - ve = v.ToVertex() + ve = vd.ToVertex() } selections[k] = &gripql.Selection{ Result: &gripql.Selection_Vertex{ @@ -175,10 +176,10 @@ func Convert(graph gdbi.GraphInterface, dataType gdbi.DataType, markTypes map[st } case gdbi.EdgeData: var ee *gripql.Edge - if !v.Loaded { + if !vd.Loaded { ee = graph.GetEdge(ee.Gid, true).ToEdge() } else { - ee = v.ToEdge() + ee = vd.ToEdge() } selections[k] = &gripql.Selection{ Result: &gripql.Selection_Edge{ diff --git a/engine/queue/queue.go b/engine/queue/queue.go deleted file mode 100644 index d0849b5f..00000000 --- a/engine/queue/queue.go +++ /dev/null @@ -1,74 +0,0 @@ -package queue - -import ( - "fmt" - "sync" - "github.com/bmeg/grip/gdbi" -) - -type MemQueue struct { - input chan gdbi.Traveler - output chan gdbi.Traveler -} - -type Queue interface { - GetInput() chan gdbi.Traveler - GetOutput() chan gdbi.Traveler -} - - -func New() Queue { - o := MemQueue{ - input: make(chan gdbi.Traveler, 50), - output: make(chan gdbi.Traveler, 50), - } - queue := make([]gdbi.Traveler, 0, 1000) - closed := false - m := &sync.Mutex{} - inCount := 0 - outCount := 0 - go func() { - for i := range o.input { - m.Lock() - inCount++ - if i.IsSignal() { - //fmt.Printf("Queue got signal %d\n", i.Signal.ID) - } - //fmt.Printf("Queue Size: %d %d / %d\n", len(queue), inCount, outCount) - queue = append(queue, i) - m.Unlock() - } - closed = true - }() - go func() { - defer close(o.output) - for running := true; running ;{ - var v gdbi.Traveler - m.Lock() - if len(queue) > 0 { - v = queue[0] - queue = queue[1:] - } else { - if closed { - running = false - } - } - m.Unlock() - if v != nil { - o.output <- v - outCount++ - } - } - fmt.Printf("Closing Queue Size: %d %d / %d\n", len(queue), inCount, outCount) - fmt.Printf("Closing Buffered Queue\n") - }() - return &o -} - -func (q *MemQueue) GetInput() chan gdbi.Traveler { - return q.input -} - -func (q *MemQueue) GetOutput() chan gdbi.Traveler { - return q.output -} diff --git a/gdbi/interface.go b/gdbi/interface.go index 88eca9ab..1f5a1de6 100644 --- a/gdbi/interface.go +++ b/gdbi/interface.go @@ -26,10 +26,34 @@ type DataElement struct { Loaded bool } -type Vertex = DataElement +// DataRef is a handler interface above DataElement, that allows processing pipelines +// to avoid loading data data required for DataElement until it is actually needed +type DataRef interface { + Get() *DataElement + Copy() DataRef +} + +func (d *DataElement) Get() *DataElement { + return d +} + +func (d *DataElement) Copy() DataRef { + return &DataElement{ + ID: d.ID, + To: d.To, + From: d.From, + Label: d.Label, + Loaded: d.Loaded, + Data: d.Data, + } +} +type Vertex = DataElement type Edge = DataElement +type VertexRef = DataRef +type EdgeRef = DataRef + type GraphElement struct { Vertex *Vertex Edge *Edge @@ -54,9 +78,9 @@ type Signal struct { // Traveler is a query element that traverse the graph type BaseTraveler struct { - Current *DataElement - Marks map[string]*DataElement - Selections map[string]*DataElement + Current DataRef + Marks map[string]DataRef + Selections map[string]DataRef Aggregation *Aggregate Count uint32 Render interface{} @@ -68,15 +92,15 @@ type Traveler interface { IsSignal() bool GetSignal() Signal IsNull() bool - GetCurrent() *DataElement + GetCurrent() DataRef GetCurrentID() string - AddCurrent(r *DataElement) Traveler + AddCurrent(r DataRef) Traveler Copy() Traveler HasMark(label string) bool - GetMark(label string) *DataElement - AddMark(label string, r *DataElement) Traveler + GetMark(label string) DataRef + AddMark(label string, r DataRef) Traveler ListMarks() []string - GetSelections() map[string]*DataElement + GetSelections() map[string]DataRef GetRender() interface{} GetPath() []DataElementID GetAggregation() *Aggregate @@ -102,8 +126,8 @@ const ( type ElementLookup struct { ID string Ref Traveler - Vertex *Vertex - Edge *Edge + Vertex VertexRef + Edge EdgeRef } // GraphDB is the base interface for graph databases diff --git a/jsonpath/jsonpath.go b/gdbi/jsonpath.go similarity index 70% rename from jsonpath/jsonpath.go rename to gdbi/jsonpath.go index f65a27b2..f77ceb47 100644 --- a/jsonpath/jsonpath.go +++ b/gdbi/jsonpath.go @@ -1,64 +1,15 @@ -package jsonpath +package gdbi import ( // "fmt" "fmt" "strings" - "github.com/bmeg/grip/gdbi" - "github.com/bmeg/grip/gripql" "github.com/bmeg/grip/log" + "github.com/bmeg/grip/travelerpath" "github.com/bmeg/jsonpath" ) -// Current represents the 'current' traveler namespace -var Current = "__current__" - -// GetNamespace returns the namespace of the provided path -// -// Example: -// GetNamespace("$gene.symbol.ensembl") returns "gene" -func GetNamespace(path string) string { - namespace := "" - parts := strings.Split(path, ".") - if strings.HasPrefix(parts[0], "$") { - namespace = strings.TrimPrefix(parts[0], "$") - } - if namespace == "" { - namespace = Current - } - return namespace -} - -// GetJSONPath strips the namespace from the path and returns the valid -// Json path within the document referenced by the namespace -// -// Example: -// GetJSONPath("gene.symbol.ensembl") returns "$.data.symbol.ensembl" -func GetJSONPath(path string) string { - parts := strings.Split(path, ".") - if strings.HasPrefix(parts[0], "$") { - parts = parts[1:] - } - if len(parts) == 0 { - return "" - } - found := false - for _, v := range gripql.ReservedFields { - if parts[0] == v { - found = true - parts[0] = strings.TrimPrefix(parts[0], "_") - } - } - - if !found { - parts = append([]string{"data"}, parts...) - } - - parts = append([]string{"$"}, parts...) - return strings.Join(parts, ".") -} - // GetDoc returns the document referenced by the provided namespace. // // Example for a traveler containing: @@ -94,12 +45,12 @@ func GetJSONPath(path string) string { // } // } // } -func GetDoc(traveler gdbi.Traveler, namespace string) map[string]interface{} { +func GetDoc(traveler Traveler, namespace string) map[string]interface{} { var tmap map[string]interface{} - if namespace == Current { - tmap = traveler.GetCurrent().ToDict() + if namespace == travelerpath.Current { + tmap = traveler.GetCurrent().Get().ToDict() } else { - tmap = traveler.GetMark(namespace).ToDict() + tmap = traveler.GetMark(namespace).Get().ToDict() } return tmap } @@ -127,9 +78,9 @@ func GetDoc(traveler gdbi.Traveler, namespace string) map[string]interface{} { // } // // TravelerPathLookup(travler, "$gene.symbol.ensembl") returns "ENSG00000012048" -func TravelerPathLookup(traveler gdbi.Traveler, path string) interface{} { - namespace := GetNamespace(path) - field := GetJSONPath(path) +func TravelerPathLookup(traveler Traveler, path string) interface{} { + namespace := travelerpath.GetNamespace(path) + field := travelerpath.GetJSONPath(path) doc := GetDoc(traveler, namespace) if field == "" { fmt.Printf("Null field, return %#v\n", doc) @@ -143,9 +94,9 @@ func TravelerPathLookup(traveler gdbi.Traveler, path string) interface{} { } // TravelerSetValue(travler, "$gene.symbol.ensembl", "hi") inserts the value in the location" -func TravelerSetValue(traveler gdbi.Traveler, path string, val interface{}) error { - namespace := GetNamespace(path) - field := GetJSONPath(path) +func TravelerSetValue(traveler Traveler, path string, val interface{}) error { + namespace := travelerpath.GetNamespace(path) + field := travelerpath.GetJSONPath(path) if field == "" { return nil } @@ -154,9 +105,9 @@ func TravelerSetValue(traveler gdbi.Traveler, path string, val interface{}) erro } // TravelerPathExists returns true if the field exists in the given Traveler -func TravelerPathExists(traveler gdbi.Traveler, path string) bool { - namespace := GetNamespace(path) - field := GetJSONPath(path) +func TravelerPathExists(traveler Traveler, path string) bool { + namespace := travelerpath.GetNamespace(path) + field := travelerpath.GetJSONPath(path) if field == "" { return false } @@ -166,7 +117,7 @@ func TravelerPathExists(traveler gdbi.Traveler, path string) bool { } // RenderTraveler takes a template and fills in the values using the data structure -func RenderTraveler(traveler gdbi.Traveler, template interface{}) interface{} { +func RenderTraveler(traveler Traveler, template interface{}) interface{} { switch elem := template.(type) { case string: return TravelerPathLookup(traveler, elem) @@ -190,7 +141,7 @@ func RenderTraveler(traveler gdbi.Traveler, template interface{}) interface{} { } // SelectTravelerFields returns a new copy of the traveler with only the selected fields -func SelectTravelerFields(t gdbi.Traveler, keys ...string) gdbi.Traveler { +func SelectTravelerFields(t Traveler, keys ...string) Traveler { includePaths := []string{} excludePaths := []string{} KeyLoop: @@ -200,15 +151,15 @@ KeyLoop: exclude = true key = strings.TrimPrefix(key, "-") } - namespace := GetNamespace(key) + namespace := travelerpath.GetNamespace(key) switch namespace { - case Current: + case travelerpath.Current: // noop default: log.Errorf("SelectTravelerFields: only can select field from current traveler") continue KeyLoop } - path := GetJSONPath(key) + path := travelerpath.GetJSONPath(key) path = strings.TrimPrefix(path, "$.") if exclude { @@ -218,19 +169,19 @@ KeyLoop: } } - var out gdbi.Traveler = &gdbi.BaseTraveler{} - out = out.AddCurrent(&gdbi.DataElement{ + var out Traveler = &BaseTraveler{} + out = out.AddCurrent(&DataElement{ Data: map[string]interface{}{}, }) for _, mark := range t.ListMarks() { out = out.AddMark(mark, t.GetMark(mark)) } - var cde *gdbi.DataElement - var ode *gdbi.DataElement + var cde *DataElement + var ode *DataElement - cde = t.GetCurrent() - ode = out.GetCurrent() + cde = t.GetCurrent().Get() + ode = out.GetCurrent().Get() if len(excludePaths) > 0 { cde = excludeFields(cde, excludePaths) @@ -251,7 +202,7 @@ KeyLoop: return out } -func includeFields(new, old *gdbi.DataElement, paths []string) *gdbi.DataElement { +func includeFields(new, old *DataElement, paths []string) *DataElement { newData := make(map[string]interface{}) Include: for _, path := range paths { @@ -297,8 +248,8 @@ Include: return new } -func excludeFields(elem *gdbi.DataElement, paths []string) *gdbi.DataElement { - result := &gdbi.DataElement{ +func excludeFields(elem *DataElement, paths []string) *DataElement { + result := &DataElement{ ID: elem.ID, Label: elem.Label, From: elem.From, diff --git a/jsonpath/jsonpath_test.go b/gdbi/jsonpath_test.go similarity index 71% rename from jsonpath/jsonpath_test.go rename to gdbi/jsonpath_test.go index 0c85da30..a3e05d9a 100644 --- a/jsonpath/jsonpath_test.go +++ b/gdbi/jsonpath_test.go @@ -1,19 +1,19 @@ -package jsonpath +package gdbi import ( "os" "testing" - "github.com/bmeg/grip/gdbi" + "github.com/bmeg/grip/travelerpath" "github.com/stretchr/testify/assert" ) -var traveler gdbi.Traveler +var traveler Traveler func TestMain(m *testing.M) { // test traveler - traveler = &gdbi.BaseTraveler{} - traveler = traveler.AddCurrent(&gdbi.DataElement{ + traveler = &BaseTraveler{} + traveler = traveler.AddCurrent(&DataElement{ ID: "vertex1", Label: "foo", Data: map[string]interface{}{ @@ -28,7 +28,7 @@ func TestMain(m *testing.M) { "f": nil, }, }) - traveler = traveler.AddMark("testMark", &gdbi.DataElement{ + traveler = traveler.AddMark("testMark", &DataElement{ ID: "vertex2", Label: "bar", Data: map[string]interface{}{ @@ -44,46 +44,46 @@ func TestMain(m *testing.M) { func TestGetNamespace(t *testing.T) { expected := "foo" - result := GetNamespace("$foo.bar[1:3].baz") + result := travelerpath.GetNamespace("$foo.bar[1:3].baz") assert.Equal(t, expected, result) - result = GetNamespace("foo.bar[1:3].baz") + result = travelerpath.GetNamespace("foo.bar[1:3].baz") assert.NotEqual(t, expected, result) } func TestGetJSONPath(t *testing.T) { expected := "$.data.a" - result := GetJSONPath("a") + result := travelerpath.GetJSONPath("a") assert.Equal(t, expected, result) expected = "$.data.a" - result = GetJSONPath("_data.a") + result = travelerpath.GetJSONPath("_data.a") assert.Equal(t, expected, result) expected = "$.data.e[1].nested" - result = GetJSONPath("e[1].nested") + result = travelerpath.GetJSONPath("e[1].nested") assert.Equal(t, expected, result) expected = "$.data.a" - result = GetJSONPath("$testMark.a") + result = travelerpath.GetJSONPath("$testMark.a") assert.Equal(t, expected, result) expected = "$.data.a" - result = GetJSONPath("testMark.a") + result = travelerpath.GetJSONPath("testMark.a") assert.NotEqual(t, expected, result) } func TestGetDoc(t *testing.T) { - expected := traveler.GetMark("testMark").ToDict() + expected := traveler.GetMark("testMark").Get().ToDict() result := GetDoc(traveler, "testMark") assert.Equal(t, expected, result) - expected = traveler.GetMark("i-dont-exist").ToDict() + expected = traveler.GetMark("i-dont-exist").Get().ToDict() result = GetDoc(traveler, "i-dont-exist") assert.Equal(t, expected, result) - expected = traveler.GetCurrent().ToDict() - result = GetDoc(traveler, Current) + expected = traveler.GetCurrent().Get().ToDict() + result = GetDoc(traveler, travelerpath.Current) assert.Equal(t, expected, result) } @@ -104,36 +104,36 @@ func TestTravelerPathExists(t *testing.T) { } func TestRender(t *testing.T) { - expected := traveler.GetCurrent().Data["a"] + expected := traveler.GetCurrent().Get().Data["a"] result := RenderTraveler(traveler, "a") assert.Equal(t, expected, result) expected = []interface{}{ - traveler.GetCurrent().Data["a"], - traveler.GetCurrent().Data["b"], - traveler.GetCurrent().Data["c"], - traveler.GetCurrent().Data["d"], + traveler.GetCurrent().Get().Data["a"], + traveler.GetCurrent().Get().Data["b"], + traveler.GetCurrent().Get().Data["c"], + traveler.GetCurrent().Get().Data["d"], } result = RenderTraveler(traveler, []interface{}{"a", "b", "c", "d"}) assert.Equal(t, expected, result) expected = map[string]interface{}{ - "current.gid": traveler.GetCurrent().ID, - "current.label": traveler.GetCurrent().Label, - "current.a": traveler.GetCurrent().Data["a"], - "current.b": traveler.GetCurrent().Data["b"], - "current.c": traveler.GetCurrent().Data["c"], - "current.d": traveler.GetCurrent().Data["d"], - "mark.gid": traveler.GetMark("testMark").ID, - "mark.label": traveler.GetMark("testMark").Label, - "mark.a": traveler.GetMark("testMark").Data["a"], - "mark.b": traveler.GetMark("testMark").Data["b"], - "mark.c": traveler.GetMark("testMark").Data["c"], - "mark.d": traveler.GetMark("testMark").Data["d"], + "current.gid": traveler.GetCurrent().Get().ID, + "current.label": traveler.GetCurrent().Get().Label, + "current.a": traveler.GetCurrent().Get().Data["a"], + "current.b": traveler.GetCurrent().Get().Data["b"], + "current.c": traveler.GetCurrent().Get().Data["c"], + "current.d": traveler.GetCurrent().Get().Data["d"], + "mark.gid": traveler.GetMark("testMark").Get().ID, + "mark.label": traveler.GetMark("testMark").Get().Label, + "mark.a": traveler.GetMark("testMark").Get().Data["a"], + "mark.b": traveler.GetMark("testMark").Get().Data["b"], + "mark.c": traveler.GetMark("testMark").Get().Data["c"], + "mark.d": traveler.GetMark("testMark").Get().Data["d"], "mark.d[0]": 4, "current.e[0].nested": "field1", "current.e.nested": []interface{}{"field1", "field2"}, - "current.f": traveler.GetCurrent().Data["f"], + "current.f": traveler.GetCurrent().Get().Data["f"], } result = RenderTraveler(traveler, map[string]interface{}{ "current.gid": "_gid", @@ -157,7 +157,7 @@ func TestRender(t *testing.T) { } func TestIncludeFields(t *testing.T) { - orig := &gdbi.DataElement{ + orig := &DataElement{ ID: "vertex1", Label: "foo", Data: map[string]interface{}{ @@ -170,13 +170,13 @@ func TestIncludeFields(t *testing.T) { "f": nil, }, } - new := &gdbi.DataElement{ + new := &DataElement{ ID: "vertex1", Label: "foo", Data: map[string]interface{}{}, } - expected := &gdbi.DataElement{ + expected := &DataElement{ ID: "vertex1", Label: "foo", Data: map[string]interface{}{ @@ -192,7 +192,7 @@ func TestIncludeFields(t *testing.T) { } func TestExcludeFields(t *testing.T) { - orig := &gdbi.DataElement{ + orig := &DataElement{ ID: "vertex1", Label: "foo", Data: map[string]interface{}{ @@ -205,7 +205,7 @@ func TestExcludeFields(t *testing.T) { "f": nil, }, } - expected := &gdbi.DataElement{ + expected := &DataElement{ ID: "vertex1", Label: "foo", Data: map[string]interface{}{ @@ -222,8 +222,8 @@ func TestExcludeFields(t *testing.T) { } func TestSelectFields(t *testing.T) { - expected := (&gdbi.BaseTraveler{}).AddMark("testMark", traveler.GetMark("testMark")) - expected = expected.AddCurrent(&gdbi.DataElement{ + expected := (&BaseTraveler{}).AddMark("testMark", traveler.GetMark("testMark")) + expected = expected.AddCurrent(&DataElement{ ID: "vertex1", Label: "foo", Data: map[string]interface{}{ @@ -239,7 +239,7 @@ func TestSelectFields(t *testing.T) { result := SelectTravelerFields(traveler, "-a", "-_data.d") assert.Equal(t, expected, result) - expected = expected.AddCurrent(&gdbi.DataElement{ + expected = expected.AddCurrent(&DataElement{ ID: "vertex1", Label: "foo", Data: map[string]interface{}{}, @@ -247,7 +247,7 @@ func TestSelectFields(t *testing.T) { result = SelectTravelerFields(traveler) assert.Equal(t, expected, result) - expected = expected.AddCurrent(&gdbi.DataElement{ + expected = expected.AddCurrent(&DataElement{ ID: "vertex1", Label: "foo", Data: map[string]interface{}{ @@ -264,7 +264,7 @@ func TestSelectFields(t *testing.T) { result = SelectTravelerFields(traveler, "_gid", "_label", "a", "_data.b", "$testMark.b", "$testMark._data.d") assert.Equal(t, expected, result) - expected = expected.AddCurrent(&gdbi.DataElement{ + expected = expected.AddCurrent(&DataElement{ ID: "vertex1", Label: "foo", Data: map[string]interface{}{ diff --git a/gdbi/pipeline.go b/gdbi/pipeline.go index c5d2569e..6ca0c7f7 100644 --- a/gdbi/pipeline.go +++ b/gdbi/pipeline.go @@ -39,3 +39,42 @@ type Pipeline interface { DataType() DataType MarkTypes() map[string]DataType } + +type StatementCompiler interface { + V(gs *gripql.GraphStatement_V, ps *State) (Processor, error) + E(gs *gripql.GraphStatement_E, ps *State) (Processor, error) + In(gs *gripql.GraphStatement_In, ps *State) (Processor, error) + Out(gs *gripql.GraphStatement_Out, ps *State) (Processor, error) + InNull(gs *gripql.GraphStatement_InNull, ps *State) (Processor, error) + OutNull(gs *gripql.GraphStatement_OutNull, ps *State) (Processor, error) + Both(gs *gripql.GraphStatement_Both, ps *State) (Processor, error) + InE(gs *gripql.GraphStatement_InE, ps *State) (Processor, error) + InENull(gs *gripql.GraphStatement_InENull, ps *State) (Processor, error) + OutE(gs *gripql.GraphStatement_OutE, ps *State) (Processor, error) + OutENull(gs *gripql.GraphStatement_OutENull, ps *State) (Processor, error) + BothE(gs *gripql.GraphStatement_BothE, ps *State) (Processor, error) + Has(gs *gripql.GraphStatement_Has, ps *State) (Processor, error) + HasLabel(gs *gripql.GraphStatement_HasLabel, ps *State) (Processor, error) + HasKey(gs *gripql.GraphStatement_HasKey, ps *State) (Processor, error) + HasID(gs *gripql.GraphStatement_HasId, ps *State) (Processor, error) + + Limit(gs *gripql.GraphStatement_Limit, ps *State) (Processor, error) + Skip(gs *gripql.GraphStatement_Skip, ps *State) (Processor, error) + Range(gs *gripql.GraphStatement_Range, ps *State) (Processor, error) + Count(gs *gripql.GraphStatement_Count, ps *State) (Processor, error) + Distinct(gs *gripql.GraphStatement_Distinct, ps *State) (Processor, error) + As(gs *gripql.GraphStatement_As, ps *State) (Processor, error) + Set(gs *gripql.GraphStatement_Set, ps *State) (Processor, error) + Increment(gs *gripql.GraphStatement_Increment, ps *State) (Processor, error) + Mark(gs *gripql.GraphStatement_Mark, ps *State) (Processor, error) + Jump(gs *gripql.GraphStatement_Jump, ps *State) (Processor, error) + Select(gs *gripql.GraphStatement_Select, ps *State) (Processor, error) + + Render(gs *gripql.GraphStatement_Render, ps *State) (Processor, error) + Path(gs *gripql.GraphStatement_Path, ps *State) (Processor, error) + Unwind(gs *gripql.GraphStatement_Unwind, ps *State) (Processor, error) + Fields(gs *gripql.GraphStatement_Fields, ps *State) (Processor, error) + Aggregate(gs *gripql.GraphStatement_Aggregate, ps *State) (Processor, error) + + Custom(gs *gripql.GraphStatement, ps *State) (Processor, error) +} diff --git a/gdbi/queue.go b/gdbi/queue.go new file mode 100644 index 00000000..0c213691 --- /dev/null +++ b/gdbi/queue.go @@ -0,0 +1,72 @@ +package gdbi + +import ( + "fmt" + "sync" +) + +type MemQueue struct { + input chan Traveler + output chan Traveler +} + +type Queue interface { + GetInput() chan Traveler + GetOutput() chan Traveler +} + +func NewQueue() Queue { + o := MemQueue{ + input: make(chan Traveler, 50), + output: make(chan Traveler, 50), + } + queue := make([]Traveler, 0, 1000) + closed := false + m := &sync.Mutex{} + inCount := 0 + outCount := 0 + go func() { + for i := range o.input { + m.Lock() + inCount++ + if i.IsSignal() { + //fmt.Printf("Queue got signal %d\n", i.Signal.ID) + } + //fmt.Printf("Queue Size: %d %d / %d\n", len(queue), inCount, outCount) + queue = append(queue, i) + m.Unlock() + } + closed = true + }() + go func() { + defer close(o.output) + for running := true; running; { + var v Traveler + m.Lock() + if len(queue) > 0 { + v = queue[0] + queue = queue[1:] + } else { + if closed { + running = false + } + } + m.Unlock() + if v != nil { + o.output <- v + outCount++ + } + } + fmt.Printf("Closing Queue Size: %d %d / %d\n", len(queue), inCount, outCount) + fmt.Printf("Closing Buffered Queue\n") + }() + return &o +} + +func (q *MemQueue) GetInput() chan Traveler { + return q.input +} + +func (q *MemQueue) GetOutput() chan Traveler { + return q.output +} diff --git a/engine/pipeline/state.go b/gdbi/state.go similarity index 67% rename from engine/pipeline/state.go rename to gdbi/state.go index 33ef0a96..e485595e 100644 --- a/engine/pipeline/state.go +++ b/gdbi/state.go @@ -1,14 +1,14 @@ -package pipeline +package gdbi import ( - "github.com/bmeg/grip/engine/inspect" - "github.com/bmeg/grip/gdbi" + //"github.com/bmeg/grip/engine/inspect" "github.com/bmeg/grip/gripql" + "github.com/bmeg/grip/gripql/inspect" ) type State struct { - LastType gdbi.DataType - MarkTypes map[string]gdbi.DataType + LastType DataType + MarkTypes map[string]DataType Steps []string StepOutputs map[string][]string CurStep string @@ -28,11 +28,11 @@ func (ps *State) StepLoadData() bool { return false } -func (ps *State) GetLastType() gdbi.DataType { +func (ps *State) GetLastType() DataType { return ps.LastType } -func (ps *State) SetLastType(a gdbi.DataType) { +func (ps *State) SetLastType(a DataType) { ps.LastType = a } @@ -41,8 +41,8 @@ func NewPipelineState(stmts []*gripql.GraphStatement) *State { stepOut := inspect.PipelineStepOutputs(stmts) return &State{ - LastType: gdbi.NoData, - MarkTypes: map[string]gdbi.DataType{}, + LastType: NoData, + MarkTypes: map[string]DataType{}, Steps: steps, StepOutputs: stepOut, } diff --git a/gdbi/statement_processor.go b/gdbi/statement_processor.go new file mode 100644 index 00000000..10ce411c --- /dev/null +++ b/gdbi/statement_processor.go @@ -0,0 +1,237 @@ +package gdbi + +import ( + "fmt" + + "github.com/bmeg/grip/gripql" + "github.com/bmeg/grip/travelerpath" +) + +func StatementProcessor( + sc StatementCompiler, + gs *gripql.GraphStatement, + db GraphInterface, + ps *State) (Processor, error) { + + switch stmt := gs.GetStatement().(type) { + + case *gripql.GraphStatement_V: + if ps.LastType != NoData { + return nil, fmt.Errorf(`"V" statement is only valid at the beginning of the traversal`) + } + o, err := sc.V(stmt, ps) + ps.LastType = VertexData + return o, err + + case *gripql.GraphStatement_E: + if ps.LastType != NoData { + return nil, fmt.Errorf(`"E" statement is only valid at the beginning of the traversal`) + } + o, err := sc.E(stmt, ps) + ps.LastType = EdgeData + return o, err + + case *gripql.GraphStatement_In: + if ps.LastType != VertexData && ps.LastType != EdgeData { + return nil, fmt.Errorf(`"in" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } + o, err := sc.In(stmt, ps) + ps.LastType = VertexData + return o, err + + case *gripql.GraphStatement_InNull: + if ps.LastType != VertexData && ps.LastType != EdgeData { + return nil, fmt.Errorf(`"in" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } + o, err := sc.InNull(stmt, ps) + ps.LastType = VertexData + return o, err + + case *gripql.GraphStatement_Out: + if ps.LastType != VertexData && ps.LastType != EdgeData { + return nil, fmt.Errorf(`"out" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } + o, err := sc.Out(stmt, ps) + ps.LastType = VertexData + return o, err + + case *gripql.GraphStatement_OutNull: + if ps.LastType != VertexData && ps.LastType != EdgeData { + return nil, fmt.Errorf(`"out" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } + o, err := sc.OutNull(stmt, ps) + ps.LastType = VertexData + return o, err + + case *gripql.GraphStatement_Both: + if ps.LastType != VertexData && ps.LastType != EdgeData { + return nil, fmt.Errorf(`"both" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } + o, err := sc.Both(stmt, ps) + ps.LastType = VertexData + return o, err + + case *gripql.GraphStatement_InE: + if ps.LastType != VertexData { + return nil, fmt.Errorf(`"inEdge" statement is only valid for the vertex type not: %s`, ps.LastType.String()) + } + o, err := sc.InE(stmt, ps) + ps.LastType = EdgeData + return o, err + + case *gripql.GraphStatement_InENull: + if ps.LastType != VertexData { + return nil, fmt.Errorf(`"inEdge" statement is only valid for the vertex type not: %s`, ps.LastType.String()) + } + o, err := sc.InENull(stmt, ps) + ps.LastType = EdgeData + return o, err + + case *gripql.GraphStatement_OutE: + if ps.LastType != VertexData { + return nil, fmt.Errorf(`"outEdgeNull" statement is only valid for the vertex type not: %s`, ps.LastType.String()) + } + o, err := sc.OutE(stmt, ps) + ps.LastType = EdgeData + return o, err + + case *gripql.GraphStatement_OutENull: + if ps.LastType != VertexData { + return nil, fmt.Errorf(`"outEdgeNull" statement is only valid for the vertex type not: %s`, ps.LastType.String()) + } + o, err := sc.OutENull(stmt, ps) + ps.LastType = EdgeData + return o, err + + case *gripql.GraphStatement_BothE: + if ps.LastType != VertexData { + return nil, fmt.Errorf(`"bothEdge" statement is only valid for the vertex type not: %s`, ps.LastType.String()) + } + o, err := sc.BothE(stmt, ps) + ps.LastType = EdgeData + return o, err + + case *gripql.GraphStatement_Has: + if ps.LastType != VertexData && ps.LastType != EdgeData { + return nil, fmt.Errorf(`"Has" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } + o, err := sc.Has(stmt, ps) + return o, err + + case *gripql.GraphStatement_HasLabel: + if ps.LastType != VertexData && ps.LastType != EdgeData { + return nil, fmt.Errorf(`"HasLabel" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } + o, err := sc.HasLabel(stmt, ps) + return o, err + + case *gripql.GraphStatement_HasKey: + if ps.LastType != VertexData && ps.LastType != EdgeData { + return nil, fmt.Errorf(`"HasKey" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } + o, err := sc.HasKey(stmt, ps) + return o, err + + case *gripql.GraphStatement_HasId: + if ps.LastType != VertexData && ps.LastType != EdgeData { + return nil, fmt.Errorf(`"HasId" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } + o, err := sc.HasID(stmt, ps) + ps.LastType = EdgeData + return o, err + + case *gripql.GraphStatement_Limit: + return sc.Limit(stmt, ps) + + case *gripql.GraphStatement_Skip: + return sc.Skip(stmt, ps) + + case *gripql.GraphStatement_Range: + return sc.Range(stmt, ps) + + case *gripql.GraphStatement_Count: + o, err := sc.Count(stmt, ps) + ps.LastType = CountData + return o, err + + case *gripql.GraphStatement_Distinct: + if ps.LastType != VertexData && ps.LastType != EdgeData { + return nil, fmt.Errorf(`"distinct" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } + o, err := sc.Distinct(stmt, ps) + return o, err + + case *gripql.GraphStatement_As: + if ps.LastType == NoData { + return nil, fmt.Errorf(`"mark" statement is not valid at the beginning of a traversal`) + } + if stmt.As == "" { + return nil, fmt.Errorf(`"mark" statement cannot have an empty name`) + } + if err := gripql.ValidateFieldName(stmt.As); err != nil { + return nil, fmt.Errorf(`"mark" statement invalid; %v`, err) + } + if stmt.As == travelerpath.Current { + return nil, fmt.Errorf(`"mark" statement invalid; uses reserved name %s`, travelerpath.Current) + } + ps.MarkTypes[stmt.As] = ps.LastType + return sc.As(stmt, ps) + + case *gripql.GraphStatement_Set: + return sc.Set(stmt, ps) + + case *gripql.GraphStatement_Increment: + return sc.Increment(stmt, ps) + + case *gripql.GraphStatement_Mark: + return sc.Mark(stmt, ps) + + case *gripql.GraphStatement_Jump: + return sc.Jump(stmt, ps) + + case *gripql.GraphStatement_Select: + if ps.LastType != VertexData && ps.LastType != EdgeData { + return nil, fmt.Errorf(`"select" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } + out, err := sc.Select(stmt, ps) + ps.LastType = ps.MarkTypes[stmt.Select.Marks[0]] + return out, err + + case *gripql.GraphStatement_Render: + if ps.LastType != VertexData && ps.LastType != EdgeData { + return nil, fmt.Errorf(`"render" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } + out, err := sc.Render(stmt, ps) + ps.LastType = RenderData + return out, err + + case *gripql.GraphStatement_Path: + if ps.LastType != VertexData && ps.LastType != EdgeData { + return nil, fmt.Errorf(`"path" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } + out, err := sc.Path(stmt, ps) + ps.LastType = PathData + return out, err + + case *gripql.GraphStatement_Unwind: + return sc.Unwind(stmt, ps) + + case *gripql.GraphStatement_Fields: + if ps.LastType != VertexData && ps.LastType != EdgeData { + return nil, fmt.Errorf(`"fields" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } + return sc.Fields(stmt, ps) + + case *gripql.GraphStatement_Aggregate: + if ps.LastType != VertexData && ps.LastType != EdgeData { + return nil, fmt.Errorf(`"aggregate" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } + out, err := sc.Aggregate(stmt, ps) + ps.LastType = AggregationData + return out, err + + default: + + return sc.Custom(gs, ps) + } +} diff --git a/gdbi/traveler.go b/gdbi/traveler.go index 9053bc5a..e778292e 100644 --- a/gdbi/traveler.go +++ b/gdbi/traveler.go @@ -26,9 +26,9 @@ const ( ) // AddCurrent creates a new copy of the travel with new 'current' value -func (t *BaseTraveler) AddCurrent(r *DataElement) Traveler { +func (t *BaseTraveler) AddCurrent(r DataRef) Traveler { o := BaseTraveler{ - Marks: map[string]*DataElement{}, + Marks: map[string]DataRef{}, Path: make([]DataElementID, len(t.Path)+1), Signal: t.Signal, } @@ -38,12 +38,13 @@ func (t *BaseTraveler) AddCurrent(r *DataElement) Traveler { for i := range t.Path { o.Path[i] = t.Path[i] } - if r == nil { + rd := r.Get() + if rd == nil { o.Path[len(t.Path)] = DataElementID{} - } else if r.To != "" { - o.Path[len(t.Path)] = DataElementID{Edge: r.ID} + } else if rd.To != "" { + o.Path[len(t.Path)] = DataElementID{Edge: rd.ID} } else { - o.Path[len(t.Path)] = DataElementID{Vertex: r.ID} + o.Path[len(t.Path)] = DataElementID{Vertex: rd.ID} } o.Current = r return &o @@ -52,17 +53,18 @@ func (t *BaseTraveler) AddCurrent(r *DataElement) Traveler { // AddCurrent creates a new copy of the travel with new 'current' value func (t *BaseTraveler) Copy() Traveler { o := BaseTraveler{ - Marks: map[string]*DataElement{}, + Marks: map[string]DataRef{}, Path: make([]DataElementID, len(t.Path)), Signal: t.Signal, } for k, v := range t.Marks { + vg := v.Get() o.Marks[k] = &DataElement{ - ID: v.ID, - Label: v.Label, - From: v.From, To: v.To, - Data: copy.DeepCopy(v.Data).(map[string]interface{}), - Loaded: v.Loaded, + ID: vg.ID, + Label: vg.Label, + From: vg.From, To: vg.To, + Data: copy.DeepCopy(vg.Data).(map[string]interface{}), + Loaded: vg.Loaded, } } for i := range t.Path { @@ -103,8 +105,8 @@ func (t *BaseTraveler) ListMarks() []string { } // AddMark adds a result to travels state map using `label` as the name -func (t *BaseTraveler) AddMark(label string, r *DataElement) Traveler { - o := BaseTraveler{Marks: map[string]*DataElement{}, Path: make([]DataElementID, len(t.Path))} +func (t *BaseTraveler) AddMark(label string, r DataRef) Traveler { + o := BaseTraveler{Marks: map[string]DataRef{}, Path: make([]DataElementID, len(t.Path))} for k, v := range t.Marks { o.Marks[k] = v } @@ -117,24 +119,24 @@ func (t *BaseTraveler) AddMark(label string, r *DataElement) Traveler { } // GetMark gets stored result in travels state using its label -func (t *BaseTraveler) GetMark(label string) *DataElement { +func (t *BaseTraveler) GetMark(label string) DataRef { return t.Marks[label] } // GetCurrent get current result value attached to the traveler -func (t *BaseTraveler) GetCurrent() *DataElement { +func (t *BaseTraveler) GetCurrent() DataRef { return t.Current } func (t *BaseTraveler) GetCurrentID() string { - return t.Current.ID + return t.Current.Get().ID } func (t *BaseTraveler) GetCount() uint32 { return t.Count } -func (t *BaseTraveler) GetSelections() map[string]*DataElement { +func (t *BaseTraveler) GetSelections() map[string]DataRef { return t.Selections } diff --git a/grids/new.go b/grids/new.go index 2d97a7b9..eeaf5e66 100644 --- a/grids/new.go +++ b/grids/new.go @@ -2,104 +2,11 @@ package grids import ( "fmt" - "os" - "path/filepath" - "github.com/cockroachdb/pebble" - - "github.com/akrylysov/pogreb" - "github.com/bmeg/grip/gripql" - "github.com/bmeg/grip/kvi" - "github.com/bmeg/grip/kvi/pebbledb" - "github.com/bmeg/grip/kvindex" - "github.com/bmeg/grip/log" - "github.com/bmeg/grip/timestamp" + "github.com/bmeg/grip/gdbi" ) -// Graph implements the GDB interface using a genertic key/value storage driver -type Graph struct { - graphID string - graphKey uint64 - - keyMap *KeyMap - keykv pogreb.DB - - graphkv kvi.KVInterface // *pebble.DB - indexkv kvi.KVInterface // *pebble.DB - idx *kvindex.KVIndex - ts *timestamp.Timestamp -} - -// Close the connection -func (g *Graph) Close() error { - g.keyMap.Close() - g.graphkv.Close() - g.indexkv.Close() - return nil -} - -// AddGraph creates a new graph named `graph` -func (kgraph *GDB) AddGraph(graph string) error { - err := gripql.ValidateGraphName(graph) - if err != nil { - return err - } - g, err := newGraph(kgraph.basePath, graph) - if err != nil { - return err - } - kgraph.drivers[graph] = g - return nil -} - -func newGraph(baseDir, name string) (*Graph, error) { - dbPath := filepath.Join(baseDir, name) - - log.Infof("Creating new GRIDS graph %s", name) - - _, err := os.Stat(dbPath) - if os.IsNotExist(err) { - os.Mkdir(dbPath, 0700) - } - keykvPath := fmt.Sprintf("%s/keymap", dbPath) - graphkvPath := fmt.Sprintf("%s/graph", dbPath) - indexkvPath := fmt.Sprintf("%s/index", dbPath) - keykv, err := pogreb.Open(keykvPath, nil) - if err != nil { - return nil, err - } - graphkv, err := pebble.Open(graphkvPath, &pebble.Options{}) - if err != nil { - return nil, err - } - indexkv, err := pebble.Open(indexkvPath, &pebble.Options{}) - if err != nil { - return nil, err - } - ts := timestamp.NewTimestamp() - - o := &Graph{ - keyMap: NewKeyMap(keykv), - graphkv: pebbledb.WrapPebble(graphkv), - indexkv: pebbledb.WrapPebble(indexkv), - ts: &ts, - idx: kvindex.NewIndex(pebbledb.WrapPebble(indexkv)), - } - - return o, nil -} - -// DeleteGraph deletes `graph` -func (kgraph *GDB) DeleteGraph(graph string) error { - err := gripql.ValidateGraphName(graph) - if err != nil { - return nil - } - if d, ok := kgraph.drivers[graph]; ok { - d.Close() - delete(kgraph.drivers, graph) - } - dbPath := filepath.Join(kgraph.basePath, graph) - os.RemoveAll(dbPath) - return nil +// NewKVGraphDB intitalize a new grids graph driver +func NewGraphDB(baseDir string) (gdbi.GraphDB, error) { + return nil, fmt.Errorf("Not implemented") } diff --git a/grids/compiler.go b/grids/old/compiler.go similarity index 96% rename from grids/compiler.go rename to grids/old/compiler.go index b19e98f1..b6ad1f72 100644 --- a/grids/compiler.go +++ b/grids/old/compiler.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/bmeg/grip/engine/core" - "github.com/bmeg/grip/engine/pipeline" "github.com/bmeg/grip/gdbi" "github.com/bmeg/grip/gripql" "github.com/bmeg/grip/util/protoutil" @@ -45,7 +44,7 @@ func (comp Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.CompileO stmts = core.IndexStartOptimize(stmts) - ps := pipeline.NewPipelineState(stmts) + ps := gdbi.NewPipelineState(stmts) if opts != nil { ps.LastType = opts.PipelineExtension ps.MarkTypes = opts.ExtensionMarkTypes @@ -63,7 +62,7 @@ func (comp Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.CompileO if p, err := GetRawProcessor(comp.graph, ps, gs); err == nil && optimizeOn { procs = append(procs, p) } else { - p, err := core.StatementProcessor(gs, comp.graph, ps) + p, err := gdbi.StatementProcessor(gs, comp.graph, ps) if err != nil { fmt.Printf("Error %s at %d %#v", err, i, gs) return &core.DefaultPipeline{}, err diff --git a/grids/old/config.go b/grids/old/config.go new file mode 100644 index 00000000..8cddba33 --- /dev/null +++ b/grids/old/config.go @@ -0,0 +1,5 @@ +package grids + +type Config struct { + Path string `json:"path"` +} diff --git a/grids/graph.go b/grids/old/graph.go similarity index 100% rename from grids/graph.go rename to grids/old/graph.go diff --git a/grids/old/graph_lite.go b/grids/old/graph_lite.go new file mode 100644 index 00000000..6f7f7b1f --- /dev/null +++ b/grids/old/graph_lite.go @@ -0,0 +1 @@ +package grids diff --git a/grids/graphdb.go b/grids/old/graphdb.go similarity index 100% rename from grids/graphdb.go rename to grids/old/graphdb.go diff --git a/grids/index.go b/grids/old/index.go similarity index 89% rename from grids/index.go rename to grids/old/index.go index bb59724a..f802e6a7 100644 --- a/grids/index.go +++ b/grids/old/index.go @@ -7,8 +7,8 @@ import ( "github.com/bmeg/grip/gdbi" "github.com/bmeg/grip/gripql" - "github.com/bmeg/grip/jsonpath" "github.com/bmeg/grip/log" + "github.com/bmeg/grip/travelerpath" ) func (kgraph *Graph) setupGraphIndex(graph string) error { @@ -38,7 +38,7 @@ func (kgraph *Graph) deleteGraphIndex(graph string) error { } func normalizePath(path string) string { - path = jsonpath.GetJSONPath(path) + path = travelerpath.GetJSONPath(path) path = strings.TrimPrefix(path, "$.") path = strings.TrimPrefix(path, "data.") return path @@ -64,7 +64,7 @@ func edgeIdxStruct(e *gdbi.Edge) map[string]interface{} { return k } -//AddVertexIndex add index to vertices +// AddVertexIndex add index to vertices func (ggraph *Graph) AddVertexIndex(label string, field string) error { log.WithFields(log.Fields{"label": label, "field": field}).Info("Adding vertex index") field = normalizePath(field) @@ -72,14 +72,14 @@ func (ggraph *Graph) AddVertexIndex(label string, field string) error { return ggraph.idx.AddField(fmt.Sprintf("%s.v.%s.%s", ggraph.graphID, label, field)) } -//DeleteVertexIndex delete index from vertices +// DeleteVertexIndex delete index from vertices func (ggraph *Graph) DeleteVertexIndex(label string, field string) error { log.WithFields(log.Fields{"label": label, "field": field}).Info("Deleting vertex index") field = normalizePath(field) return ggraph.idx.RemoveField(fmt.Sprintf("%s.v.%s.%s", ggraph.graphID, label, field)) } -//GetVertexIndexList lists out all the vertex indices for a graph +// GetVertexIndexList lists out all the vertex indices for a graph func (ggraph *Graph) GetVertexIndexList() <-chan *gripql.IndexID { log.Debug("Running GetVertexIndexList") out := make(chan *gripql.IndexID) @@ -96,8 +96,8 @@ func (ggraph *Graph) GetVertexIndexList() <-chan *gripql.IndexID { return out } -//VertexLabelScan produces a channel of all vertex ids in a graph -//that match a given label +// VertexLabelScan produces a channel of all vertex ids in a graph +// that match a given label func (ggraph *Graph) VertexLabelScan(ctx context.Context, label string) chan string { log.WithFields(log.Fields{"label": label}).Debug("Running VertexLabelScan") //TODO: Make this work better diff --git a/grids/keymap.go b/grids/old/keymap.go similarity index 100% rename from grids/keymap.go rename to grids/old/keymap.go diff --git a/grids/keys.go b/grids/old/keys.go similarity index 100% rename from grids/keys.go rename to grids/old/keys.go diff --git a/grids/old/new.go b/grids/old/new.go new file mode 100644 index 00000000..2d97a7b9 --- /dev/null +++ b/grids/old/new.go @@ -0,0 +1,105 @@ +package grids + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/cockroachdb/pebble" + + "github.com/akrylysov/pogreb" + "github.com/bmeg/grip/gripql" + "github.com/bmeg/grip/kvi" + "github.com/bmeg/grip/kvi/pebbledb" + "github.com/bmeg/grip/kvindex" + "github.com/bmeg/grip/log" + "github.com/bmeg/grip/timestamp" +) + +// Graph implements the GDB interface using a genertic key/value storage driver +type Graph struct { + graphID string + graphKey uint64 + + keyMap *KeyMap + keykv pogreb.DB + + graphkv kvi.KVInterface // *pebble.DB + indexkv kvi.KVInterface // *pebble.DB + idx *kvindex.KVIndex + ts *timestamp.Timestamp +} + +// Close the connection +func (g *Graph) Close() error { + g.keyMap.Close() + g.graphkv.Close() + g.indexkv.Close() + return nil +} + +// AddGraph creates a new graph named `graph` +func (kgraph *GDB) AddGraph(graph string) error { + err := gripql.ValidateGraphName(graph) + if err != nil { + return err + } + g, err := newGraph(kgraph.basePath, graph) + if err != nil { + return err + } + kgraph.drivers[graph] = g + return nil +} + +func newGraph(baseDir, name string) (*Graph, error) { + dbPath := filepath.Join(baseDir, name) + + log.Infof("Creating new GRIDS graph %s", name) + + _, err := os.Stat(dbPath) + if os.IsNotExist(err) { + os.Mkdir(dbPath, 0700) + } + keykvPath := fmt.Sprintf("%s/keymap", dbPath) + graphkvPath := fmt.Sprintf("%s/graph", dbPath) + indexkvPath := fmt.Sprintf("%s/index", dbPath) + keykv, err := pogreb.Open(keykvPath, nil) + if err != nil { + return nil, err + } + graphkv, err := pebble.Open(graphkvPath, &pebble.Options{}) + if err != nil { + return nil, err + } + indexkv, err := pebble.Open(indexkvPath, &pebble.Options{}) + if err != nil { + return nil, err + } + ts := timestamp.NewTimestamp() + + o := &Graph{ + keyMap: NewKeyMap(keykv), + graphkv: pebbledb.WrapPebble(graphkv), + indexkv: pebbledb.WrapPebble(indexkv), + ts: &ts, + idx: kvindex.NewIndex(pebbledb.WrapPebble(indexkv)), + } + + return o, nil +} + +// DeleteGraph deletes `graph` +func (kgraph *GDB) DeleteGraph(graph string) error { + err := gripql.ValidateGraphName(graph) + if err != nil { + return nil + } + if d, ok := kgraph.drivers[graph]; ok { + d.Close() + delete(kgraph.drivers, graph) + } + dbPath := filepath.Join(kgraph.basePath, graph) + os.RemoveAll(dbPath) + return nil +} diff --git a/grids/raw_graph.go b/grids/old/raw_graph.go similarity index 100% rename from grids/raw_graph.go rename to grids/old/raw_graph.go diff --git a/grids/raw_processors.go b/grids/old/raw_processors.go similarity index 100% rename from grids/raw_processors.go rename to grids/old/raw_processors.go diff --git a/grids/schema.go b/grids/old/schema.go similarity index 100% rename from grids/schema.go rename to grids/old/schema.go diff --git a/grids/old/statement_compiler.go b/grids/old/statement_compiler.go new file mode 100644 index 00000000..189f8fef --- /dev/null +++ b/grids/old/statement_compiler.go @@ -0,0 +1,250 @@ +package grids + +import ( + "fmt" + + "github.com/bmeg/grip/engine/logic" + "github.com/bmeg/grip/gdbi" + "github.com/bmeg/grip/gripql" + "github.com/bmeg/grip/travelerpath" + "github.com/bmeg/grip/util/protoutil" +) + +type GridStmtCompiler struct { + db Graph +} + +func (sc *GridStmtCompiler) V(stmt *gripql.GraphStatement_V, ps *gdbi.State) (gdbi.Processor, error) { + ids := protoutil.AsStringList(stmt.V) + return &LookupVerts{db: sc.db, ids: ids, loadData: ps.StepLoadData()}, nil +} + +func (sc *GridStmtCompiler) E(stmt *gripql.GraphStatement_E, ps *gdbi.State) (gdbi.Processor, error) { + ids := protoutil.AsStringList(stmt.E) + return &LookupEdges{db: sc.db, ids: ids, loadData: ps.StepLoadData()}, nil +} + +func (sc *GridStmtCompiler) In(stmt *gripql.GraphStatement_In, ps *gdbi.State) (gdbi.Processor, error) { + labels := protoutil.AsStringList(stmt.In) + if ps.LastType == gdbi.VertexData { + return &LookupVertexAdjIn{db: sc.db, labels: labels, loadData: ps.StepLoadData()}, nil + } else if ps.LastType == gdbi.EdgeData { + return &LookupEdgeAdjIn{db: sc.db, labels: labels, loadData: ps.StepLoadData()}, nil + } else { + return nil, fmt.Errorf(`"in" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } +} + +func (sc *GridStmtCompiler) InNull(stmt *gripql.GraphStatement_InNull, ps *gdbi.State) (gdbi.Processor, error) { + labels := protoutil.AsStringList(stmt.InNull) + if ps.LastType == gdbi.VertexData { + return &LookupVertexAdjIn{db: sc.db, labels: labels, loadData: ps.StepLoadData(), emitNull: true}, nil + } else if ps.LastType == gdbi.EdgeData { + return &LookupEdgeAdjIn{db: sc.db, labels: labels, loadData: ps.StepLoadData()}, nil + } else { + return nil, fmt.Errorf(`"in" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } +} +func (sc *GridStmtCompiler) Out(stmt *gripql.GraphStatement_Out, ps *gdbi.State) (gdbi.Processor, error) { + labels := protoutil.AsStringList(stmt.Out) + if ps.LastType == gdbi.VertexData { + return &LookupVertexAdjOut{db: sc.db, labels: labels, loadData: ps.StepLoadData()}, nil + } else if ps.LastType == gdbi.EdgeData { + return &LookupEdgeAdjOut{db: sc.db, labels: labels, loadData: ps.StepLoadData()}, nil + } else { + return nil, fmt.Errorf(`"out" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } +} + +func (sc *GridStmtCompiler) OutNull(stmt *gripql.GraphStatement_OutNull, ps *gdbi.State) (gdbi.Processor, error) { + labels := protoutil.AsStringList(stmt.OutNull) + if ps.LastType == gdbi.VertexData { + return &LookupVertexAdjOut{db: sc.db, labels: labels, loadData: ps.StepLoadData(), emitNull: true}, nil + } else if ps.LastType == gdbi.EdgeData { + return &LookupEdgeAdjOut{db: sc.db, labels: labels, loadData: ps.StepLoadData()}, nil + } else { + return nil, fmt.Errorf(`"out" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } +} + +func (sc *GridStmtCompiler) Both(stmt *gripql.GraphStatement_Both, ps *gdbi.State) (gdbi.Processor, error) { + labels := protoutil.AsStringList(stmt.Both) + if ps.LastType == gdbi.VertexData { + return &both{db: sc.db, labels: labels, lastType: gdbi.VertexData, toType: gdbi.VertexData, loadData: ps.StepLoadData()}, nil + } else if ps.LastType == gdbi.EdgeData { + return &both{db: sc.db, labels: labels, lastType: gdbi.EdgeData, toType: gdbi.VertexData, loadData: ps.StepLoadData()}, nil + } else { + return nil, fmt.Errorf(`"both" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) + } +} + +func (sc *GridStmtCompiler) InE(stmt *gripql.GraphStatement_InE, ps *gdbi.State) (gdbi.Processor, error) { + labels := protoutil.AsStringList(stmt.InE) + return &InE{db: sc.db, labels: labels, loadData: ps.StepLoadData()}, nil +} + +func (sc *GridStmtCompiler) InENull(stmt *gripql.GraphStatement_InENull, ps *gdbi.State) (gdbi.Processor, error) { + labels := protoutil.AsStringList(stmt.InENull) + ps.LastType = gdbi.EdgeData + return &InE{db: sc.db, labels: labels, loadData: ps.StepLoadData(), emitNull: true}, nil +} + +func (sc *GridStmtCompiler) OutE(stmt *gripql.GraphStatement_OutE, ps *gdbi.State) (gdbi.Processor, error) { + labels := protoutil.AsStringList(stmt.OutE) + ps.LastType = gdbi.EdgeData + return &OutE{db: sc.db, labels: labels, loadData: ps.StepLoadData()}, nil +} + +func (sc *GridStmtCompiler) OutENull(stmt *gripql.GraphStatement_OutENull, ps *gdbi.State) (gdbi.Processor, error) { + labels := protoutil.AsStringList(stmt.OutENull) + ps.LastType = gdbi.EdgeData + return &OutE{db: sc.db, labels: labels, loadData: ps.StepLoadData(), emitNull: true}, nil +} + +func (sc *GridStmtCompiler) BothE(stmt *gripql.GraphStatement_BothE, ps *gdbi.State) (gdbi.Processor, error) { + labels := protoutil.AsStringList(stmt.BothE) + ps.LastType = gdbi.EdgeData + return &both{db: sc.db, labels: labels, lastType: gdbi.VertexData, toType: gdbi.EdgeData, loadData: ps.StepLoadData()}, nil +} + +func (sc *GridStmtCompiler) Has(stmt *gripql.GraphStatement_Has, ps *gdbi.State) (gdbi.Processor, error) { + return &Has{stmt.Has}, nil +} + +func (sc *GridStmtCompiler) HasLabel(stmt *gripql.GraphStatement_HasLabel, ps *gdbi.State) (gdbi.Processor, error) { + labels := protoutil.AsStringList(stmt.HasLabel) + if len(labels) == 0 { + return nil, fmt.Errorf(`no labels provided to "HasLabel" statement`) + } + return &HasLabel{labels}, nil +} + +func (sc *GridStmtCompiler) HasKey(stmt *gripql.GraphStatement_HasKey, ps *gdbi.State) (gdbi.Processor, error) { + keys := protoutil.AsStringList(stmt.HasKey) + if len(keys) == 0 { + return nil, fmt.Errorf(`no keys provided to "HasKey" statement`) + } + return &HasKey{keys}, nil +} + +func (sc *GridStmtCompiler) HasID(stmt *gripql.GraphStatement_HasId, ps *gdbi.State) (gdbi.Processor, error) { + ids := protoutil.AsStringList(stmt.HasId) + if len(ids) == 0 { + return nil, fmt.Errorf(`no ids provided to "HasId" statement`) + } + return &HasID{ids}, nil +} + +func (sc *GridStmtCompiler) Limit(stmt *gripql.GraphStatement_Limit, ps *gdbi.State) (gdbi.Processor, error) { + return &Limit{stmt.Limit}, nil +} + +func (sc *GridStmtCompiler) Skip(stmt *gripql.GraphStatement_Skip, ps *gdbi.State) (gdbi.Processor, error) { + return &Skip{stmt.Skip}, nil +} + +func (sc *GridStmtCompiler) Range(stmt *gripql.GraphStatement_Range, ps *gdbi.State) (gdbi.Processor, error) { + return &Range{start: stmt.Range.Start, stop: stmt.Range.Stop}, nil +} + +func (sc *GridStmtCompiler) Count(stmt *gripql.GraphStatement_Count, ps *gdbi.State) (gdbi.Processor, error) { + return &Count{}, nil +} + +func (sc *GridStmtCompiler) Distinct(stmt *gripql.GraphStatement_Distinct, ps *gdbi.State) (gdbi.Processor, error) { + fields := protoutil.AsStringList(stmt.Distinct) + if len(fields) == 0 { + fields = append(fields, "_gid") + } + return &Distinct{fields}, nil +} + +func (sc *GridStmtCompiler) As(stmt *gripql.GraphStatement_As, ps *gdbi.State) (gdbi.Processor, error) { + if stmt.As == "" { + return nil, fmt.Errorf(`"mark" statement cannot have an empty name`) + } + if err := gripql.ValidateFieldName(stmt.As); err != nil { + return nil, fmt.Errorf(`"mark" statement invalid; %v`, err) + } + if stmt.As == travelerpath.Current { + return nil, fmt.Errorf(`"mark" statement invalid; uses reserved name %s`, travelerpath.Current) + } + ps.MarkTypes[stmt.As] = ps.LastType + return &Marker{stmt.As}, nil +} + +func (sc *GridStmtCompiler) Set(stmt *gripql.GraphStatement_Set, ps *gdbi.State) (gdbi.Processor, error) { + return &ValueSet{key: stmt.Set.Key, value: stmt.Set.Value.AsInterface()}, nil +} + +func (sc *GridStmtCompiler) Increment(stmt *gripql.GraphStatement_Increment, ps *gdbi.State) (gdbi.Processor, error) { + return &ValueIncrement{key: stmt.Increment.Key, value: stmt.Increment.Value}, nil +} + +func (sc *GridStmtCompiler) Mark(stmt *gripql.GraphStatement_Mark, ps *gdbi.State) (gdbi.Processor, error) { + return &logic.JumpMark{Name: stmt.Mark}, nil +} + +func (sc *GridStmtCompiler) Jump(stmt *gripql.GraphStatement_Jump, ps *gdbi.State) (gdbi.Processor, error) { + return &logic.Jump{Mark: stmt.Jump.Mark, Stmt: stmt.Jump.Expression, Emit: stmt.Jump.Emit}, nil +} + +func (sc *GridStmtCompiler) Select(stmt *gripql.GraphStatement_Select, ps *gdbi.State) (gdbi.Processor, error) { + switch len(stmt.Select.Marks) { + case 0: + return nil, fmt.Errorf(`"select" statement has an empty list of mark names`) + case 1: + ps.LastType = ps.MarkTypes[stmt.Select.Marks[0]] + return &MarkSelect{stmt.Select.Marks[0]}, nil + default: + ps.LastType = gdbi.SelectionData + return &Selector{stmt.Select.Marks}, nil + } +} + +func (sc *GridStmtCompiler) Render(stmt *gripql.GraphStatement_Render, ps *gdbi.State) (gdbi.Processor, error) { + return &Render{stmt.Render.AsInterface()}, nil +} + +func (sc *GridStmtCompiler) Path(stmt *gripql.GraphStatement_Path, ps *gdbi.State) (gdbi.Processor, error) { + return &Path{stmt.Path.AsSlice()}, nil +} + +func (sc *GridStmtCompiler) Unwind(stmt *gripql.GraphStatement_Unwind, ps *gdbi.State) (gdbi.Processor, error) { + return &Unwind{stmt.Unwind}, nil +} + +func (sc *GridStmtCompiler) Fields(stmt *gripql.GraphStatement_Fields, ps *gdbi.State) (gdbi.Processor, error) { + fields := protoutil.AsStringList(stmt.Fields) + return &Fields{fields}, nil +} + +func (sc *GridStmtCompiler) Aggregate(stmt *gripql.GraphStatement_Aggregate, ps *gdbi.State) (gdbi.Processor, error) { + aggs := make(map[string]interface{}) + for _, a := range stmt.Aggregate.Aggregations { + if _, ok := aggs[a.Name]; ok { + return nil, fmt.Errorf("duplicate aggregation name '%s' found; all aggregations must have a unique name", a.Name) + } + } + return &aggregate{stmt.Aggregate.Aggregations}, nil +} + +func (sc *GridStmtCompiler) Custom(gs *gripql.GraphStatement, ps *gdbi.State) (gdbi.Processor, error) { + + switch stmt := gs.GetStatement().(type) { + + //Custom graph statements + case *gripql.GraphStatement_LookupVertsIndex: + ps.LastType = gdbi.VertexData + return &LookupVertsIndex{db: sc.db, labels: stmt.Labels, loadData: ps.StepLoadData()}, nil + + case *gripql.GraphStatement_EngineCustom: + proc := stmt.Custom.(gdbi.CustomProcGen) + ps.LastType = proc.GetType() + return proc.GetProcessor(sc.db, ps) + + default: + return nil, fmt.Errorf("grip compile: unknown statement type: %s", gs.GetStatement()) + } + +} diff --git a/grids/traveler.go b/grids/old/traveler.go similarity index 97% rename from grids/traveler.go rename to grids/old/traveler.go index a2307bc1..476b3f99 100644 --- a/grids/traveler.go +++ b/grids/old/traveler.go @@ -135,7 +135,7 @@ func (tr *GRIDTraveler) IsNull() bool { } // AddCurrent creates a new copy of the travel with new 'current' value -func (t *GRIDTraveler) AddCurrent(r *gdbi.DataElement) gdbi.Traveler { +func (t *GRIDTraveler) AddCurrent(r gdbi.DataRef) gdbi.Traveler { a := t.GRIDCopy() c, _ := DataElementToGRID(r, t.Graph) a.Current = c @@ -216,7 +216,7 @@ func (t *GRIDTraveler) ListMarks() []string { } // AddMark adds a result to travels state map using `label` as the name -func (t *GRIDTraveler) AddMark(label string, r *gdbi.DataElement) gdbi.Traveler { +func (t *GRIDTraveler) AddMark(label string, r gdbi.DataRef) gdbi.Traveler { o := t.GRIDCopy() n, _ := DataElementToGRID(r, t.Graph) o.Marks[label] = n diff --git a/gripper/optimize.go b/gripper/optimize.go index b63e5550..64893098 100644 --- a/gripper/optimize.go +++ b/gripper/optimize.go @@ -3,9 +3,9 @@ package gripper import ( "context" - "github.com/bmeg/grip/engine/inspect" "github.com/bmeg/grip/gdbi" "github.com/bmeg/grip/gripql" + "github.com/bmeg/grip/gripql/inspect" "github.com/bmeg/grip/util/setcmp" "github.com/bmeg/jsonpath" ) diff --git a/jobstorage/serializer_test.go b/jobstorage/serializer_test.go index 302d66d6..1227f290 100644 --- a/jobstorage/serializer_test.go +++ b/jobstorage/serializer_test.go @@ -27,7 +27,7 @@ func TestSerializeStream(t *testing.T) { if o.GetCurrent() == nil { t.Errorf("Incorrect ouput") } else { - if i, err := strconv.Atoi(o.GetCurrent().ID); err == nil { + if i, err := strconv.Atoi(o.GetCurrent().Get().ID); err == nil { if i != count { t.Errorf("Incorrect ouput order") } diff --git a/kvgraph/index.go b/kvgraph/index.go index 193c799b..5023da89 100644 --- a/kvgraph/index.go +++ b/kvgraph/index.go @@ -6,8 +6,8 @@ import ( "strings" "github.com/bmeg/grip/gripql" - "github.com/bmeg/grip/jsonpath" "github.com/bmeg/grip/log" + "github.com/bmeg/grip/travelerpath" ) func (kgraph *KVGraph) setupGraphIndex(graph string) error { @@ -33,7 +33,7 @@ func (kgraph *KVGraph) deleteGraphIndex(graph string) { } func normalizePath(path string) string { - path = jsonpath.GetJSONPath(path) + path = travelerpath.GetJSONPath(path) path = strings.TrimPrefix(path, "$.") path = strings.TrimPrefix(path, "data.") return path @@ -59,7 +59,7 @@ func edgeIdxStruct(e *gripql.Edge) map[string]interface{} { return k } -//AddVertexIndex add index to vertices +// AddVertexIndex add index to vertices func (kgdb *KVInterfaceGDB) AddVertexIndex(label string, field string) error { log.WithFields(log.Fields{"label": label, "field": field}).Info("Adding vertex index") field = normalizePath(field) @@ -67,14 +67,14 @@ func (kgdb *KVInterfaceGDB) AddVertexIndex(label string, field string) error { return kgdb.kvg.idx.AddField(fmt.Sprintf("%s.v.%s.%s", kgdb.graph, label, field)) } -//DeleteVertexIndex delete index from vertices +// DeleteVertexIndex delete index from vertices func (kgdb *KVInterfaceGDB) DeleteVertexIndex(label string, field string) error { log.WithFields(log.Fields{"label": label, "field": field}).Info("Deleting vertex index") field = normalizePath(field) return kgdb.kvg.idx.RemoveField(fmt.Sprintf("%s.v.%s.%s", kgdb.graph, label, field)) } -//GetVertexIndexList lists out all the vertex indices for a graph +// GetVertexIndexList lists out all the vertex indices for a graph func (kgdb *KVInterfaceGDB) GetVertexIndexList() <-chan *gripql.IndexID { log.Debug("Running GetVertexIndexList") out := make(chan *gripql.IndexID) @@ -91,8 +91,8 @@ func (kgdb *KVInterfaceGDB) GetVertexIndexList() <-chan *gripql.IndexID { return out } -//VertexLabelScan produces a channel of all vertex ids in a graph -//that match a given label +// VertexLabelScan produces a channel of all vertex ids in a graph +// that match a given label func (kgdb *KVInterfaceGDB) VertexLabelScan(ctx context.Context, label string) chan string { log.WithFields(log.Fields{"label": label}).Debug("Running VertexLabelScan") //TODO: Make this work better diff --git a/kvgraph/schema.go b/kvgraph/schema.go index 2d4d49e5..788f5028 100644 --- a/kvgraph/schema.go +++ b/kvgraph/schema.go @@ -54,10 +54,10 @@ func (ma *KVGraph) sampleSchema(ctx context.Context, graph string, n uint32, ran reqChan <- gdbi.ElementLookup{ID: i} close(reqChan) for e := range gi.GetOutEdgeChannel(ctx, reqChan, true, false, []string{}) { - o := gi.GetVertex(e.Edge.To, false) + o := gi.GetVertex(e.Edge.Get().To, false) if o != nil { - k := fromtokey{from: v.Label, to: o.Label, label: e.Edge.Label} - ds := gripql.GetDataFieldTypes(e.Edge.Data) + k := fromtokey{from: v.Label, to: o.Label, label: e.Edge.Get().Label} + ds := gripql.GetDataFieldTypes(e.Edge.Get().Data) if p, ok := fromToPairs[k]; ok { fromToPairs[k] = util.MergeMaps(p, ds) } else { diff --git a/mongo/compile.go b/mongo/compile.go index 613afe03..34f84fa2 100644 --- a/mongo/compile.go +++ b/mongo/compile.go @@ -7,8 +7,8 @@ import ( "github.com/bmeg/grip/engine/core" "github.com/bmeg/grip/gdbi" "github.com/bmeg/grip/gripql" - "github.com/bmeg/grip/jsonpath" "github.com/bmeg/grip/log" + "github.com/bmeg/grip/travelerpath" "github.com/bmeg/grip/util/protoutil" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" @@ -564,7 +564,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile hasKeys := bson.M{} keys := protoutil.AsStringList(stmt.HasKey) for _, key := range keys { - key = jsonpath.GetJSONPath(key) + key = travelerpath.GetJSONPath(key) key = strings.TrimPrefix(key, "$.") hasKeys[key] = bson.M{"$exists": true} } @@ -602,13 +602,13 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile keys := bson.M{} match := bson.M{} for _, f := range fields { - namespace := jsonpath.GetNamespace(f) - f = jsonpath.GetJSONPath(f) + namespace := travelerpath.GetNamespace(f) + f = travelerpath.GetJSONPath(f) f = strings.TrimPrefix(f, "$.") if f == "gid" { f = "_id" } - if namespace != jsonpath.Current { + if namespace != travelerpath.Current { f = fmt.Sprintf("marks.%s.%s", namespace, f) } match[f] = bson.M{"$exists": true} @@ -656,8 +656,8 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile if err := gripql.ValidateFieldName(stmt.As); err != nil { return &Pipeline{}, fmt.Errorf(`"as" statement invalid; %v`, err) } - if stmt.As == jsonpath.Current { - return &Pipeline{}, fmt.Errorf(`"as" statement invalid; uses reserved name %s`, jsonpath.Current) + if stmt.As == travelerpath.Current { + return &Pipeline{}, fmt.Errorf(`"as" statement invalid; uses reserved name %s`, travelerpath.Current) } markTypes[stmt.As] = lastType query = append(query, bson.D{primitive.E{Key: "$addFields", Value: bson.M{"marks": bson.M{stmt.As: "$$ROOT"}}}}) @@ -736,12 +736,12 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile exclude = true f = strings.TrimPrefix(f, "-") } - namespace := jsonpath.GetNamespace(f) - if namespace != jsonpath.Current { + namespace := travelerpath.GetNamespace(f) + if namespace != travelerpath.Current { log.Errorf("FieldsProcessor: only can select field from current traveler") continue SelectLoop } - f = jsonpath.GetJSONPath(f) + f = travelerpath.GetJSONPath(f) f = strings.TrimPrefix(f, "$.") if exclude { excludeFields = append(excludeFields, f) @@ -791,7 +791,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile switch a.Aggregation.(type) { case *gripql.Aggregate_Term: agg := a.GetTerm() - field := jsonpath.GetJSONPath(agg.Field) + field := travelerpath.GetJSONPath(agg.Field) field = strings.TrimPrefix(field, "$.") if field == "gid" { field = "_id" @@ -814,7 +814,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile case *gripql.Aggregate_Histogram: agg := a.GetHistogram() - field := jsonpath.GetJSONPath(agg.Field) + field := travelerpath.GetJSONPath(agg.Field) field = strings.TrimPrefix(field, "$.") stmt := []bson.M{ { @@ -839,7 +839,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile case *gripql.Aggregate_Percentile: agg := a.GetPercentile() - field := jsonpath.GetJSONPath(agg.Field) + field := travelerpath.GetJSONPath(agg.Field) field = strings.TrimPrefix(field, "$.") stmt := []bson.M{ { @@ -873,7 +873,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile case *gripql.Aggregate_Type: agg := a.GetType() - field := jsonpath.GetJSONPath(agg.Field) + field := travelerpath.GetJSONPath(agg.Field) field = strings.TrimPrefix(field, "$.") stmt := []bson.M{ { @@ -899,7 +899,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile case *gripql.Aggregate_Field: agg := a.GetField() - field := jsonpath.GetJSONPath(agg.Field) + field := travelerpath.GetJSONPath(agg.Field) field = strings.TrimPrefix(field, "$.") stmt := []bson.M{ { diff --git a/mongo/compile_test.go b/mongo/compile_test.go index 7dd6523f..3ea0cba2 100644 --- a/mongo/compile_test.go +++ b/mongo/compile_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/bmeg/grip/gripql" - "github.com/bmeg/grip/jsonpath" + "github.com/bmeg/grip/travelerpath" "github.com/bmeg/grip/util" "go.mongodb.org/mongo-driver/bson" ) @@ -37,14 +37,14 @@ func TestDistinctPathing(t *testing.T) { keys := bson.M{} for _, f := range fields { - namespace := jsonpath.GetNamespace(f) + namespace := travelerpath.GetNamespace(f) fmt.Printf("Namespace: %s\n", namespace) - f = jsonpath.GetJSONPath(f) + f = travelerpath.GetJSONPath(f) f = strings.TrimPrefix(f, "$.") if f == "gid" { f = "_id" } - if namespace != jsonpath.Current { + if namespace != travelerpath.Current { f = fmt.Sprintf("marks.%s.%s", namespace, f) } match[f] = bson.M{"$exists": true} diff --git a/mongo/has_evaluator.go b/mongo/has_evaluator.go index c6bcab28..5e6dbc22 100644 --- a/mongo/has_evaluator.go +++ b/mongo/has_evaluator.go @@ -4,8 +4,8 @@ import ( "strings" "github.com/bmeg/grip/gripql" - "github.com/bmeg/grip/jsonpath" "github.com/bmeg/grip/log" + "github.com/bmeg/grip/travelerpath" "go.mongodb.org/mongo-driver/bson" ) @@ -80,7 +80,7 @@ func convertHasExpression(stmt *gripql.HasExpression, not bool) bson.M { } func convertPath(key string) string { - key = jsonpath.GetJSONPath(key) + key = travelerpath.GetJSONPath(key) key = strings.TrimPrefix(key, "$.") if key == "gid" { key = "_id" diff --git a/mongo/index.go b/mongo/index.go index 53941b53..bd9a3db0 100644 --- a/mongo/index.go +++ b/mongo/index.go @@ -6,8 +6,8 @@ import ( "strings" "github.com/bmeg/grip/gripql" - "github.com/bmeg/grip/jsonpath" "github.com/bmeg/grip/log" + "github.com/bmeg/grip/travelerpath" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" @@ -16,7 +16,7 @@ import ( // AddVertexIndex add index to vertices func (mg *Graph) AddVertexIndex(label string, field string) error { log.WithFields(log.Fields{"label": label, "field": field}).Info("Adding vertex index") - field = jsonpath.GetJSONPath(field) + field = travelerpath.GetJSONPath(field) field = strings.TrimPrefix(field, "$.") idx := mg.ar.VertexCollection(mg.graph).Indexes() @@ -36,7 +36,7 @@ func (mg *Graph) AddVertexIndex(label string, field string) error { // DeleteVertexIndex delete index from vertices func (mg *Graph) DeleteVertexIndex(label string, field string) error { log.WithFields(log.Fields{"label": label, "field": field}).Info("Deleting vertex index") - field = jsonpath.GetJSONPath(field) + field = travelerpath.GetJSONPath(field) field = strings.TrimPrefix(field, "$.") idx := mg.ar.VertexCollection(mg.graph).Indexes() diff --git a/mongo/processor.go b/mongo/processor.go index 4f2b72dd..783f21f1 100644 --- a/mongo/processor.go +++ b/mongo/processor.go @@ -88,7 +88,7 @@ func (proc *Processor) Process(ctx context.Context, man gdbi.Manager, in gdbi.In out <- eo case gdbi.SelectionData: - selections := map[string]*gdbi.DataElement{} + selections := map[string]gdbi.DataRef{} if marks, ok := result["marks"]; ok { if marks, ok := marks.(map[string]interface{}); ok { for k, v := range marks { diff --git a/test/inspect_test.go b/test/inspect_test.go index f19c49b0..bd7d2bfd 100644 --- a/test/inspect_test.go +++ b/test/inspect_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/bmeg/grip/engine/core" - "github.com/bmeg/grip/engine/inspect" "github.com/bmeg/grip/gripql" + "github.com/bmeg/grip/gripql/inspect" "github.com/bmeg/grip/util/setcmp" ) diff --git a/travelerpath/jsonpath.go b/travelerpath/jsonpath.go new file mode 100644 index 00000000..705293bc --- /dev/null +++ b/travelerpath/jsonpath.go @@ -0,0 +1,55 @@ +package travelerpath + +import ( + "strings" + + "github.com/bmeg/grip/gripql" +) + +// Current represents the 'current' traveler namespace +var Current = "__current__" + +// GetNamespace returns the namespace of the provided path +// +// Example: +// GetNamespace("$gene.symbol.ensembl") returns "gene" +func GetNamespace(path string) string { + namespace := "" + parts := strings.Split(path, ".") + if strings.HasPrefix(parts[0], "$") { + namespace = strings.TrimPrefix(parts[0], "$") + } + if namespace == "" { + namespace = Current + } + return namespace +} + +// GetJSONPath strips the namespace from the path and returns the valid +// Json path within the document referenced by the namespace +// +// Example: +// GetJSONPath("gene.symbol.ensembl") returns "$.data.symbol.ensembl" +func GetJSONPath(path string) string { + parts := strings.Split(path, ".") + if strings.HasPrefix(parts[0], "$") { + parts = parts[1:] + } + if len(parts) == 0 { + return "" + } + found := false + for _, v := range gripql.ReservedFields { + if parts[0] == v { + found = true + parts[0] = strings.TrimPrefix(parts[0], "_") + } + } + + if !found { + parts = append([]string{"data"}, parts...) + } + + parts = append([]string{"$"}, parts...) + return strings.Join(parts, ".") +} From 88aa084cb4d345124e429c5d3376d78d91915fed Mon Sep 17 00:00:00 2001 From: Kyle Ellrott Date: Wed, 7 Feb 2024 07:45:15 -0800 Subject: [PATCH 03/23] Adding missing files --- gripql/inspect/haslabel.go | 59 +++++++++++++ gripql/inspect/inspect.go | 172 +++++++++++++++++++++++++++++++++++++ 2 files changed, 231 insertions(+) create mode 100644 gripql/inspect/haslabel.go create mode 100644 gripql/inspect/inspect.go diff --git a/gripql/inspect/haslabel.go b/gripql/inspect/haslabel.go new file mode 100644 index 00000000..fa9abdcc --- /dev/null +++ b/gripql/inspect/haslabel.go @@ -0,0 +1,59 @@ +package inspect + +import ( + "github.com/bmeg/grip/gripql" + "github.com/bmeg/grip/util/protoutil" +) + +func FindVertexHasLabelStart(pipe []*gripql.GraphStatement) ([]string, []*gripql.GraphStatement) { + hasLabelLen := 0 + labels := []string{} + isDone := false + for i, step := range pipe { + if isDone { + break + } + if i == 0 { + if _, ok := step.GetStatement().(*gripql.GraphStatement_V); ok { + //lookupV = lv + } else { + break + } + continue + } + switch s := step.GetStatement().(type) { + case *gripql.GraphStatement_HasLabel: + labels = protoutil.AsStringList(s.HasLabel) + hasLabelLen = i + 1 + default: + isDone = true + } + } + return labels, pipe[hasLabelLen:] +} + +func FindEdgeHasLabelStart(pipe []*gripql.GraphStatement) ([]string, []*gripql.GraphStatement) { + hasLabelLen := 0 + labels := []string{} + isDone := false + for i, step := range pipe { + if isDone { + break + } + if i == 0 { + if _, ok := step.GetStatement().(*gripql.GraphStatement_E); ok { + } else { + break + } + continue + } + switch s := step.GetStatement().(type) { + case *gripql.GraphStatement_HasLabel: + labels = protoutil.AsStringList(s.HasLabel) + hasLabelLen = i + 1 + default: + isDone = true + } + } + return labels, pipe[hasLabelLen:] +} diff --git a/gripql/inspect/inspect.go b/gripql/inspect/inspect.go new file mode 100644 index 00000000..ca376824 --- /dev/null +++ b/gripql/inspect/inspect.go @@ -0,0 +1,172 @@ +package inspect + +import ( + "fmt" + + "github.com/bmeg/grip/gripql" + "github.com/bmeg/grip/log" + "github.com/bmeg/grip/travelerpath" + "github.com/bmeg/grip/util/protoutil" +) + +func arrayEq(a, b []string) bool { + if len(a) != len(b) { + return false + } + for i := range a { + if a[i] != b[i] { + return false + } + } + return true +} + +func contains(a []string, n string) bool { + for _, c := range a { + if c == n { + return true + } + } + return false +} + +// PipelineSteps create an array, the same length at stmts that labels the +// step id for each of the GraphStatements +func PipelineSteps(stmts []*gripql.GraphStatement) []string { + out := []string{} + curState := 0 + for _, gs := range stmts { + switch gs.GetStatement().(type) { + //These commands all change the position of the traveler. When that happens, + //we go to the next 'step' of the traversal + case *gripql.GraphStatement_V, *gripql.GraphStatement_E, *gripql.GraphStatement_Out, + *gripql.GraphStatement_In, *gripql.GraphStatement_OutE, *gripql.GraphStatement_InE, + *gripql.GraphStatement_Both, *gripql.GraphStatement_BothE, *gripql.GraphStatement_Select, + *gripql.GraphStatement_InNull, *gripql.GraphStatement_OutNull, + *gripql.GraphStatement_InENull, *gripql.GraphStatement_OutENull: + curState++ + case *gripql.GraphStatement_Limit, *gripql.GraphStatement_As, *gripql.GraphStatement_Has, + *gripql.GraphStatement_HasId, *gripql.GraphStatement_HasKey, *gripql.GraphStatement_HasLabel, + *gripql.GraphStatement_Count, *gripql.GraphStatement_Skip, *gripql.GraphStatement_Distinct, + *gripql.GraphStatement_Range, *gripql.GraphStatement_Aggregate, *gripql.GraphStatement_Render, + *gripql.GraphStatement_Fields, *gripql.GraphStatement_Unwind, *gripql.GraphStatement_Path, + *gripql.GraphStatement_Set, *gripql.GraphStatement_Increment, + *gripql.GraphStatement_Mark, *gripql.GraphStatement_Jump: + case *gripql.GraphStatement_LookupVertsIndex, *gripql.GraphStatement_EngineCustom: + default: + log.Errorf("Unknown Graph Statement: %T", gs.GetStatement()) + } + out = append(out, fmt.Sprintf("%d", curState)) + } + return out +} + +// PipelineSteps identify the variable names each step can be aliasesed using +// the as_ operation +func PipelineAsSteps(stmts []*gripql.GraphStatement) map[string]string { + out := map[string]string{} + steps := PipelineSteps(stmts) + + for i, gs := range stmts { + switch stmt := gs.GetStatement().(type) { + case *gripql.GraphStatement_As: + out[stmt.As] = steps[i] + } + } + return out +} + +// PipelineStepOutputs identify the required outputs for each step in the traversal +func PipelineStepOutputs(stmts []*gripql.GraphStatement) map[string][]string { + + steps := PipelineSteps(stmts) + asMap := PipelineAsSteps(stmts) + onLast := true + out := map[string][]string{} + for i := len(stmts) - 1; i >= 0; i-- { + gs := stmts[i] + switch gs.GetStatement().(type) { + case *gripql.GraphStatement_Count: + onLast = false + case *gripql.GraphStatement_Select: + if onLast { + sel := gs.GetSelect().Marks + for _, s := range sel { + if a, ok := asMap[s]; ok { + out[a] = []string{"*"} + } + } + onLast = false + } + case *gripql.GraphStatement_Distinct: + //if there is a distinct step, we need to load data, but only for requested fields + fields := protoutil.AsStringList(gs.GetDistinct()) + for _, f := range fields { + n := travelerpath.GetNamespace(f) + if n == travelerpath.Current { + out[steps[i]] = []string{"*"} + } + if a, ok := asMap[n]; ok { + out[a] = []string{"*"} + } + } + case *gripql.GraphStatement_V, *gripql.GraphStatement_E, + *gripql.GraphStatement_Out, *gripql.GraphStatement_In, + *gripql.GraphStatement_OutE, *gripql.GraphStatement_InE, + *gripql.GraphStatement_Both, *gripql.GraphStatement_BothE: + if onLast { + out[steps[i]] = []string{"*"} + } + onLast = false + case *gripql.GraphStatement_LookupVertsIndex: + if onLast { + out[steps[i]] = []string{"*"} + } + onLast = false + + case *gripql.GraphStatement_HasLabel: + if x, ok := out[steps[i]]; ok { + out[steps[i]] = append(x, "_label") + } else { + out[steps[i]] = []string{"_label"} + } + case *gripql.GraphStatement_Has: + out[steps[i]] = []string{"*"} + } + } + return out +} + +// PipelineNoLoadPath identifies 'paths' which are groups of statements that move +// travelers across multiple steps, and don't require data (other then the label) +// to be loaded +func PipelineNoLoadPath(stmts []*gripql.GraphStatement, minLen int) [][]int { + out := [][]int{} + + steps := PipelineSteps(stmts) + outputs := PipelineStepOutputs(stmts) + curPath := []int{} + for i := range steps { + switch stmts[i].GetStatement().(type) { + case *gripql.GraphStatement_In, *gripql.GraphStatement_Out, + *gripql.GraphStatement_InE, *gripql.GraphStatement_OutE, + *gripql.GraphStatement_HasLabel: + if s, ok := outputs[steps[i]]; !ok { + curPath = append(curPath, i) + } else { + if arrayEq(s, []string{"_label"}) { + curPath = append(curPath, i) + } else { + if len(curPath) >= minLen { + out = append(out, curPath) + } + curPath = []int{} + } + } + } + } + if len(curPath) >= minLen { + out = append(out, curPath) + } + return out +} From ddf6deeff56f8f2faaa46fd5619afc9bb3c8cf0f Mon Sep 17 00:00:00 2001 From: Kyle Ellrott Date: Wed, 7 Feb 2024 07:53:30 -0800 Subject: [PATCH 04/23] Fixing reference issues and move old test code --- engine/pipeline/pipes.go | 48 ++++++++++++++++------------- {test => grids/test}/keymap_test.go | 0 2 files changed, 27 insertions(+), 21 deletions(-) rename {test => grids/test}/keymap_test.go (100%) diff --git a/engine/pipeline/pipes.go b/engine/pipeline/pipes.go index 3756f54d..e9a3ede7 100644 --- a/engine/pipeline/pipes.go +++ b/engine/pipeline/pipes.go @@ -118,33 +118,39 @@ func Resume(ctx context.Context, pipe gdbi.Pipeline, workdir string, input gdbi. func Convert(graph gdbi.GraphInterface, dataType gdbi.DataType, markTypes map[string]gdbi.DataType, t gdbi.Traveler) *gripql.QueryResult { switch dataType { case gdbi.VertexData: - ve := t.GetCurrent().Get() - if ve != nil { - if !ve.Loaded { - //log.Infof("Loading output vertex: %s", ve.ID) - //TODO: doing single vertex queries is slow. - // Need to rework this to do batched queries - ve = graph.GetVertex(ve.ID, true) - } - return &gripql.QueryResult{ - Result: &gripql.QueryResult_Vertex{ - Vertex: ve.ToVertex(), - }, + ver := t.GetCurrent() + if ver != nil { + ve := ver.Get() + if ve != nil { + if !ve.Loaded { + //log.Infof("Loading output vertex: %s", ve.ID) + //TODO: doing single vertex queries is slow. + // Need to rework this to do batched queries + ve = graph.GetVertex(ve.ID, true) + } + return &gripql.QueryResult{ + Result: &gripql.QueryResult_Vertex{ + Vertex: ve.ToVertex(), + }, + } } } else { return &gripql.QueryResult{Result: &gripql.QueryResult_Vertex{}} } case gdbi.EdgeData: - ee := t.GetCurrent().Get() - if ee != nil { - if !ee.Loaded { - ee = graph.GetEdge(ee.ID, true) - } - return &gripql.QueryResult{ - Result: &gripql.QueryResult_Edge{ - Edge: ee.ToEdge(), - }, + eer := t.GetCurrent() + if eer != nil { + ee := eer.Get() + if ee != nil { + if !ee.Loaded { + ee = graph.GetEdge(ee.ID, true) + } + return &gripql.QueryResult{ + Result: &gripql.QueryResult_Edge{ + Edge: ee.ToEdge(), + }, + } } } else { return &gripql.QueryResult{Result: &gripql.QueryResult_Edge{}} diff --git a/test/keymap_test.go b/grids/test/keymap_test.go similarity index 100% rename from test/keymap_test.go rename to grids/test/keymap_test.go From 37b04e38a30fc03aeaa78a407af3565f0accbdb3 Mon Sep 17 00:00:00 2001 From: Kyle Ellrott Date: Wed, 7 Feb 2024 08:45:17 -0800 Subject: [PATCH 05/23] Adding verbose output option to server and fixing pebble bulk insert compaction rate --- cmd/server/main.go | 8 ++++++++ gdbi/jsonpath.go | 12 ++++++++++-- gdbi/traveler.go | 16 +++++++++------- kvi/pebbledb/pebble_store.go | 5 ++++- 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/cmd/server/main.go b/cmd/server/main.go index 8f0c7ddf..b903cf34 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -18,6 +18,7 @@ import ( var conf = &config.Config{} var configFile string var driver = "badger" +var verbose bool var endPoints = map[string]string{} @@ -102,6 +103,11 @@ var Cmd = &cobra.Command{ conf.RPCClient.ServerAddress = conf.Server.RPCAddress() } } + + if verbose { + conf.Logger.Level = "debug" + } + return nil }, RunE: func(cmd *cobra.Command, args []string) error { @@ -119,6 +125,8 @@ func init() { flags.StringVar(&conf.Logger.Formatter, "log-format", conf.Logger.Formatter, "Log format [text, json]") flags.BoolVar(&conf.Server.RequestLogging.Enable, "log-requests", conf.Server.RequestLogging.Enable, "Log all requests") + flags.BoolVar(&verbose, "verbose", verbose, "Verbose") + flags.StringVarP(&pluginDir, "plugins", "p", pluginDir, "Directory with GRIPPER plugins") flags.StringVarP(&driver, "driver", "d", driver, "Default Driver") diff --git a/gdbi/jsonpath.go b/gdbi/jsonpath.go index f77ceb47..91228f0e 100644 --- a/gdbi/jsonpath.go +++ b/gdbi/jsonpath.go @@ -48,9 +48,17 @@ import ( func GetDoc(traveler Traveler, namespace string) map[string]interface{} { var tmap map[string]interface{} if namespace == travelerpath.Current { - tmap = traveler.GetCurrent().Get().ToDict() + dr := traveler.GetCurrent() + if dr == nil { + return nil + } + tmap = dr.Get().ToDict() } else { - tmap = traveler.GetMark(namespace).Get().ToDict() + dr := traveler.GetMark(namespace) + if dr == nil { + return nil + } + tmap = dr.Get().ToDict() } return tmap } diff --git a/gdbi/traveler.go b/gdbi/traveler.go index e778292e..35f8dec7 100644 --- a/gdbi/traveler.go +++ b/gdbi/traveler.go @@ -38,13 +38,15 @@ func (t *BaseTraveler) AddCurrent(r DataRef) Traveler { for i := range t.Path { o.Path[i] = t.Path[i] } - rd := r.Get() - if rd == nil { - o.Path[len(t.Path)] = DataElementID{} - } else if rd.To != "" { - o.Path[len(t.Path)] = DataElementID{Edge: rd.ID} - } else { - o.Path[len(t.Path)] = DataElementID{Vertex: rd.ID} + if r != nil { + rd := r.Get() + if rd == nil { + o.Path[len(t.Path)] = DataElementID{} + } else if rd.To != "" { + o.Path[len(t.Path)] = DataElementID{Edge: rd.ID} + } else { + o.Path[len(t.Path)] = DataElementID{Vertex: rd.ID} + } } o.Current = r return &o diff --git a/kvi/pebbledb/pebble_store.go b/kvi/pebbledb/pebble_store.go index 78b61986..d3446078 100644 --- a/kvi/pebbledb/pebble_store.go +++ b/kvi/pebbledb/pebble_store.go @@ -19,6 +19,8 @@ import ( var loaded = kvi.AddKVDriver("pebble", NewKVInterface) +var defaultCompactLimit = uint32(10000) + // PebbleKV is an implementation of the KVStore for badger type PebbleKV struct { db *pebble.DB @@ -32,7 +34,7 @@ func NewKVInterface(path string, kopts kvi.Options) (kvi.KVInterface, error) { if err != nil { return nil, err } - return &PebbleKV{db: db}, nil + return &PebbleKV{db: db, insertCount: 0, compactLimit: defaultCompactLimit}, nil } func WrapPebble(db *pebble.DB) kvi.KVInterface { @@ -269,6 +271,7 @@ func (pdb *PebbleKV) BulkWrite(u func(tx kvi.KVBulkWrite) error) error { pdb.insertCount += ptx.totalInserts if pdb.insertCount > pdb.compactLimit { + log.Debugf("Running pebble compact %d > %d", pdb.insertCount, pdb.compactLimit) //pdb.db.Compact(ptx.lowest, ptx.highest, true) pdb.db.Compact([]byte{0x00}, []byte{0xFF}, true) pdb.insertCount = 0 From 0f69c26e16e95cecc9b51c31517185ba7519364c Mon Sep 17 00:00:00 2001 From: Kyle Ellrott Date: Wed, 7 Feb 2024 11:20:27 -0800 Subject: [PATCH 06/23] Simplifying `select` command and removing alternate use, which is better handled by `render` --- conformance/tests/ot_mark.py | 4 +- engine/core/statement_compiler.go | 12 +- engine/pipeline/pipes.go | 39 - gdbi/statement_processor.go | 2 +- gripql/gripql.pb.go | 1736 +++++++++----------- gripql/gripql.proto | 18 +- gripql/inspect/inspect.go | 10 - gripql/python/gripql/query.py | 15 +- gripql/query.go | 7 +- gripql/schema/scan.go | 68 +- mongo/compile.go | 60 +- website/content/docs/queries/operations.md | 10 +- 12 files changed, 813 insertions(+), 1168 deletions(-) diff --git a/conformance/tests/ot_mark.py b/conformance/tests/ot_mark.py index 18ab5c3f..e33c3657 100644 --- a/conformance/tests/ot_mark.py +++ b/conformance/tests/ot_mark.py @@ -9,7 +9,7 @@ def test_mark_select_label_filter(man): for row in G.query().V("Film:1").as_("a").\ both("films").\ as_("b").\ - select(["a", "b"]): + render({"a" : "$a", "b" : "$b"}): count += 1 if len(row) != 2: errors.append("Incorrect number of marks returned") @@ -32,7 +32,7 @@ def test_mark_select(man): count = 0 for row in G.query().V("Character:1").as_("a").out().as_( - "b").out().as_("c").select(["a", "b", "c"]): + "b").out().as_("c").render({"a": "$a", "b": "$b", "c": "$c"}): count += 1 if len(row) != 3: errors.append("Incorrect number of marks returned") diff --git a/engine/core/statement_compiler.go b/engine/core/statement_compiler.go index 015c7f0a..30333d5f 100644 --- a/engine/core/statement_compiler.go +++ b/engine/core/statement_compiler.go @@ -190,16 +190,8 @@ func (sc *DefaultStmtCompiler) Jump(stmt *gripql.GraphStatement_Jump, ps *gdbi.S } func (sc *DefaultStmtCompiler) Select(stmt *gripql.GraphStatement_Select, ps *gdbi.State) (gdbi.Processor, error) { - switch len(stmt.Select.Marks) { - case 0: - return nil, fmt.Errorf(`"select" statement has an empty list of mark names`) - case 1: - ps.LastType = ps.MarkTypes[stmt.Select.Marks[0]] - return &MarkSelect{stmt.Select.Marks[0]}, nil - default: - ps.LastType = gdbi.SelectionData - return &Selector{stmt.Select.Marks}, nil - } + ps.LastType = ps.MarkTypes[stmt.Select] + return &MarkSelect{stmt.Select}, nil } func (sc *DefaultStmtCompiler) Render(stmt *gripql.GraphStatement_Render, ps *gdbi.State) (gdbi.Processor, error) { diff --git a/engine/pipeline/pipes.go b/engine/pipeline/pipes.go index e9a3ede7..a8436f67 100644 --- a/engine/pipeline/pipes.go +++ b/engine/pipeline/pipes.go @@ -163,45 +163,6 @@ func Convert(graph gdbi.GraphInterface, dataType gdbi.DataType, markTypes map[st }, } - case gdbi.SelectionData: - selections := map[string]*gripql.Selection{} - for k, v := range t.GetSelections() { - vd := v.Get() - switch markTypes[k] { - case gdbi.VertexData: - var ve *gripql.Vertex - if !vd.Loaded { - ve = graph.GetVertex(vd.ID, true).ToVertex() - } else { - ve = vd.ToVertex() - } - selections[k] = &gripql.Selection{ - Result: &gripql.Selection_Vertex{ - Vertex: ve, - }, - } - case gdbi.EdgeData: - var ee *gripql.Edge - if !vd.Loaded { - ee = graph.GetEdge(ee.Gid, true).ToEdge() - } else { - ee = vd.ToEdge() - } - selections[k] = &gripql.Selection{ - Result: &gripql.Selection_Edge{ - Edge: ee, - }, - } - } - } - return &gripql.QueryResult{ - Result: &gripql.QueryResult_Selections{ - Selections: &gripql.Selections{ - Selections: selections, - }, - }, - } - case gdbi.RenderData: sValue, _ := structpb.NewValue(t.GetRender()) return &gripql.QueryResult{ diff --git a/gdbi/statement_processor.go b/gdbi/statement_processor.go index 10ce411c..38730e3e 100644 --- a/gdbi/statement_processor.go +++ b/gdbi/statement_processor.go @@ -194,7 +194,7 @@ func StatementProcessor( return nil, fmt.Errorf(`"select" statement is only valid for edge or vertex types not: %s`, ps.LastType.String()) } out, err := sc.Select(stmt, ps) - ps.LastType = ps.MarkTypes[stmt.Select.Marks[0]] + ps.LastType = ps.MarkTypes[stmt.Select] return out, err case *gripql.GraphStatement_Render: diff --git a/gripql/gripql.pb.go b/gripql/gripql.pb.go index 2664b202..67e7415a 100644 --- a/gripql/gripql.pb.go +++ b/gripql/gripql.pb.go @@ -551,11 +551,11 @@ func (x *GraphStatement) GetAs() string { return "" } -func (x *GraphStatement) GetSelect() *SelectStatement { +func (x *GraphStatement) GetSelect() string { if x, ok := x.GetStatement().(*GraphStatement_Select); ok { return x.Select } - return nil + return "" } func (x *GraphStatement) GetLimit() uint32 { @@ -741,7 +741,7 @@ type GraphStatement_As struct { } type GraphStatement_Select struct { - Select *SelectStatement `protobuf:"bytes,21,opt,name=select,proto3,oneof"` + Select string `protobuf:"bytes,21,opt,name=select,proto3,oneof"` } type GraphStatement_Limit struct { @@ -1761,181 +1761,6 @@ func (x *HasCondition) GetCondition() Condition { return Condition_UNKNOWN_CONDITION } -type SelectStatement struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Marks []string `protobuf:"bytes,1,rep,name=marks,proto3" json:"marks,omitempty"` -} - -func (x *SelectStatement) Reset() { - *x = SelectStatement{} - if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[18] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *SelectStatement) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SelectStatement) ProtoMessage() {} - -func (x *SelectStatement) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[18] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SelectStatement.ProtoReflect.Descriptor instead. -func (*SelectStatement) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{18} -} - -func (x *SelectStatement) GetMarks() []string { - if x != nil { - return x.Marks - } - return nil -} - -type Selection struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Result: - // - // *Selection_Vertex - // *Selection_Edge - Result isSelection_Result `protobuf_oneof:"result"` -} - -func (x *Selection) Reset() { - *x = Selection{} - if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[19] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Selection) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Selection) ProtoMessage() {} - -func (x *Selection) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[19] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Selection.ProtoReflect.Descriptor instead. -func (*Selection) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{19} -} - -func (m *Selection) GetResult() isSelection_Result { - if m != nil { - return m.Result - } - return nil -} - -func (x *Selection) GetVertex() *Vertex { - if x, ok := x.GetResult().(*Selection_Vertex); ok { - return x.Vertex - } - return nil -} - -func (x *Selection) GetEdge() *Edge { - if x, ok := x.GetResult().(*Selection_Edge); ok { - return x.Edge - } - return nil -} - -type isSelection_Result interface { - isSelection_Result() -} - -type Selection_Vertex struct { - Vertex *Vertex `protobuf:"bytes,1,opt,name=vertex,proto3,oneof"` -} - -type Selection_Edge struct { - Edge *Edge `protobuf:"bytes,2,opt,name=edge,proto3,oneof"` -} - -func (*Selection_Vertex) isSelection_Result() {} - -func (*Selection_Edge) isSelection_Result() {} - -type Selections struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Selections map[string]*Selection `protobuf:"bytes,1,rep,name=selections,proto3" json:"selections,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` -} - -func (x *Selections) Reset() { - *x = Selections{} - if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[20] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Selections) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Selections) ProtoMessage() {} - -func (x *Selections) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[20] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use Selections.ProtoReflect.Descriptor instead. -func (*Selections) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{20} -} - -func (x *Selections) GetSelections() map[string]*Selection { - if x != nil { - return x.Selections - } - return nil -} - type Jump struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1949,7 +1774,7 @@ type Jump struct { func (x *Jump) Reset() { *x = Jump{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[21] + mi := &file_gripql_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1962,7 +1787,7 @@ func (x *Jump) String() string { func (*Jump) ProtoMessage() {} func (x *Jump) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[21] + mi := &file_gripql_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1975,7 +1800,7 @@ func (x *Jump) ProtoReflect() protoreflect.Message { // Deprecated: Use Jump.ProtoReflect.Descriptor instead. func (*Jump) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{21} + return file_gripql_proto_rawDescGZIP(), []int{18} } func (x *Jump) GetMark() string { @@ -2011,7 +1836,7 @@ type Set struct { func (x *Set) Reset() { *x = Set{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[22] + mi := &file_gripql_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2024,7 +1849,7 @@ func (x *Set) String() string { func (*Set) ProtoMessage() {} func (x *Set) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[22] + mi := &file_gripql_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2037,7 +1862,7 @@ func (x *Set) ProtoReflect() protoreflect.Message { // Deprecated: Use Set.ProtoReflect.Descriptor instead. func (*Set) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{22} + return file_gripql_proto_rawDescGZIP(), []int{19} } func (x *Set) GetKey() string { @@ -2066,7 +1891,7 @@ type Increment struct { func (x *Increment) Reset() { *x = Increment{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[23] + mi := &file_gripql_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2079,7 +1904,7 @@ func (x *Increment) String() string { func (*Increment) ProtoMessage() {} func (x *Increment) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[23] + mi := &file_gripql_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2092,7 +1917,7 @@ func (x *Increment) ProtoReflect() protoreflect.Message { // Deprecated: Use Increment.ProtoReflect.Descriptor instead. func (*Increment) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{23} + return file_gripql_proto_rawDescGZIP(), []int{20} } func (x *Increment) GetKey() string { @@ -2122,7 +1947,7 @@ type Vertex struct { func (x *Vertex) Reset() { *x = Vertex{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[24] + mi := &file_gripql_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2135,7 +1960,7 @@ func (x *Vertex) String() string { func (*Vertex) ProtoMessage() {} func (x *Vertex) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[24] + mi := &file_gripql_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2148,7 +1973,7 @@ func (x *Vertex) ProtoReflect() protoreflect.Message { // Deprecated: Use Vertex.ProtoReflect.Descriptor instead. func (*Vertex) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{24} + return file_gripql_proto_rawDescGZIP(), []int{21} } func (x *Vertex) GetGid() string { @@ -2187,7 +2012,7 @@ type Edge struct { func (x *Edge) Reset() { *x = Edge{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[25] + mi := &file_gripql_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2200,7 +2025,7 @@ func (x *Edge) String() string { func (*Edge) ProtoMessage() {} func (x *Edge) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[25] + mi := &file_gripql_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2213,7 +2038,7 @@ func (x *Edge) ProtoReflect() protoreflect.Message { // Deprecated: Use Edge.ProtoReflect.Descriptor instead. func (*Edge) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{25} + return file_gripql_proto_rawDescGZIP(), []int{22} } func (x *Edge) GetGid() string { @@ -2261,7 +2086,6 @@ type QueryResult struct { // *QueryResult_Vertex // *QueryResult_Edge // *QueryResult_Aggregations - // *QueryResult_Selections // *QueryResult_Render // *QueryResult_Count // *QueryResult_Path @@ -2271,7 +2095,7 @@ type QueryResult struct { func (x *QueryResult) Reset() { *x = QueryResult{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[26] + mi := &file_gripql_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2284,7 +2108,7 @@ func (x *QueryResult) String() string { func (*QueryResult) ProtoMessage() {} func (x *QueryResult) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[26] + mi := &file_gripql_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2297,7 +2121,7 @@ func (x *QueryResult) ProtoReflect() protoreflect.Message { // Deprecated: Use QueryResult.ProtoReflect.Descriptor instead. func (*QueryResult) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{26} + return file_gripql_proto_rawDescGZIP(), []int{23} } func (m *QueryResult) GetResult() isQueryResult_Result { @@ -2328,13 +2152,6 @@ func (x *QueryResult) GetAggregations() *NamedAggregationResult { return nil } -func (x *QueryResult) GetSelections() *Selections { - if x, ok := x.GetResult().(*QueryResult_Selections); ok { - return x.Selections - } - return nil -} - func (x *QueryResult) GetRender() *structpb.Value { if x, ok := x.GetResult().(*QueryResult_Render); ok { return x.Render @@ -2372,10 +2189,6 @@ type QueryResult_Aggregations struct { Aggregations *NamedAggregationResult `protobuf:"bytes,3,opt,name=aggregations,proto3,oneof"` } -type QueryResult_Selections struct { - Selections *Selections `protobuf:"bytes,4,opt,name=selections,proto3,oneof"` -} - type QueryResult_Render struct { Render *structpb.Value `protobuf:"bytes,5,opt,name=render,proto3,oneof"` } @@ -2394,8 +2207,6 @@ func (*QueryResult_Edge) isQueryResult_Result() {} func (*QueryResult_Aggregations) isQueryResult_Result() {} -func (*QueryResult_Selections) isQueryResult_Result() {} - func (*QueryResult_Render) isQueryResult_Result() {} func (*QueryResult_Count) isQueryResult_Result() {} @@ -2414,7 +2225,7 @@ type QueryJob struct { func (x *QueryJob) Reset() { *x = QueryJob{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[27] + mi := &file_gripql_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2427,7 +2238,7 @@ func (x *QueryJob) String() string { func (*QueryJob) ProtoMessage() {} func (x *QueryJob) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[27] + mi := &file_gripql_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2440,7 +2251,7 @@ func (x *QueryJob) ProtoReflect() protoreflect.Message { // Deprecated: Use QueryJob.ProtoReflect.Descriptor instead. func (*QueryJob) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{27} + return file_gripql_proto_rawDescGZIP(), []int{24} } func (x *QueryJob) GetId() string { @@ -2470,7 +2281,7 @@ type ExtendQuery struct { func (x *ExtendQuery) Reset() { *x = ExtendQuery{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[28] + mi := &file_gripql_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2483,7 +2294,7 @@ func (x *ExtendQuery) String() string { func (*ExtendQuery) ProtoMessage() {} func (x *ExtendQuery) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[28] + mi := &file_gripql_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2496,7 +2307,7 @@ func (x *ExtendQuery) ProtoReflect() protoreflect.Message { // Deprecated: Use ExtendQuery.ProtoReflect.Descriptor instead. func (*ExtendQuery) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{28} + return file_gripql_proto_rawDescGZIP(), []int{25} } func (x *ExtendQuery) GetSrcId() string { @@ -2536,7 +2347,7 @@ type JobStatus struct { func (x *JobStatus) Reset() { *x = JobStatus{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[29] + mi := &file_gripql_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2549,7 +2360,7 @@ func (x *JobStatus) String() string { func (*JobStatus) ProtoMessage() {} func (x *JobStatus) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[29] + mi := &file_gripql_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2562,7 +2373,7 @@ func (x *JobStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use JobStatus.ProtoReflect.Descriptor instead. func (*JobStatus) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{29} + return file_gripql_proto_rawDescGZIP(), []int{26} } func (x *JobStatus) GetId() string { @@ -2618,7 +2429,7 @@ type EditResult struct { func (x *EditResult) Reset() { *x = EditResult{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[30] + mi := &file_gripql_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2631,7 +2442,7 @@ func (x *EditResult) String() string { func (*EditResult) ProtoMessage() {} func (x *EditResult) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[30] + mi := &file_gripql_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2644,7 +2455,7 @@ func (x *EditResult) ProtoReflect() protoreflect.Message { // Deprecated: Use EditResult.ProtoReflect.Descriptor instead. func (*EditResult) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{30} + return file_gripql_proto_rawDescGZIP(), []int{27} } func (x *EditResult) GetId() string { @@ -2666,7 +2477,7 @@ type BulkEditResult struct { func (x *BulkEditResult) Reset() { *x = BulkEditResult{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[31] + mi := &file_gripql_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2679,7 +2490,7 @@ func (x *BulkEditResult) String() string { func (*BulkEditResult) ProtoMessage() {} func (x *BulkEditResult) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[31] + mi := &file_gripql_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2692,7 +2503,7 @@ func (x *BulkEditResult) ProtoReflect() protoreflect.Message { // Deprecated: Use BulkEditResult.ProtoReflect.Descriptor instead. func (*BulkEditResult) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{31} + return file_gripql_proto_rawDescGZIP(), []int{28} } func (x *BulkEditResult) GetInsertCount() int32 { @@ -2722,7 +2533,7 @@ type GraphElement struct { func (x *GraphElement) Reset() { *x = GraphElement{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[32] + mi := &file_gripql_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2735,7 +2546,7 @@ func (x *GraphElement) String() string { func (*GraphElement) ProtoMessage() {} func (x *GraphElement) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[32] + mi := &file_gripql_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2748,7 +2559,7 @@ func (x *GraphElement) ProtoReflect() protoreflect.Message { // Deprecated: Use GraphElement.ProtoReflect.Descriptor instead. func (*GraphElement) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{32} + return file_gripql_proto_rawDescGZIP(), []int{29} } func (x *GraphElement) GetGraph() string { @@ -2783,7 +2594,7 @@ type GraphID struct { func (x *GraphID) Reset() { *x = GraphID{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[33] + mi := &file_gripql_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2796,7 +2607,7 @@ func (x *GraphID) String() string { func (*GraphID) ProtoMessage() {} func (x *GraphID) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[33] + mi := &file_gripql_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2809,7 +2620,7 @@ func (x *GraphID) ProtoReflect() protoreflect.Message { // Deprecated: Use GraphID.ProtoReflect.Descriptor instead. func (*GraphID) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{33} + return file_gripql_proto_rawDescGZIP(), []int{30} } func (x *GraphID) GetGraph() string { @@ -2831,7 +2642,7 @@ type ElementID struct { func (x *ElementID) Reset() { *x = ElementID{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[34] + mi := &file_gripql_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2844,7 +2655,7 @@ func (x *ElementID) String() string { func (*ElementID) ProtoMessage() {} func (x *ElementID) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[34] + mi := &file_gripql_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2857,7 +2668,7 @@ func (x *ElementID) ProtoReflect() protoreflect.Message { // Deprecated: Use ElementID.ProtoReflect.Descriptor instead. func (*ElementID) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{34} + return file_gripql_proto_rawDescGZIP(), []int{31} } func (x *ElementID) GetGraph() string { @@ -2887,7 +2698,7 @@ type IndexID struct { func (x *IndexID) Reset() { *x = IndexID{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[35] + mi := &file_gripql_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2900,7 +2711,7 @@ func (x *IndexID) String() string { func (*IndexID) ProtoMessage() {} func (x *IndexID) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[35] + mi := &file_gripql_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2913,7 +2724,7 @@ func (x *IndexID) ProtoReflect() protoreflect.Message { // Deprecated: Use IndexID.ProtoReflect.Descriptor instead. func (*IndexID) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{35} + return file_gripql_proto_rawDescGZIP(), []int{32} } func (x *IndexID) GetGraph() string { @@ -2948,7 +2759,7 @@ type Timestamp struct { func (x *Timestamp) Reset() { *x = Timestamp{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[36] + mi := &file_gripql_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2961,7 +2772,7 @@ func (x *Timestamp) String() string { func (*Timestamp) ProtoMessage() {} func (x *Timestamp) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[36] + mi := &file_gripql_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2974,7 +2785,7 @@ func (x *Timestamp) ProtoReflect() protoreflect.Message { // Deprecated: Use Timestamp.ProtoReflect.Descriptor instead. func (*Timestamp) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{36} + return file_gripql_proto_rawDescGZIP(), []int{33} } func (x *Timestamp) GetTimestamp() string { @@ -2993,7 +2804,7 @@ type Empty struct { func (x *Empty) Reset() { *x = Empty{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[37] + mi := &file_gripql_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3006,7 +2817,7 @@ func (x *Empty) String() string { func (*Empty) ProtoMessage() {} func (x *Empty) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[37] + mi := &file_gripql_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3019,7 +2830,7 @@ func (x *Empty) ProtoReflect() protoreflect.Message { // Deprecated: Use Empty.ProtoReflect.Descriptor instead. func (*Empty) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{37} + return file_gripql_proto_rawDescGZIP(), []int{34} } type ListGraphsResponse struct { @@ -3033,7 +2844,7 @@ type ListGraphsResponse struct { func (x *ListGraphsResponse) Reset() { *x = ListGraphsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[38] + mi := &file_gripql_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3046,7 +2857,7 @@ func (x *ListGraphsResponse) String() string { func (*ListGraphsResponse) ProtoMessage() {} func (x *ListGraphsResponse) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[38] + mi := &file_gripql_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3059,7 +2870,7 @@ func (x *ListGraphsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListGraphsResponse.ProtoReflect.Descriptor instead. func (*ListGraphsResponse) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{38} + return file_gripql_proto_rawDescGZIP(), []int{35} } func (x *ListGraphsResponse) GetGraphs() []string { @@ -3080,7 +2891,7 @@ type ListIndicesResponse struct { func (x *ListIndicesResponse) Reset() { *x = ListIndicesResponse{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[39] + mi := &file_gripql_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3093,7 +2904,7 @@ func (x *ListIndicesResponse) String() string { func (*ListIndicesResponse) ProtoMessage() {} func (x *ListIndicesResponse) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[39] + mi := &file_gripql_proto_msgTypes[36] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3106,7 +2917,7 @@ func (x *ListIndicesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListIndicesResponse.ProtoReflect.Descriptor instead. func (*ListIndicesResponse) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{39} + return file_gripql_proto_rawDescGZIP(), []int{36} } func (x *ListIndicesResponse) GetIndices() []*IndexID { @@ -3128,7 +2939,7 @@ type ListLabelsResponse struct { func (x *ListLabelsResponse) Reset() { *x = ListLabelsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[40] + mi := &file_gripql_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3141,7 +2952,7 @@ func (x *ListLabelsResponse) String() string { func (*ListLabelsResponse) ProtoMessage() {} func (x *ListLabelsResponse) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[40] + mi := &file_gripql_proto_msgTypes[37] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3154,7 +2965,7 @@ func (x *ListLabelsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListLabelsResponse.ProtoReflect.Descriptor instead. func (*ListLabelsResponse) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{40} + return file_gripql_proto_rawDescGZIP(), []int{37} } func (x *ListLabelsResponse) GetVertexLabels() []string { @@ -3185,7 +2996,7 @@ type TableInfo struct { func (x *TableInfo) Reset() { *x = TableInfo{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[41] + mi := &file_gripql_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3198,7 +3009,7 @@ func (x *TableInfo) String() string { func (*TableInfo) ProtoMessage() {} func (x *TableInfo) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[41] + mi := &file_gripql_proto_msgTypes[38] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3211,7 +3022,7 @@ func (x *TableInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use TableInfo.ProtoReflect.Descriptor instead. func (*TableInfo) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{41} + return file_gripql_proto_rawDescGZIP(), []int{38} } func (x *TableInfo) GetSource() string { @@ -3255,7 +3066,7 @@ type PluginConfig struct { func (x *PluginConfig) Reset() { *x = PluginConfig{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[42] + mi := &file_gripql_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3268,7 +3079,7 @@ func (x *PluginConfig) String() string { func (*PluginConfig) ProtoMessage() {} func (x *PluginConfig) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[42] + mi := &file_gripql_proto_msgTypes[39] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3281,7 +3092,7 @@ func (x *PluginConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use PluginConfig.ProtoReflect.Descriptor instead. func (*PluginConfig) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{42} + return file_gripql_proto_rawDescGZIP(), []int{39} } func (x *PluginConfig) GetName() string { @@ -3317,7 +3128,7 @@ type PluginStatus struct { func (x *PluginStatus) Reset() { *x = PluginStatus{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[43] + mi := &file_gripql_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3330,7 +3141,7 @@ func (x *PluginStatus) String() string { func (*PluginStatus) ProtoMessage() {} func (x *PluginStatus) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[43] + mi := &file_gripql_proto_msgTypes[40] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3343,7 +3154,7 @@ func (x *PluginStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use PluginStatus.ProtoReflect.Descriptor instead. func (*PluginStatus) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{43} + return file_gripql_proto_rawDescGZIP(), []int{40} } func (x *PluginStatus) GetName() string { @@ -3371,7 +3182,7 @@ type ListDriversResponse struct { func (x *ListDriversResponse) Reset() { *x = ListDriversResponse{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[44] + mi := &file_gripql_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3384,7 +3195,7 @@ func (x *ListDriversResponse) String() string { func (*ListDriversResponse) ProtoMessage() {} func (x *ListDriversResponse) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[44] + mi := &file_gripql_proto_msgTypes[41] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3397,7 +3208,7 @@ func (x *ListDriversResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListDriversResponse.ProtoReflect.Descriptor instead. func (*ListDriversResponse) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{44} + return file_gripql_proto_rawDescGZIP(), []int{41} } func (x *ListDriversResponse) GetDrivers() []string { @@ -3418,7 +3229,7 @@ type ListPluginsResponse struct { func (x *ListPluginsResponse) Reset() { *x = ListPluginsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_gripql_proto_msgTypes[45] + mi := &file_gripql_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3431,7 +3242,7 @@ func (x *ListPluginsResponse) String() string { func (*ListPluginsResponse) ProtoMessage() {} func (x *ListPluginsResponse) ProtoReflect() protoreflect.Message { - mi := &file_gripql_proto_msgTypes[45] + mi := &file_gripql_proto_msgTypes[42] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3444,7 +3255,7 @@ func (x *ListPluginsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListPluginsResponse.ProtoReflect.Descriptor instead. func (*ListPluginsResponse) Descriptor() ([]byte, []int) { - return file_gripql_proto_rawDescGZIP(), []int{45} + return file_gripql_proto_rawDescGZIP(), []int{42} } func (x *ListPluginsResponse) GetPlugins() []string { @@ -3477,7 +3288,7 @@ var file_gripql_proto_rawDesc = []byte{ 0x65, 0x72, 0x79, 0x22, 0x38, 0x0a, 0x08, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x74, 0x12, 0x2c, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x53, 0x74, 0x61, - 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0xba, 0x0b, + 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0xa1, 0x0b, 0x0a, 0x0e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x53, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x01, 0x76, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, @@ -3518,511 +3329,487 @@ var file_gripql_proto_rawDesc = []byte{ 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x08, 0x6f, 0x75, 0x74, 0x45, 0x4e, 0x75, 0x6c, 0x6c, 0x12, 0x10, 0x0a, 0x02, 0x61, 0x73, 0x18, 0x14, 0x20, - 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x02, 0x61, 0x73, 0x12, 0x31, 0x0a, 0x06, 0x73, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x72, 0x69, 0x70, - 0x71, 0x6c, 0x2e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, - 0x6e, 0x74, 0x48, 0x00, 0x52, 0x06, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x12, 0x16, 0x0a, 0x05, - 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x05, 0x6c, - 0x69, 0x6d, 0x69, 0x74, 0x12, 0x14, 0x0a, 0x04, 0x73, 0x6b, 0x69, 0x70, 0x18, 0x19, 0x20, 0x01, - 0x28, 0x0d, 0x48, 0x00, 0x52, 0x04, 0x73, 0x6b, 0x69, 0x70, 0x12, 0x25, 0x0a, 0x05, 0x72, 0x61, - 0x6e, 0x67, 0x65, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x67, 0x72, 0x69, 0x70, - 0x71, 0x6c, 0x2e, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x48, 0x00, 0x52, 0x05, 0x72, 0x61, 0x6e, 0x67, - 0x65, 0x12, 0x29, 0x0a, 0x03, 0x68, 0x61, 0x73, 0x18, 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, - 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x48, 0x61, 0x73, 0x45, 0x78, 0x70, 0x72, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x03, 0x68, 0x61, 0x73, 0x12, 0x39, 0x0a, 0x09, - 0x68, 0x61, 0x73, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x02, 0x61, 0x73, 0x12, 0x18, 0x0a, 0x06, 0x73, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x18, 0x15, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x73, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x12, 0x16, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x18, 0x20, 0x01, + 0x28, 0x0d, 0x48, 0x00, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x14, 0x0a, 0x04, 0x73, + 0x6b, 0x69, 0x70, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x04, 0x73, 0x6b, 0x69, + 0x70, 0x12, 0x25, 0x0a, 0x05, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0d, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x48, + 0x00, 0x52, 0x05, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x29, 0x0a, 0x03, 0x68, 0x61, 0x73, 0x18, + 0x1e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x48, + 0x61, 0x73, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x03, + 0x68, 0x61, 0x73, 0x12, 0x39, 0x0a, 0x09, 0x68, 0x61, 0x73, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, + 0x18, 0x1f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x48, 0x00, 0x52, 0x08, 0x68, 0x61, 0x73, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x35, + 0x0a, 0x07, 0x68, 0x61, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x08, 0x68, - 0x61, 0x73, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x35, 0x0a, 0x07, 0x68, 0x61, 0x73, 0x5f, 0x6b, - 0x65, 0x79, 0x18, 0x20, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x06, 0x68, 0x61, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x33, - 0x0a, 0x06, 0x68, 0x61, 0x73, 0x5f, 0x69, 0x64, 0x18, 0x21, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x05, 0x68, 0x61, - 0x73, 0x49, 0x64, 0x12, 0x38, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x63, 0x74, 0x18, - 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x06, 0x68, + 0x61, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x33, 0x0a, 0x06, 0x68, 0x61, 0x73, 0x5f, 0x69, 0x64, 0x18, + 0x21, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x48, 0x00, 0x52, 0x08, 0x64, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x63, 0x74, 0x12, 0x34, 0x0a, - 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x32, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x06, 0x66, 0x69, 0x65, - 0x6c, 0x64, 0x73, 0x12, 0x18, 0x0a, 0x06, 0x75, 0x6e, 0x77, 0x69, 0x6e, 0x64, 0x18, 0x33, 0x20, - 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x75, 0x6e, 0x77, 0x69, 0x6e, 0x64, 0x12, 0x16, 0x0a, - 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x3c, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x34, 0x0a, 0x09, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, - 0x74, 0x65, 0x18, 0x3d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, - 0x6c, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x48, 0x00, - 0x52, 0x09, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x12, 0x30, 0x0a, 0x06, 0x72, - 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x3e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x30, 0x0a, - 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x3f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, - 0x14, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x46, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, - 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x22, 0x0a, 0x04, 0x6a, 0x75, 0x6d, 0x70, 0x18, 0x47, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x4a, 0x75, 0x6d, - 0x70, 0x48, 0x00, 0x52, 0x04, 0x6a, 0x75, 0x6d, 0x70, 0x12, 0x1f, 0x0a, 0x03, 0x73, 0x65, 0x74, - 0x18, 0x48, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, - 0x53, 0x65, 0x74, 0x48, 0x00, 0x52, 0x03, 0x73, 0x65, 0x74, 0x12, 0x31, 0x0a, 0x09, 0x69, 0x6e, - 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x49, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, - 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, - 0x48, 0x00, 0x52, 0x09, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x0b, 0x0a, - 0x09, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x31, 0x0a, 0x05, 0x52, 0x61, - 0x6e, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x74, 0x6f, - 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x73, 0x74, 0x6f, 0x70, 0x22, 0x62, 0x0a, - 0x13, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x61, 0x70, 0x68, 0x12, 0x35, 0x0a, 0x0c, 0x61, 0x67, - 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x11, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, - 0x61, 0x74, 0x65, 0x52, 0x0c, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x22, 0x45, 0x0a, 0x0c, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x12, 0x35, 0x0a, 0x0c, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, + 0x65, 0x48, 0x00, 0x52, 0x05, 0x68, 0x61, 0x73, 0x49, 0x64, 0x12, 0x38, 0x0a, 0x08, 0x64, 0x69, + 0x73, 0x74, 0x69, 0x6e, 0x63, 0x74, 0x18, 0x28, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, + 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x08, 0x64, 0x69, 0x73, 0x74, + 0x69, 0x6e, 0x63, 0x74, 0x12, 0x34, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x32, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x48, 0x00, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x18, 0x0a, 0x06, 0x75, 0x6e, + 0x77, 0x69, 0x6e, 0x64, 0x18, 0x33, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x75, 0x6e, + 0x77, 0x69, 0x6e, 0x64, 0x12, 0x16, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x3c, 0x20, + 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x34, 0x0a, 0x09, + 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x18, 0x3d, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x14, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x48, 0x00, 0x52, 0x09, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, + 0x74, 0x65, 0x12, 0x30, 0x0a, 0x06, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x3e, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, + 0x6e, 0x64, 0x65, 0x72, 0x12, 0x30, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x3f, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x48, 0x00, + 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x14, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x46, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x22, 0x0a, 0x04, + 0x6a, 0x75, 0x6d, 0x70, 0x18, 0x47, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x67, 0x72, 0x69, + 0x70, 0x71, 0x6c, 0x2e, 0x4a, 0x75, 0x6d, 0x70, 0x48, 0x00, 0x52, 0x04, 0x6a, 0x75, 0x6d, 0x70, + 0x12, 0x1f, 0x0a, 0x03, 0x73, 0x65, 0x74, 0x18, 0x48, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, + 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x53, 0x65, 0x74, 0x48, 0x00, 0x52, 0x03, 0x73, 0x65, + 0x74, 0x12, 0x31, 0x0a, 0x09, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x49, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x49, 0x6e, + 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x09, 0x69, 0x6e, 0x63, 0x72, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x0b, 0x0a, 0x09, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x22, 0x31, 0x0a, 0x05, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x12, 0x12, 0x0a, 0x04, 0x73, 0x74, 0x6f, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, + 0x73, 0x74, 0x6f, 0x70, 0x22, 0x62, 0x0a, 0x13, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x61, 0x70, + 0x68, 0x12, 0x35, 0x0a, 0x0c, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x52, 0x0c, 0x61, 0x67, 0x67, 0x72, - 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xef, 0x02, 0x0a, 0x09, 0x41, 0x67, 0x67, - 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x04, 0x74, 0x65, - 0x72, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, - 0x6c, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x48, 0x00, 0x52, 0x04, 0x74, 0x65, 0x72, 0x6d, 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x65, 0x72, - 0x63, 0x65, 0x6e, 0x74, 0x69, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, - 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x69, 0x6c, - 0x65, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0a, - 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x69, 0x6c, 0x65, 0x12, 0x3c, 0x0a, 0x09, 0x68, 0x69, - 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, - 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, - 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x09, 0x68, - 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, 0x30, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, - 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, - 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x48, 0x00, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x2d, 0x0a, 0x04, 0x74, 0x79, - 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, - 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x48, 0x00, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x30, 0x0a, 0x05, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, - 0x6c, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x42, 0x0d, 0x0a, 0x0b, 0x61, - 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x3b, 0x0a, 0x0f, 0x54, 0x65, - 0x72, 0x6d, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, - 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, - 0x65, 0x6c, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x22, 0x49, 0x0a, 0x15, 0x50, 0x65, 0x72, 0x63, 0x65, - 0x6e, 0x74, 0x69, 0x6c, 0x65, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, - 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x01, 0x52, 0x08, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, - 0x74, 0x73, 0x22, 0x48, 0x0a, 0x14, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x41, - 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, - 0x65, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, - 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x22, 0x28, 0x0a, 0x10, - 0x46, 0x69, 0x65, 0x6c, 0x64, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x22, 0x27, 0x0a, 0x0f, 0x54, 0x79, 0x70, 0x65, 0x41, 0x67, - 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x65, - 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x22, - 0x12, 0x0a, 0x10, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x22, 0x6c, 0x0a, 0x16, 0x4e, 0x61, 0x6d, 0x65, 0x64, 0x41, 0x67, 0x67, 0x72, - 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x12, 0x0a, + 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x45, 0x0a, 0x0c, 0x41, 0x67, 0x67, 0x72, + 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x35, 0x0a, 0x0c, 0x61, 0x67, 0x67, 0x72, + 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, + 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, + 0x65, 0x52, 0x0c, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, + 0xef, 0x02, 0x0a, 0x09, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x28, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x22, 0x4c, 0x0a, 0x11, 0x48, 0x61, 0x73, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x37, 0x0a, 0x0b, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, - 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x67, 0x72, - 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x48, 0x61, 0x73, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, - 0x6f, 0x6e, 0x52, 0x0b, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, - 0xda, 0x01, 0x0a, 0x0d, 0x48, 0x61, 0x73, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x2d, 0x0a, 0x03, 0x61, 0x6e, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, - 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x48, 0x61, 0x73, 0x45, 0x78, 0x70, 0x72, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x03, 0x61, 0x6e, 0x64, - 0x12, 0x2b, 0x0a, 0x02, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, - 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x48, 0x61, 0x73, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, 0x52, 0x02, 0x6f, 0x72, 0x12, 0x29, 0x0a, - 0x03, 0x6e, 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x67, 0x72, 0x69, - 0x70, 0x71, 0x6c, 0x2e, 0x48, 0x61, 0x73, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x48, 0x00, 0x52, 0x03, 0x6e, 0x6f, 0x74, 0x12, 0x34, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x64, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x72, - 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x48, 0x61, 0x73, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x48, 0x00, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x0c, - 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x7f, 0x0a, 0x0c, - 0x48, 0x61, 0x73, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2f, 0x0a, 0x09, - 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x11, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x27, 0x0a, - 0x0f, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, - 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x05, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x22, 0x63, 0x0a, 0x09, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x56, 0x65, 0x72, - 0x74, 0x65, 0x78, 0x48, 0x00, 0x52, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x12, 0x22, 0x0a, - 0x04, 0x65, 0x64, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x67, 0x72, - 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x64, 0x67, 0x65, 0x48, 0x00, 0x52, 0x04, 0x65, 0x64, 0x67, - 0x65, 0x42, 0x08, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0xa2, 0x01, 0x0a, 0x0a, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x42, 0x0a, 0x0a, 0x73, 0x65, - 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, - 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x2e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x0a, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x50, - 0x0a, 0x0f, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x12, 0x27, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x53, 0x65, 0x6c, 0x65, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, - 0x22, 0x65, 0x0a, 0x04, 0x4a, 0x75, 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6d, 0x61, 0x72, 0x6b, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x61, 0x72, 0x6b, 0x12, 0x35, 0x0a, 0x0a, - 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x15, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x48, 0x61, 0x73, 0x45, 0x78, 0x70, - 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x04, 0x65, 0x6d, 0x69, 0x74, 0x22, 0x45, 0x0a, 0x03, 0x53, 0x65, 0x74, 0x12, 0x10, - 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, - 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x33, - 0x0a, 0x09, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x22, 0x5d, 0x0a, 0x06, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x12, 0x10, 0x0a, - 0x03, 0x67, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x67, 0x69, 0x64, 0x12, - 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x2b, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x04, 0x64, 0x61, - 0x74, 0x61, 0x22, 0x7f, 0x0a, 0x04, 0x45, 0x64, 0x67, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x67, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, - 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, - 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x2b, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x04, 0x64, - 0x61, 0x74, 0x61, 0x22, 0xdd, 0x02, 0x0a, 0x0b, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, - 0x75, 0x6c, 0x74, 0x12, 0x28, 0x0a, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x56, 0x65, 0x72, - 0x74, 0x65, 0x78, 0x48, 0x00, 0x52, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x12, 0x22, 0x0a, - 0x04, 0x65, 0x64, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x67, 0x72, - 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x64, 0x67, 0x65, 0x48, 0x00, 0x52, 0x04, 0x65, 0x64, 0x67, - 0x65, 0x12, 0x44, 0x0a, 0x0c, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, - 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x64, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x61, 0x67, 0x67, 0x72, 0x65, - 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x34, 0x0a, 0x0a, 0x73, 0x65, 0x6c, 0x65, 0x63, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x72, - 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x48, - 0x00, 0x52, 0x0a, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x30, 0x0a, - 0x06, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, - 0x16, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, - 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x30, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x48, 0x00, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x42, 0x08, 0x0a, 0x06, 0x72, 0x65, 0x73, - 0x75, 0x6c, 0x74, 0x22, 0x30, 0x0a, 0x08, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x12, - 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, - 0x14, 0x0a, 0x05, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x67, 0x72, 0x61, 0x70, 0x68, 0x22, 0x68, 0x0a, 0x0b, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x51, - 0x75, 0x65, 0x72, 0x79, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x72, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x72, 0x63, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x67, - 0x72, 0x61, 0x70, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x61, 0x70, - 0x68, 0x12, 0x2c, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x16, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, - 0xbb, 0x01, 0x0a, 0x09, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0e, 0x0a, + 0x65, 0x12, 0x2d, 0x0a, 0x04, 0x74, 0x65, 0x72, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x54, 0x65, 0x72, 0x6d, 0x41, 0x67, 0x67, + 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x04, 0x74, 0x65, 0x72, 0x6d, + 0x12, 0x3f, 0x0a, 0x0a, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x69, 0x6c, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x50, 0x65, + 0x72, 0x63, 0x65, 0x6e, 0x74, 0x69, 0x6c, 0x65, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x0a, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x69, 0x6c, + 0x65, 0x12, 0x3c, 0x0a, 0x09, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x48, 0x69, + 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x09, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x12, + 0x30, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, + 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x41, 0x67, 0x67, + 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x12, 0x2d, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x41, 0x67, 0x67, + 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x12, 0x30, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x18, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x67, + 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x05, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x42, 0x0d, 0x0a, 0x0b, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x22, 0x3b, 0x0a, 0x0f, 0x54, 0x65, 0x72, 0x6d, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, + 0x7a, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x22, 0x49, + 0x0a, 0x15, 0x50, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x69, 0x6c, 0x65, 0x41, 0x67, 0x67, 0x72, + 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x1a, 0x0a, + 0x08, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x01, 0x52, + 0x08, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x48, 0x0a, 0x14, 0x48, 0x69, 0x73, + 0x74, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x76, 0x61, 0x6c, 0x22, 0x28, 0x0a, 0x10, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x41, 0x67, 0x67, 0x72, + 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x22, 0x27, 0x0a, + 0x0f, 0x54, 0x79, 0x70, 0x65, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x22, 0x12, 0x0a, 0x10, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x41, + 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x6c, 0x0a, 0x16, 0x4e, 0x61, + 0x6d, 0x65, 0x64, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x01, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x4c, 0x0a, 0x11, 0x48, 0x61, 0x73, 0x45, + 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x37, 0x0a, + 0x0b, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x48, 0x61, 0x73, 0x45, + 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x65, 0x78, 0x70, 0x72, 0x65, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xda, 0x01, 0x0a, 0x0d, 0x48, 0x61, 0x73, 0x45, 0x78, + 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x0a, 0x03, 0x61, 0x6e, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x48, + 0x61, 0x73, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, + 0x48, 0x00, 0x52, 0x03, 0x61, 0x6e, 0x64, 0x12, 0x2b, 0x0a, 0x02, 0x6f, 0x72, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x48, 0x61, 0x73, + 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x48, 0x00, + 0x52, 0x02, 0x6f, 0x72, 0x12, 0x29, 0x0a, 0x03, 0x6e, 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x48, 0x61, 0x73, 0x45, 0x78, + 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x03, 0x6e, 0x6f, 0x74, 0x12, + 0x34, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x48, 0x61, 0x73, 0x43, + 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x64, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x0c, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, + 0x69, 0x6f, 0x6e, 0x22, 0x7f, 0x0a, 0x0c, 0x48, 0x61, 0x73, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x12, 0x2f, 0x0a, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, + 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x64, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x65, 0x0a, 0x04, 0x4a, 0x75, 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, + 0x6d, 0x61, 0x72, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6d, 0x61, 0x72, 0x6b, + 0x12, 0x35, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x48, 0x61, + 0x73, 0x45, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x65, 0x78, 0x70, + 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x65, 0x6d, 0x69, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x65, 0x6d, 0x69, 0x74, 0x22, 0x45, 0x0a, 0x03, 0x53, + 0x65, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x22, 0x33, 0x0a, 0x09, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x5d, 0x0a, 0x06, 0x56, 0x65, 0x72, 0x74, 0x65, + 0x78, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x67, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x2b, 0x0a, 0x04, 0x64, 0x61, 0x74, + 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, + 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x7f, 0x0a, 0x04, 0x45, 0x64, 0x67, 0x65, 0x12, 0x10, + 0x0a, 0x03, 0x67, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x67, 0x69, 0x64, + 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x2b, 0x0a, 0x04, 0x64, 0x61, + 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, + 0x74, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xa7, 0x02, 0x0a, 0x0b, 0x51, 0x75, 0x65, 0x72, + 0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x28, 0x0a, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, + 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, + 0x2e, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x48, 0x00, 0x52, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, + 0x78, 0x12, 0x22, 0x0a, 0x04, 0x65, 0x64, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x0c, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x64, 0x67, 0x65, 0x48, 0x00, 0x52, + 0x04, 0x65, 0x64, 0x67, 0x65, 0x12, 0x44, 0x0a, 0x0c, 0x61, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x67, 0x72, + 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x64, 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x61, + 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x30, 0x0a, 0x06, 0x72, + 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x16, 0x0a, + 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x00, 0x52, 0x05, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x30, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x48, + 0x00, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x42, 0x08, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x22, 0x30, 0x0a, 0x08, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, - 0x61, 0x70, 0x68, 0x12, 0x26, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x4a, 0x6f, 0x62, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, - 0x74, 0x12, 0x2c, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x16, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x53, - 0x74, 0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, - 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x1c, 0x0a, - 0x0a, 0x45, 0x64, 0x69, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x54, 0x0a, 0x0e, 0x42, - 0x75, 0x6c, 0x6b, 0x45, 0x64, 0x69, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x21, 0x0a, - 0x0c, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x0b, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, - 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x75, 0x6e, - 0x74, 0x22, 0x6e, 0x0a, 0x0c, 0x47, 0x72, 0x61, 0x70, 0x68, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, - 0x74, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x67, 0x72, 0x61, 0x70, 0x68, 0x12, 0x26, 0x0a, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, - 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, - 0x2e, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x52, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x12, - 0x20, 0x0a, 0x04, 0x65, 0x64, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, - 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x64, 0x67, 0x65, 0x52, 0x04, 0x65, 0x64, 0x67, - 0x65, 0x22, 0x1f, 0x0a, 0x07, 0x47, 0x72, 0x61, 0x70, 0x68, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, - 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x61, - 0x70, 0x68, 0x22, 0x31, 0x0a, 0x09, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x12, + 0x61, 0x70, 0x68, 0x22, 0x68, 0x0a, 0x0b, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x51, 0x75, 0x65, + 0x72, 0x79, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x72, 0x63, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x73, 0x72, 0x63, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x61, + 0x70, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x61, 0x70, 0x68, 0x12, + 0x2c, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, + 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0xbb, 0x01, + 0x0a, 0x09, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x61, 0x70, + 0x68, 0x12, 0x26, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x10, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x2c, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, + 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x1c, 0x0a, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x1c, 0x0a, 0x0a, 0x45, + 0x64, 0x69, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x54, 0x0a, 0x0e, 0x42, 0x75, 0x6c, + 0x6b, 0x45, 0x64, 0x69, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x69, + 0x6e, 0x73, 0x65, 0x72, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x0b, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1f, + 0x0a, 0x0b, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x0a, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, + 0x6e, 0x0a, 0x0c, 0x47, 0x72, 0x61, 0x70, 0x68, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, - 0x67, 0x72, 0x61, 0x70, 0x68, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x4b, 0x0a, 0x07, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x49, 0x44, - 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x05, 0x67, 0x72, 0x61, 0x70, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x14, 0x0a, 0x05, - 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x65, - 0x6c, 0x64, 0x22, 0x29, 0x0a, 0x09, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, - 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x07, 0x0a, - 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x2c, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, - 0x61, 0x70, 0x68, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, - 0x67, 0x72, 0x61, 0x70, 0x68, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x67, 0x72, - 0x61, 0x70, 0x68, 0x73, 0x22, 0x40, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x64, 0x69, - 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x69, - 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x67, - 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x49, 0x44, 0x52, 0x07, 0x69, - 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x22, 0x5a, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x61, - 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x0d, - 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x0c, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x4c, 0x61, 0x62, 0x65, 0x6c, - 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x64, 0x67, 0x65, 0x4c, 0x61, 0x62, 0x65, - 0x6c, 0x73, 0x22, 0xc6, 0x01, 0x0a, 0x09, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, - 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, - 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x66, 0x69, - 0x65, 0x6c, 0x64, 0x73, 0x12, 0x39, 0x0a, 0x08, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6d, 0x61, 0x70, - 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, - 0x54, 0x61, 0x62, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x4c, 0x69, 0x6e, 0x6b, 0x4d, 0x61, - 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x6c, 0x69, 0x6e, 0x6b, 0x4d, 0x61, 0x70, 0x1a, - 0x3a, 0x0a, 0x0c, 0x4c, 0x69, 0x6e, 0x6b, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x67, 0x72, 0x61, 0x70, 0x68, 0x12, 0x26, 0x0a, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x56, + 0x65, 0x72, 0x74, 0x65, 0x78, 0x52, 0x06, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x12, 0x20, 0x0a, + 0x04, 0x65, 0x64, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x67, 0x72, + 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x64, 0x67, 0x65, 0x52, 0x04, 0x65, 0x64, 0x67, 0x65, 0x22, + 0x1f, 0x0a, 0x07, 0x47, 0x72, 0x61, 0x70, 0x68, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, 0x61, 0x70, 0x68, + 0x22, 0x31, 0x0a, 0x09, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x12, 0x14, 0x0a, + 0x05, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x22, 0x4b, 0x0a, 0x07, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x49, 0x44, 0x12, 0x14, + 0x0a, 0x05, 0x67, 0x72, 0x61, 0x70, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x69, + 0x65, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x22, 0x29, 0x0a, 0x09, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1c, 0x0a, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x07, 0x0a, 0x05, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x22, 0x2c, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x61, 0x70, + 0x68, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x67, 0x72, 0x61, 0x70, + 0x68, 0x73, 0x22, 0x40, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x65, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x07, 0x69, 0x6e, 0x64, + 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x67, 0x72, 0x69, + 0x70, 0x71, 0x6c, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x49, 0x44, 0x52, 0x07, 0x69, 0x6e, 0x64, + 0x69, 0x63, 0x65, 0x73, 0x22, 0x5a, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x61, 0x62, 0x65, + 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x76, 0x65, + 0x72, 0x74, 0x65, 0x78, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x0c, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, + 0x1f, 0x0a, 0x0b, 0x65, 0x64, 0x67, 0x65, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x64, 0x67, 0x65, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, + 0x22, 0xc6, 0x01, 0x0a, 0x09, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, + 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, + 0x65, 0x6c, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x73, 0x12, 0x39, 0x0a, 0x08, 0x6c, 0x69, 0x6e, 0x6b, 0x5f, 0x6d, 0x61, 0x70, 0x18, 0x04, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x54, 0x61, + 0x62, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x4c, 0x69, 0x6e, 0x6b, 0x4d, 0x61, 0x70, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x6c, 0x69, 0x6e, 0x6b, 0x4d, 0x61, 0x70, 0x1a, 0x3a, 0x0a, + 0x0c, 0x4c, 0x69, 0x6e, 0x6b, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xaf, 0x01, 0x0a, 0x0c, 0x50, 0x6c, + 0x75, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x12, 0x38, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, + 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x1a, 0x39, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xaf, 0x01, 0x0a, 0x0c, - 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x16, 0x0a, 0x06, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x12, 0x38, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, - 0x6c, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x1a, 0x39, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x38, 0x0a, - 0x0c, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x2f, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x44, - 0x72, 0x69, 0x76, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x07, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x73, 0x22, 0x2f, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, - 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x18, 0x0a, 0x07, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x07, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x2a, 0xa2, 0x01, 0x0a, 0x09, 0x43, 0x6f, - 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x0a, 0x11, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, - 0x57, 0x4e, 0x5f, 0x43, 0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x06, - 0x0a, 0x02, 0x45, 0x51, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x4e, 0x45, 0x51, 0x10, 0x02, 0x12, - 0x06, 0x0a, 0x02, 0x47, 0x54, 0x10, 0x03, 0x12, 0x07, 0x0a, 0x03, 0x47, 0x54, 0x45, 0x10, 0x04, - 0x12, 0x06, 0x0a, 0x02, 0x4c, 0x54, 0x10, 0x05, 0x12, 0x07, 0x0a, 0x03, 0x4c, 0x54, 0x45, 0x10, - 0x06, 0x12, 0x0a, 0x0a, 0x06, 0x49, 0x4e, 0x53, 0x49, 0x44, 0x45, 0x10, 0x07, 0x12, 0x0b, 0x0a, - 0x07, 0x4f, 0x55, 0x54, 0x53, 0x49, 0x44, 0x45, 0x10, 0x08, 0x12, 0x0b, 0x0a, 0x07, 0x42, 0x45, - 0x54, 0x57, 0x45, 0x45, 0x4e, 0x10, 0x09, 0x12, 0x0a, 0x0a, 0x06, 0x57, 0x49, 0x54, 0x48, 0x49, - 0x4e, 0x10, 0x0a, 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x49, 0x54, 0x48, 0x4f, 0x55, 0x54, 0x10, 0x0b, - 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x49, 0x4e, 0x53, 0x10, 0x0c, 0x2a, 0x49, - 0x0a, 0x08, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x51, 0x55, - 0x45, 0x55, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x55, 0x4e, 0x4e, 0x49, 0x4e, - 0x47, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x10, - 0x02, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07, - 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x04, 0x2a, 0x4f, 0x0a, 0x09, 0x46, 0x69, 0x65, - 0x6c, 0x64, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, - 0x4e, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, - 0x0b, 0x0a, 0x07, 0x4e, 0x55, 0x4d, 0x45, 0x52, 0x49, 0x43, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, - 0x42, 0x4f, 0x4f, 0x4c, 0x10, 0x03, 0x12, 0x07, 0x0a, 0x03, 0x4d, 0x41, 0x50, 0x10, 0x04, 0x12, - 0x09, 0x0a, 0x05, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 0x05, 0x32, 0xcf, 0x06, 0x0a, 0x05, 0x51, - 0x75, 0x65, 0x72, 0x79, 0x12, 0x5a, 0x0a, 0x09, 0x54, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73, 0x61, - 0x6c, 0x12, 0x12, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x13, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x51, - 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x1c, 0x22, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, - 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x3a, 0x01, 0x2a, 0x30, 0x01, - 0x12, 0x55, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x12, 0x11, 0x2e, - 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, - 0x1a, 0x0e, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, - 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x12, 0x1d, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, - 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x76, 0x65, 0x72, 0x74, - 0x65, 0x78, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0x4f, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x45, 0x64, - 0x67, 0x65, 0x12, 0x11, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x6c, 0x65, 0x6d, - 0x65, 0x6e, 0x74, 0x49, 0x44, 0x1a, 0x0c, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, - 0x64, 0x67, 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, - 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x65, - 0x64, 0x67, 0x65, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0x57, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x54, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x0f, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, - 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x49, 0x44, 0x1a, 0x11, 0x2e, 0x67, 0x72, 0x69, 0x70, - 0x71, 0x6c, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x23, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, - 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x12, 0x4d, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x0f, - 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x49, 0x44, 0x1a, - 0x0d, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x22, 0x20, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, - 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, - 0x12, 0x4f, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x0f, - 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x49, 0x44, 0x1a, - 0x0d, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x22, 0x21, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x12, 0x19, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, - 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, - 0x67, 0x12, 0x4a, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x61, 0x70, 0x68, 0x73, 0x12, - 0x0d, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1a, - 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x61, 0x70, - 0x68, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x11, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x0b, 0x12, 0x09, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x12, 0x5c, 0x0a, - 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x12, 0x0f, 0x2e, 0x67, - 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x49, 0x44, 0x1a, 0x1b, 0x2e, - 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x64, 0x69, 0x63, - 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x19, 0x12, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, - 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x5a, 0x0a, 0x0a, 0x4c, - 0x69, 0x73, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x0f, 0x2e, 0x67, 0x72, 0x69, 0x70, - 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x49, 0x44, 0x1a, 0x1a, 0x2e, 0x67, 0x72, 0x69, - 0x70, 0x71, 0x6c, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x12, 0x17, - 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, - 0x7d, 0x2f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x43, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x54, - 0x61, 0x62, 0x6c, 0x65, 0x73, 0x12, 0x0d, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, - 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x11, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x54, 0x61, - 0x62, 0x6c, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x11, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0b, 0x12, - 0x09, 0x2f, 0x76, 0x31, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x30, 0x01, 0x32, 0xed, 0x04, 0x0a, - 0x03, 0x4a, 0x6f, 0x62, 0x12, 0x50, 0x0a, 0x06, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x12, 0x12, - 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x51, 0x75, 0x65, - 0x72, 0x79, 0x1a, 0x10, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x4a, 0x6f, 0x62, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x22, 0x15, 0x2f, 0x76, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x38, 0x0a, 0x0c, 0x50, + 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x2f, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x72, 0x69, + 0x76, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x64, + 0x72, 0x69, 0x76, 0x65, 0x72, 0x73, 0x22, 0x2f, 0x0a, 0x13, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6c, + 0x75, 0x67, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, + 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x2a, 0xa2, 0x01, 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x64, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x0a, 0x11, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, + 0x5f, 0x43, 0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x06, 0x0a, 0x02, + 0x45, 0x51, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x4e, 0x45, 0x51, 0x10, 0x02, 0x12, 0x06, 0x0a, + 0x02, 0x47, 0x54, 0x10, 0x03, 0x12, 0x07, 0x0a, 0x03, 0x47, 0x54, 0x45, 0x10, 0x04, 0x12, 0x06, + 0x0a, 0x02, 0x4c, 0x54, 0x10, 0x05, 0x12, 0x07, 0x0a, 0x03, 0x4c, 0x54, 0x45, 0x10, 0x06, 0x12, + 0x0a, 0x0a, 0x06, 0x49, 0x4e, 0x53, 0x49, 0x44, 0x45, 0x10, 0x07, 0x12, 0x0b, 0x0a, 0x07, 0x4f, + 0x55, 0x54, 0x53, 0x49, 0x44, 0x45, 0x10, 0x08, 0x12, 0x0b, 0x0a, 0x07, 0x42, 0x45, 0x54, 0x57, + 0x45, 0x45, 0x4e, 0x10, 0x09, 0x12, 0x0a, 0x0a, 0x06, 0x57, 0x49, 0x54, 0x48, 0x49, 0x4e, 0x10, + 0x0a, 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x49, 0x54, 0x48, 0x4f, 0x55, 0x54, 0x10, 0x0b, 0x12, 0x0c, + 0x0a, 0x08, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x49, 0x4e, 0x53, 0x10, 0x0c, 0x2a, 0x49, 0x0a, 0x08, + 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x51, 0x55, 0x45, 0x55, + 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x55, 0x4e, 0x4e, 0x49, 0x4e, 0x47, 0x10, + 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x02, 0x12, + 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, + 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x04, 0x2a, 0x4f, 0x0a, 0x09, 0x46, 0x69, 0x65, 0x6c, 0x64, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, + 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x0b, 0x0a, + 0x07, 0x4e, 0x55, 0x4d, 0x45, 0x52, 0x49, 0x43, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x42, 0x4f, + 0x4f, 0x4c, 0x10, 0x03, 0x12, 0x07, 0x0a, 0x03, 0x4d, 0x41, 0x50, 0x10, 0x04, 0x12, 0x09, 0x0a, + 0x05, 0x41, 0x52, 0x52, 0x41, 0x59, 0x10, 0x05, 0x32, 0xcf, 0x06, 0x0a, 0x05, 0x51, 0x75, 0x65, + 0x72, 0x79, 0x12, 0x5a, 0x0a, 0x09, 0x54, 0x72, 0x61, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, 0x12, + 0x12, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x1a, 0x13, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x51, 0x75, 0x65, + 0x72, 0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, + 0x22, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, + 0x70, 0x68, 0x7d, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x3a, 0x01, 0x2a, 0x30, 0x01, 0x12, 0x55, + 0x0a, 0x09, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x12, 0x11, 0x2e, 0x67, 0x72, + 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x1a, 0x0e, + 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x22, 0x25, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x12, 0x1d, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, + 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, + 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0x4f, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x45, 0x64, 0x67, 0x65, + 0x12, 0x11, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, + 0x74, 0x49, 0x44, 0x1a, 0x0c, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x64, 0x67, + 0x65, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x65, 0x64, 0x67, + 0x65, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0x57, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x54, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x0f, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, + 0x47, 0x72, 0x61, 0x70, 0x68, 0x49, 0x44, 0x1a, 0x11, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x1d, 0x12, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, + 0x4d, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x0f, 0x2e, 0x67, + 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x49, 0x44, 0x1a, 0x0d, 0x2e, + 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x22, 0x20, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x1a, 0x12, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, + 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x4f, + 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x0f, 0x2e, 0x67, + 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x49, 0x44, 0x1a, 0x0d, 0x2e, + 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x22, 0x21, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x1b, 0x12, 0x19, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, + 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, + 0x4a, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x61, 0x70, 0x68, 0x73, 0x12, 0x0d, 0x2e, + 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1a, 0x2e, 0x67, + 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x47, 0x72, 0x61, 0x70, 0x68, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x11, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0b, + 0x12, 0x09, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x12, 0x5c, 0x0a, 0x0b, 0x4c, + 0x69, 0x73, 0x74, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, 0x12, 0x0f, 0x2e, 0x67, 0x72, 0x69, + 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x49, 0x44, 0x1a, 0x1b, 0x2e, 0x67, 0x72, + 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x6e, 0x64, 0x69, 0x63, 0x65, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, + 0x12, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, + 0x70, 0x68, 0x7d, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x5a, 0x0a, 0x0a, 0x4c, 0x69, 0x73, + 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x0f, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, + 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x49, 0x44, 0x1a, 0x1a, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, + 0x6c, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, - 0x6a, 0x6f, 0x62, 0x3a, 0x01, 0x2a, 0x12, 0x4e, 0x0a, 0x08, 0x4c, 0x69, 0x73, 0x74, 0x4a, 0x6f, - 0x62, 0x73, 0x12, 0x0f, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, - 0x68, 0x49, 0x44, 0x1a, 0x10, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x51, 0x75, 0x65, - 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, - 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, - 0x2f, 0x6a, 0x6f, 0x62, 0x30, 0x01, 0x12, 0x5e, 0x0a, 0x0a, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x4a, 0x6f, 0x62, 0x73, 0x12, 0x12, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, - 0x61, 0x70, 0x68, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x11, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, - 0x6c, 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x27, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x21, 0x22, 0x1c, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, - 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, - 0x68, 0x3a, 0x01, 0x2a, 0x30, 0x01, 0x12, 0x54, 0x0a, 0x09, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, - 0x4a, 0x6f, 0x62, 0x12, 0x10, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x51, 0x75, 0x65, - 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x1a, 0x11, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x4a, - 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, - 0x2a, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, - 0x70, 0x68, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0x51, 0x0a, 0x06, - 0x47, 0x65, 0x74, 0x4a, 0x6f, 0x62, 0x12, 0x10, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x1a, 0x11, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, - 0x6c, 0x2e, 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x22, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x1c, 0x12, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, - 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, - 0x59, 0x0a, 0x07, 0x56, 0x69, 0x65, 0x77, 0x4a, 0x6f, 0x62, 0x12, 0x10, 0x2e, 0x67, 0x72, 0x69, - 0x70, 0x71, 0x6c, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x1a, 0x13, 0x2e, 0x67, - 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x22, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x67, - 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, - 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x01, 0x2a, 0x30, 0x01, 0x12, 0x60, 0x0a, 0x09, 0x52, 0x65, - 0x73, 0x75, 0x6d, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x13, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, - 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x13, 0x2e, 0x67, - 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x22, 0x27, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x21, 0x22, 0x1c, 0x2f, 0x76, 0x31, 0x2f, 0x67, - 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, - 0x2d, 0x72, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x3a, 0x01, 0x2a, 0x30, 0x01, 0x32, 0xaa, 0x08, 0x0a, - 0x04, 0x45, 0x64, 0x69, 0x74, 0x12, 0x5f, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x56, 0x65, 0x72, 0x74, - 0x65, 0x78, 0x12, 0x14, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, - 0x68, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x1a, 0x12, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, - 0x6c, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x28, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x22, 0x22, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, - 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x3a, 0x06, - 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x12, 0x59, 0x0a, 0x07, 0x41, 0x64, 0x64, 0x45, 0x64, 0x67, - 0x65, 0x12, 0x14, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, - 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x1a, 0x12, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, - 0x2e, 0x45, 0x64, 0x69, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x24, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x1e, 0x22, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, - 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x65, 0x64, 0x67, 0x65, 0x3a, 0x04, 0x65, 0x64, 0x67, - 0x65, 0x12, 0x4c, 0x0a, 0x07, 0x42, 0x75, 0x6c, 0x6b, 0x41, 0x64, 0x64, 0x12, 0x14, 0x2e, 0x67, - 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x45, 0x6c, 0x65, 0x6d, 0x65, - 0x6e, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x42, 0x75, 0x6c, 0x6b, - 0x45, 0x64, 0x69, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x11, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x0b, 0x22, 0x09, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x28, 0x01, 0x12, - 0x4a, 0x0a, 0x08, 0x41, 0x64, 0x64, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x0f, 0x2e, 0x67, 0x72, - 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x49, 0x44, 0x1a, 0x12, 0x2e, 0x67, - 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x22, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, - 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x12, 0x4d, 0x0a, 0x0b, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x0f, 0x2e, 0x67, 0x72, 0x69, - 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x49, 0x44, 0x1a, 0x12, 0x2e, 0x67, 0x72, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x43, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x54, 0x61, 0x62, + 0x6c, 0x65, 0x73, 0x12, 0x0d, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x1a, 0x11, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x54, 0x61, 0x62, 0x6c, + 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x11, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0b, 0x12, 0x09, 0x2f, + 0x76, 0x31, 0x2f, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x30, 0x01, 0x32, 0xed, 0x04, 0x0a, 0x03, 0x4a, + 0x6f, 0x62, 0x12, 0x50, 0x0a, 0x06, 0x53, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x12, 0x12, 0x2e, 0x67, + 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x1a, 0x10, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4a, + 0x6f, 0x62, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, + 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x6a, 0x6f, + 0x62, 0x3a, 0x01, 0x2a, 0x12, 0x4e, 0x0a, 0x08, 0x4c, 0x69, 0x73, 0x74, 0x4a, 0x6f, 0x62, 0x73, + 0x12, 0x0f, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x49, + 0x44, 0x1a, 0x10, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x4a, 0x6f, 0x62, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x76, 0x31, + 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x6a, + 0x6f, 0x62, 0x30, 0x01, 0x12, 0x5e, 0x0a, 0x0a, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4a, 0x6f, + 0x62, 0x73, 0x12, 0x12, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, + 0x68, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x11, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, + 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x27, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x21, 0x22, 0x1c, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2d, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x3a, + 0x01, 0x2a, 0x30, 0x01, 0x12, 0x54, 0x0a, 0x09, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4a, 0x6f, + 0x62, 0x12, 0x10, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, + 0x4a, 0x6f, 0x62, 0x1a, 0x11, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x4a, 0x6f, 0x62, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x2a, 0x1a, + 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, + 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0x51, 0x0a, 0x06, 0x47, 0x65, + 0x74, 0x4a, 0x6f, 0x62, 0x12, 0x10, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x1a, 0x11, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, + 0x4a, 0x6f, 0x62, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x1c, 0x12, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0x59, 0x0a, + 0x07, 0x56, 0x69, 0x65, 0x77, 0x4a, 0x6f, 0x62, 0x12, 0x10, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, + 0x6c, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4a, 0x6f, 0x62, 0x1a, 0x13, 0x2e, 0x67, 0x72, 0x69, + 0x70, 0x71, 0x6c, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, + 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x22, 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, + 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2f, 0x7b, + 0x69, 0x64, 0x7d, 0x3a, 0x01, 0x2a, 0x30, 0x01, 0x12, 0x60, 0x0a, 0x09, 0x52, 0x65, 0x73, 0x75, + 0x6d, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x13, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, + 0x78, 0x74, 0x65, 0x6e, 0x64, 0x51, 0x75, 0x65, 0x72, 0x79, 0x1a, 0x13, 0x2e, 0x67, 0x72, 0x69, + 0x70, 0x71, 0x6c, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, + 0x27, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x21, 0x22, 0x1c, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, + 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x6a, 0x6f, 0x62, 0x2d, 0x72, + 0x65, 0x73, 0x75, 0x6d, 0x65, 0x3a, 0x01, 0x2a, 0x30, 0x01, 0x32, 0xaa, 0x08, 0x0a, 0x04, 0x45, + 0x64, 0x69, 0x74, 0x12, 0x5f, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, + 0x12, 0x14, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x45, + 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x1a, 0x12, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, + 0x45, 0x64, 0x69, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x28, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x22, 0x22, 0x18, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x76, 0x65, 0x72, 0x74, 0x65, 0x78, 0x3a, 0x06, 0x76, 0x65, + 0x72, 0x74, 0x65, 0x78, 0x12, 0x59, 0x0a, 0x07, 0x41, 0x64, 0x64, 0x45, 0x64, 0x67, 0x65, 0x12, + 0x14, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x45, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x1a, 0x12, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, + 0x64, 0x69, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x1e, 0x22, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x65, 0x64, 0x67, 0x65, 0x3a, 0x04, 0x65, 0x64, 0x67, 0x65, 0x12, + 0x4c, 0x0a, 0x07, 0x42, 0x75, 0x6c, 0x6b, 0x41, 0x64, 0x64, 0x12, 0x14, 0x2e, 0x67, 0x72, 0x69, + 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x1a, 0x16, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x42, 0x75, 0x6c, 0x6b, 0x45, 0x64, + 0x69, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x11, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0b, + 0x22, 0x09, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x28, 0x01, 0x12, 0x4a, 0x0a, + 0x08, 0x41, 0x64, 0x64, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x0f, 0x2e, 0x67, 0x72, 0x69, 0x70, + 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x49, 0x44, 0x1a, 0x12, 0x2e, 0x67, 0x72, 0x69, + 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x19, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x22, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, + 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x12, 0x4d, 0x0a, 0x0b, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x47, 0x72, 0x61, 0x70, 0x68, 0x12, 0x0f, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, + 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x49, 0x44, 0x1a, 0x12, 0x2e, 0x67, 0x72, 0x69, 0x70, + 0x71, 0x6c, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x19, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x2a, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, + 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x12, 0x5c, 0x0a, 0x0c, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x12, 0x11, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, + 0x6c, 0x2e, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x1a, 0x12, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, - 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x2a, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, - 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x12, 0x5c, 0x0a, 0x0c, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78, 0x12, 0x11, 0x2e, 0x67, 0x72, 0x69, - 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x1a, 0x12, 0x2e, + 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x2a, 0x1d, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, + 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x76, 0x65, 0x72, 0x74, 0x65, + 0x78, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0x58, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x45, 0x64, 0x67, 0x65, 0x12, 0x11, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x1a, 0x12, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, + 0x2e, 0x45, 0x64, 0x69, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x23, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x1d, 0x2a, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, + 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x65, 0x64, 0x67, 0x65, 0x2f, 0x7b, 0x69, 0x64, 0x7d, + 0x12, 0x5b, 0x0a, 0x08, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x0f, 0x2e, 0x67, + 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x49, 0x44, 0x1a, 0x12, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x2a, 0x1d, 0x2f, 0x76, 0x31, 0x2f, 0x67, - 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x76, 0x65, 0x72, - 0x74, 0x65, 0x78, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x12, 0x58, 0x0a, 0x0a, 0x44, 0x65, 0x6c, 0x65, - 0x74, 0x65, 0x45, 0x64, 0x67, 0x65, 0x12, 0x11, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, - 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x44, 0x1a, 0x12, 0x2e, 0x67, 0x72, 0x69, 0x70, - 0x71, 0x6c, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x23, 0x82, - 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x2a, 0x1b, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, - 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x65, 0x64, 0x67, 0x65, 0x2f, 0x7b, 0x69, - 0x64, 0x7d, 0x12, 0x5b, 0x0a, 0x08, 0x41, 0x64, 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x0f, - 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x49, 0x44, 0x1a, - 0x12, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x52, 0x65, 0x73, - 0x75, 0x6c, 0x74, 0x22, 0x2a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x22, 0x1f, 0x2f, 0x76, 0x31, - 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x69, - 0x6e, 0x64, 0x65, 0x78, 0x2f, 0x7b, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x7d, 0x3a, 0x01, 0x2a, 0x12, - 0x63, 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x0f, - 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x49, 0x44, 0x1a, - 0x12, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x52, 0x65, 0x73, - 0x75, 0x6c, 0x74, 0x22, 0x2f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x29, 0x2a, 0x27, 0x2f, 0x76, 0x31, - 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x69, - 0x6e, 0x64, 0x65, 0x78, 0x2f, 0x7b, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x7d, 0x2f, 0x7b, 0x66, 0x69, - 0x65, 0x6c, 0x64, 0x7d, 0x12, 0x53, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x53, 0x63, 0x68, 0x65, 0x6d, - 0x61, 0x12, 0x0d, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, - 0x1a, 0x12, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x52, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x22, 0x18, 0x2f, 0x76, - 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, - 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x3a, 0x01, 0x2a, 0x12, 0x57, 0x0a, 0x0c, 0x53, 0x61, 0x6d, - 0x70, 0x6c, 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x0f, 0x2e, 0x67, 0x72, 0x69, 0x70, - 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x49, 0x44, 0x1a, 0x0d, 0x2e, 0x67, 0x72, 0x69, - 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x22, 0x27, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x21, 0x12, 0x1f, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, - 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2d, 0x73, 0x61, 0x6d, 0x70, - 0x6c, 0x65, 0x12, 0x55, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, - 0x12, 0x0d, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x1a, - 0x12, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x52, 0x65, 0x73, - 0x75, 0x6c, 0x74, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x22, 0x19, 0x2f, 0x76, 0x31, - 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x6d, - 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x3a, 0x01, 0x2a, 0x32, 0x82, 0x02, 0x0a, 0x09, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x12, 0x57, 0x0a, 0x0b, 0x53, 0x74, 0x61, 0x72, 0x74, - 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x14, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, - 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x14, 0x2e, 0x67, - 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x22, 0x11, 0x2f, 0x76, 0x31, 0x2f, - 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x3a, 0x01, 0x2a, - 0x12, 0x4d, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x12, - 0x0d, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1b, - 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6c, 0x75, 0x67, - 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x12, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x0c, 0x12, 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, - 0x4d, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x73, 0x12, 0x0d, - 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1b, 0x2e, - 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x72, 0x69, 0x76, 0x65, - 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x0c, 0x12, 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x42, 0x1d, - 0x5a, 0x1b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x6d, 0x65, - 0x67, 0x2f, 0x67, 0x72, 0x69, 0x70, 0x2f, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x22, 0x2a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x24, 0x22, 0x1f, 0x2f, 0x76, 0x31, 0x2f, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x2f, 0x7b, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x7d, 0x3a, 0x01, 0x2a, 0x12, 0x63, 0x0a, + 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x0f, 0x2e, 0x67, + 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x49, 0x44, 0x1a, 0x12, 0x2e, + 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x22, 0x2f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x29, 0x2a, 0x27, 0x2f, 0x76, 0x31, 0x2f, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x69, 0x6e, 0x64, + 0x65, 0x78, 0x2f, 0x7b, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x7d, 0x2f, 0x7b, 0x66, 0x69, 0x65, 0x6c, + 0x64, 0x7d, 0x12, 0x53, 0x0a, 0x09, 0x41, 0x64, 0x64, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, + 0x0d, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x1a, 0x12, + 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x52, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x22, 0x23, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x22, 0x18, 0x2f, 0x76, 0x31, 0x2f, + 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x73, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x3a, 0x01, 0x2a, 0x12, 0x57, 0x0a, 0x0c, 0x53, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x0f, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, + 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x49, 0x44, 0x1a, 0x0d, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, + 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x22, 0x27, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x21, 0x12, + 0x1f, 0x2f, 0x76, 0x31, 0x2f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, + 0x68, 0x7d, 0x2f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2d, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x12, 0x55, 0x0a, 0x0a, 0x41, 0x64, 0x64, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x0d, + 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x47, 0x72, 0x61, 0x70, 0x68, 0x1a, 0x12, 0x2e, + 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x64, 0x69, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x22, 0x19, 0x2f, 0x76, 0x31, 0x2f, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x2f, 0x7b, 0x67, 0x72, 0x61, 0x70, 0x68, 0x7d, 0x2f, 0x6d, 0x61, 0x70, + 0x70, 0x69, 0x6e, 0x67, 0x3a, 0x01, 0x2a, 0x32, 0x82, 0x02, 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x75, 0x72, 0x65, 0x12, 0x57, 0x0a, 0x0b, 0x53, 0x74, 0x61, 0x72, 0x74, 0x50, 0x6c, + 0x75, 0x67, 0x69, 0x6e, 0x12, 0x14, 0x2e, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x50, 0x6c, + 0x75, 0x67, 0x69, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x14, 0x2e, 0x67, 0x72, 0x69, + 0x70, 0x71, 0x6c, 0x2e, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x22, 0x1c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x22, 0x11, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x6c, + 0x75, 0x67, 0x69, 0x6e, 0x2f, 0x7b, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x3a, 0x01, 0x2a, 0x12, 0x4d, + 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x12, 0x0d, 0x2e, + 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1b, 0x2e, 0x67, + 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x0c, 0x12, 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x12, 0x4d, 0x0a, + 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x73, 0x12, 0x0d, 0x2e, 0x67, + 0x72, 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1b, 0x2e, 0x67, 0x72, + 0x69, 0x70, 0x71, 0x6c, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, + 0x12, 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x72, 0x69, 0x76, 0x65, 0x72, 0x42, 0x1d, 0x5a, 0x1b, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x62, 0x6d, 0x65, 0x67, 0x2f, + 0x67, 0x72, 0x69, 0x70, 0x2f, 0x67, 0x72, 0x69, 0x70, 0x71, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -4038,7 +3825,7 @@ func file_gripql_proto_rawDescGZIP() []byte { } var file_gripql_proto_enumTypes = make([]protoimpl.EnumInfo, 3) -var file_gripql_proto_msgTypes = make([]protoimpl.MessageInfo, 49) +var file_gripql_proto_msgTypes = make([]protoimpl.MessageInfo, 45) var file_gripql_proto_goTypes = []interface{}{ (Condition)(0), // 0: gripql.Condition (JobState)(0), // 1: gripql.JobState @@ -4061,179 +3848,169 @@ var file_gripql_proto_goTypes = []interface{}{ (*HasExpressionList)(nil), // 18: gripql.HasExpressionList (*HasExpression)(nil), // 19: gripql.HasExpression (*HasCondition)(nil), // 20: gripql.HasCondition - (*SelectStatement)(nil), // 21: gripql.SelectStatement - (*Selection)(nil), // 22: gripql.Selection - (*Selections)(nil), // 23: gripql.Selections - (*Jump)(nil), // 24: gripql.Jump - (*Set)(nil), // 25: gripql.Set - (*Increment)(nil), // 26: gripql.Increment - (*Vertex)(nil), // 27: gripql.Vertex - (*Edge)(nil), // 28: gripql.Edge - (*QueryResult)(nil), // 29: gripql.QueryResult - (*QueryJob)(nil), // 30: gripql.QueryJob - (*ExtendQuery)(nil), // 31: gripql.ExtendQuery - (*JobStatus)(nil), // 32: gripql.JobStatus - (*EditResult)(nil), // 33: gripql.EditResult - (*BulkEditResult)(nil), // 34: gripql.BulkEditResult - (*GraphElement)(nil), // 35: gripql.GraphElement - (*GraphID)(nil), // 36: gripql.GraphID - (*ElementID)(nil), // 37: gripql.ElementID - (*IndexID)(nil), // 38: gripql.IndexID - (*Timestamp)(nil), // 39: gripql.Timestamp - (*Empty)(nil), // 40: gripql.Empty - (*ListGraphsResponse)(nil), // 41: gripql.ListGraphsResponse - (*ListIndicesResponse)(nil), // 42: gripql.ListIndicesResponse - (*ListLabelsResponse)(nil), // 43: gripql.ListLabelsResponse - (*TableInfo)(nil), // 44: gripql.TableInfo - (*PluginConfig)(nil), // 45: gripql.PluginConfig - (*PluginStatus)(nil), // 46: gripql.PluginStatus - (*ListDriversResponse)(nil), // 47: gripql.ListDriversResponse - (*ListPluginsResponse)(nil), // 48: gripql.ListPluginsResponse - nil, // 49: gripql.Selections.SelectionsEntry - nil, // 50: gripql.TableInfo.LinkMapEntry - nil, // 51: gripql.PluginConfig.ConfigEntry - (*structpb.ListValue)(nil), // 52: google.protobuf.ListValue - (*structpb.Value)(nil), // 53: google.protobuf.Value - (*structpb.Struct)(nil), // 54: google.protobuf.Struct + (*Jump)(nil), // 21: gripql.Jump + (*Set)(nil), // 22: gripql.Set + (*Increment)(nil), // 23: gripql.Increment + (*Vertex)(nil), // 24: gripql.Vertex + (*Edge)(nil), // 25: gripql.Edge + (*QueryResult)(nil), // 26: gripql.QueryResult + (*QueryJob)(nil), // 27: gripql.QueryJob + (*ExtendQuery)(nil), // 28: gripql.ExtendQuery + (*JobStatus)(nil), // 29: gripql.JobStatus + (*EditResult)(nil), // 30: gripql.EditResult + (*BulkEditResult)(nil), // 31: gripql.BulkEditResult + (*GraphElement)(nil), // 32: gripql.GraphElement + (*GraphID)(nil), // 33: gripql.GraphID + (*ElementID)(nil), // 34: gripql.ElementID + (*IndexID)(nil), // 35: gripql.IndexID + (*Timestamp)(nil), // 36: gripql.Timestamp + (*Empty)(nil), // 37: gripql.Empty + (*ListGraphsResponse)(nil), // 38: gripql.ListGraphsResponse + (*ListIndicesResponse)(nil), // 39: gripql.ListIndicesResponse + (*ListLabelsResponse)(nil), // 40: gripql.ListLabelsResponse + (*TableInfo)(nil), // 41: gripql.TableInfo + (*PluginConfig)(nil), // 42: gripql.PluginConfig + (*PluginStatus)(nil), // 43: gripql.PluginStatus + (*ListDriversResponse)(nil), // 44: gripql.ListDriversResponse + (*ListPluginsResponse)(nil), // 45: gripql.ListPluginsResponse + nil, // 46: gripql.TableInfo.LinkMapEntry + nil, // 47: gripql.PluginConfig.ConfigEntry + (*structpb.ListValue)(nil), // 48: google.protobuf.ListValue + (*structpb.Value)(nil), // 49: google.protobuf.Value + (*structpb.Struct)(nil), // 50: google.protobuf.Struct } var file_gripql_proto_depIdxs = []int32{ - 27, // 0: gripql.Graph.vertices:type_name -> gripql.Vertex - 28, // 1: gripql.Graph.edges:type_name -> gripql.Edge - 6, // 2: gripql.GraphQuery.query:type_name -> gripql.GraphStatement - 6, // 3: gripql.QuerySet.query:type_name -> gripql.GraphStatement - 52, // 4: gripql.GraphStatement.v:type_name -> google.protobuf.ListValue - 52, // 5: gripql.GraphStatement.e:type_name -> google.protobuf.ListValue - 52, // 6: gripql.GraphStatement.in:type_name -> google.protobuf.ListValue - 52, // 7: gripql.GraphStatement.out:type_name -> google.protobuf.ListValue - 52, // 8: gripql.GraphStatement.both:type_name -> google.protobuf.ListValue - 52, // 9: gripql.GraphStatement.in_e:type_name -> google.protobuf.ListValue - 52, // 10: gripql.GraphStatement.out_e:type_name -> google.protobuf.ListValue - 52, // 11: gripql.GraphStatement.both_e:type_name -> google.protobuf.ListValue - 52, // 12: gripql.GraphStatement.in_null:type_name -> google.protobuf.ListValue - 52, // 13: gripql.GraphStatement.out_null:type_name -> google.protobuf.ListValue - 52, // 14: gripql.GraphStatement.in_e_null:type_name -> google.protobuf.ListValue - 52, // 15: gripql.GraphStatement.out_e_null:type_name -> google.protobuf.ListValue - 21, // 16: gripql.GraphStatement.select:type_name -> gripql.SelectStatement - 7, // 17: gripql.GraphStatement.range:type_name -> gripql.Range - 19, // 18: gripql.GraphStatement.has:type_name -> gripql.HasExpression - 52, // 19: gripql.GraphStatement.has_label:type_name -> google.protobuf.ListValue - 52, // 20: gripql.GraphStatement.has_key:type_name -> google.protobuf.ListValue - 52, // 21: gripql.GraphStatement.has_id:type_name -> google.protobuf.ListValue - 52, // 22: gripql.GraphStatement.distinct:type_name -> google.protobuf.ListValue - 52, // 23: gripql.GraphStatement.fields:type_name -> google.protobuf.ListValue - 9, // 24: gripql.GraphStatement.aggregate:type_name -> gripql.Aggregations - 53, // 25: gripql.GraphStatement.render:type_name -> google.protobuf.Value - 52, // 26: gripql.GraphStatement.path:type_name -> google.protobuf.ListValue - 24, // 27: gripql.GraphStatement.jump:type_name -> gripql.Jump - 25, // 28: gripql.GraphStatement.set:type_name -> gripql.Set - 26, // 29: gripql.GraphStatement.increment:type_name -> gripql.Increment - 10, // 30: gripql.AggregationsRequest.aggregations:type_name -> gripql.Aggregate - 10, // 31: gripql.Aggregations.aggregations:type_name -> gripql.Aggregate - 11, // 32: gripql.Aggregate.term:type_name -> gripql.TermAggregation - 12, // 33: gripql.Aggregate.percentile:type_name -> gripql.PercentileAggregation - 13, // 34: gripql.Aggregate.histogram:type_name -> gripql.HistogramAggregation - 14, // 35: gripql.Aggregate.field:type_name -> gripql.FieldAggregation - 15, // 36: gripql.Aggregate.type:type_name -> gripql.TypeAggregation - 16, // 37: gripql.Aggregate.count:type_name -> gripql.CountAggregation - 53, // 38: gripql.NamedAggregationResult.key:type_name -> google.protobuf.Value - 19, // 39: gripql.HasExpressionList.expressions:type_name -> gripql.HasExpression - 18, // 40: gripql.HasExpression.and:type_name -> gripql.HasExpressionList - 18, // 41: gripql.HasExpression.or:type_name -> gripql.HasExpressionList - 19, // 42: gripql.HasExpression.not:type_name -> gripql.HasExpression - 20, // 43: gripql.HasExpression.condition:type_name -> gripql.HasCondition - 53, // 44: gripql.HasCondition.value:type_name -> google.protobuf.Value - 0, // 45: gripql.HasCondition.condition:type_name -> gripql.Condition - 27, // 46: gripql.Selection.vertex:type_name -> gripql.Vertex - 28, // 47: gripql.Selection.edge:type_name -> gripql.Edge - 49, // 48: gripql.Selections.selections:type_name -> gripql.Selections.SelectionsEntry - 19, // 49: gripql.Jump.expression:type_name -> gripql.HasExpression - 53, // 50: gripql.Set.value:type_name -> google.protobuf.Value - 54, // 51: gripql.Vertex.data:type_name -> google.protobuf.Struct - 54, // 52: gripql.Edge.data:type_name -> google.protobuf.Struct - 27, // 53: gripql.QueryResult.vertex:type_name -> gripql.Vertex - 28, // 54: gripql.QueryResult.edge:type_name -> gripql.Edge - 17, // 55: gripql.QueryResult.aggregations:type_name -> gripql.NamedAggregationResult - 23, // 56: gripql.QueryResult.selections:type_name -> gripql.Selections - 53, // 57: gripql.QueryResult.render:type_name -> google.protobuf.Value - 52, // 58: gripql.QueryResult.path:type_name -> google.protobuf.ListValue - 6, // 59: gripql.ExtendQuery.query:type_name -> gripql.GraphStatement - 1, // 60: gripql.JobStatus.state:type_name -> gripql.JobState - 6, // 61: gripql.JobStatus.query:type_name -> gripql.GraphStatement - 27, // 62: gripql.GraphElement.vertex:type_name -> gripql.Vertex - 28, // 63: gripql.GraphElement.edge:type_name -> gripql.Edge - 38, // 64: gripql.ListIndicesResponse.indices:type_name -> gripql.IndexID - 50, // 65: gripql.TableInfo.link_map:type_name -> gripql.TableInfo.LinkMapEntry - 51, // 66: gripql.PluginConfig.config:type_name -> gripql.PluginConfig.ConfigEntry - 22, // 67: gripql.Selections.SelectionsEntry.value:type_name -> gripql.Selection - 4, // 68: gripql.Query.Traversal:input_type -> gripql.GraphQuery - 37, // 69: gripql.Query.GetVertex:input_type -> gripql.ElementID - 37, // 70: gripql.Query.GetEdge:input_type -> gripql.ElementID - 36, // 71: gripql.Query.GetTimestamp:input_type -> gripql.GraphID - 36, // 72: gripql.Query.GetSchema:input_type -> gripql.GraphID - 36, // 73: gripql.Query.GetMapping:input_type -> gripql.GraphID - 40, // 74: gripql.Query.ListGraphs:input_type -> gripql.Empty - 36, // 75: gripql.Query.ListIndices:input_type -> gripql.GraphID - 36, // 76: gripql.Query.ListLabels:input_type -> gripql.GraphID - 40, // 77: gripql.Query.ListTables:input_type -> gripql.Empty - 4, // 78: gripql.Job.Submit:input_type -> gripql.GraphQuery - 36, // 79: gripql.Job.ListJobs:input_type -> gripql.GraphID - 4, // 80: gripql.Job.SearchJobs:input_type -> gripql.GraphQuery - 30, // 81: gripql.Job.DeleteJob:input_type -> gripql.QueryJob - 30, // 82: gripql.Job.GetJob:input_type -> gripql.QueryJob - 30, // 83: gripql.Job.ViewJob:input_type -> gripql.QueryJob - 31, // 84: gripql.Job.ResumeJob:input_type -> gripql.ExtendQuery - 35, // 85: gripql.Edit.AddVertex:input_type -> gripql.GraphElement - 35, // 86: gripql.Edit.AddEdge:input_type -> gripql.GraphElement - 35, // 87: gripql.Edit.BulkAdd:input_type -> gripql.GraphElement - 36, // 88: gripql.Edit.AddGraph:input_type -> gripql.GraphID - 36, // 89: gripql.Edit.DeleteGraph:input_type -> gripql.GraphID - 37, // 90: gripql.Edit.DeleteVertex:input_type -> gripql.ElementID - 37, // 91: gripql.Edit.DeleteEdge:input_type -> gripql.ElementID - 38, // 92: gripql.Edit.AddIndex:input_type -> gripql.IndexID - 38, // 93: gripql.Edit.DeleteIndex:input_type -> gripql.IndexID - 3, // 94: gripql.Edit.AddSchema:input_type -> gripql.Graph - 36, // 95: gripql.Edit.SampleSchema:input_type -> gripql.GraphID - 3, // 96: gripql.Edit.AddMapping:input_type -> gripql.Graph - 45, // 97: gripql.Configure.StartPlugin:input_type -> gripql.PluginConfig - 40, // 98: gripql.Configure.ListPlugins:input_type -> gripql.Empty - 40, // 99: gripql.Configure.ListDrivers:input_type -> gripql.Empty - 29, // 100: gripql.Query.Traversal:output_type -> gripql.QueryResult - 27, // 101: gripql.Query.GetVertex:output_type -> gripql.Vertex - 28, // 102: gripql.Query.GetEdge:output_type -> gripql.Edge - 39, // 103: gripql.Query.GetTimestamp:output_type -> gripql.Timestamp - 3, // 104: gripql.Query.GetSchema:output_type -> gripql.Graph - 3, // 105: gripql.Query.GetMapping:output_type -> gripql.Graph - 41, // 106: gripql.Query.ListGraphs:output_type -> gripql.ListGraphsResponse - 42, // 107: gripql.Query.ListIndices:output_type -> gripql.ListIndicesResponse - 43, // 108: gripql.Query.ListLabels:output_type -> gripql.ListLabelsResponse - 44, // 109: gripql.Query.ListTables:output_type -> gripql.TableInfo - 30, // 110: gripql.Job.Submit:output_type -> gripql.QueryJob - 30, // 111: gripql.Job.ListJobs:output_type -> gripql.QueryJob - 32, // 112: gripql.Job.SearchJobs:output_type -> gripql.JobStatus - 32, // 113: gripql.Job.DeleteJob:output_type -> gripql.JobStatus - 32, // 114: gripql.Job.GetJob:output_type -> gripql.JobStatus - 29, // 115: gripql.Job.ViewJob:output_type -> gripql.QueryResult - 29, // 116: gripql.Job.ResumeJob:output_type -> gripql.QueryResult - 33, // 117: gripql.Edit.AddVertex:output_type -> gripql.EditResult - 33, // 118: gripql.Edit.AddEdge:output_type -> gripql.EditResult - 34, // 119: gripql.Edit.BulkAdd:output_type -> gripql.BulkEditResult - 33, // 120: gripql.Edit.AddGraph:output_type -> gripql.EditResult - 33, // 121: gripql.Edit.DeleteGraph:output_type -> gripql.EditResult - 33, // 122: gripql.Edit.DeleteVertex:output_type -> gripql.EditResult - 33, // 123: gripql.Edit.DeleteEdge:output_type -> gripql.EditResult - 33, // 124: gripql.Edit.AddIndex:output_type -> gripql.EditResult - 33, // 125: gripql.Edit.DeleteIndex:output_type -> gripql.EditResult - 33, // 126: gripql.Edit.AddSchema:output_type -> gripql.EditResult - 3, // 127: gripql.Edit.SampleSchema:output_type -> gripql.Graph - 33, // 128: gripql.Edit.AddMapping:output_type -> gripql.EditResult - 46, // 129: gripql.Configure.StartPlugin:output_type -> gripql.PluginStatus - 48, // 130: gripql.Configure.ListPlugins:output_type -> gripql.ListPluginsResponse - 47, // 131: gripql.Configure.ListDrivers:output_type -> gripql.ListDriversResponse - 100, // [100:132] is the sub-list for method output_type - 68, // [68:100] is the sub-list for method input_type - 68, // [68:68] is the sub-list for extension type_name - 68, // [68:68] is the sub-list for extension extendee - 0, // [0:68] is the sub-list for field type_name + 24, // 0: gripql.Graph.vertices:type_name -> gripql.Vertex + 25, // 1: gripql.Graph.edges:type_name -> gripql.Edge + 6, // 2: gripql.GraphQuery.query:type_name -> gripql.GraphStatement + 6, // 3: gripql.QuerySet.query:type_name -> gripql.GraphStatement + 48, // 4: gripql.GraphStatement.v:type_name -> google.protobuf.ListValue + 48, // 5: gripql.GraphStatement.e:type_name -> google.protobuf.ListValue + 48, // 6: gripql.GraphStatement.in:type_name -> google.protobuf.ListValue + 48, // 7: gripql.GraphStatement.out:type_name -> google.protobuf.ListValue + 48, // 8: gripql.GraphStatement.both:type_name -> google.protobuf.ListValue + 48, // 9: gripql.GraphStatement.in_e:type_name -> google.protobuf.ListValue + 48, // 10: gripql.GraphStatement.out_e:type_name -> google.protobuf.ListValue + 48, // 11: gripql.GraphStatement.both_e:type_name -> google.protobuf.ListValue + 48, // 12: gripql.GraphStatement.in_null:type_name -> google.protobuf.ListValue + 48, // 13: gripql.GraphStatement.out_null:type_name -> google.protobuf.ListValue + 48, // 14: gripql.GraphStatement.in_e_null:type_name -> google.protobuf.ListValue + 48, // 15: gripql.GraphStatement.out_e_null:type_name -> google.protobuf.ListValue + 7, // 16: gripql.GraphStatement.range:type_name -> gripql.Range + 19, // 17: gripql.GraphStatement.has:type_name -> gripql.HasExpression + 48, // 18: gripql.GraphStatement.has_label:type_name -> google.protobuf.ListValue + 48, // 19: gripql.GraphStatement.has_key:type_name -> google.protobuf.ListValue + 48, // 20: gripql.GraphStatement.has_id:type_name -> google.protobuf.ListValue + 48, // 21: gripql.GraphStatement.distinct:type_name -> google.protobuf.ListValue + 48, // 22: gripql.GraphStatement.fields:type_name -> google.protobuf.ListValue + 9, // 23: gripql.GraphStatement.aggregate:type_name -> gripql.Aggregations + 49, // 24: gripql.GraphStatement.render:type_name -> google.protobuf.Value + 48, // 25: gripql.GraphStatement.path:type_name -> google.protobuf.ListValue + 21, // 26: gripql.GraphStatement.jump:type_name -> gripql.Jump + 22, // 27: gripql.GraphStatement.set:type_name -> gripql.Set + 23, // 28: gripql.GraphStatement.increment:type_name -> gripql.Increment + 10, // 29: gripql.AggregationsRequest.aggregations:type_name -> gripql.Aggregate + 10, // 30: gripql.Aggregations.aggregations:type_name -> gripql.Aggregate + 11, // 31: gripql.Aggregate.term:type_name -> gripql.TermAggregation + 12, // 32: gripql.Aggregate.percentile:type_name -> gripql.PercentileAggregation + 13, // 33: gripql.Aggregate.histogram:type_name -> gripql.HistogramAggregation + 14, // 34: gripql.Aggregate.field:type_name -> gripql.FieldAggregation + 15, // 35: gripql.Aggregate.type:type_name -> gripql.TypeAggregation + 16, // 36: gripql.Aggregate.count:type_name -> gripql.CountAggregation + 49, // 37: gripql.NamedAggregationResult.key:type_name -> google.protobuf.Value + 19, // 38: gripql.HasExpressionList.expressions:type_name -> gripql.HasExpression + 18, // 39: gripql.HasExpression.and:type_name -> gripql.HasExpressionList + 18, // 40: gripql.HasExpression.or:type_name -> gripql.HasExpressionList + 19, // 41: gripql.HasExpression.not:type_name -> gripql.HasExpression + 20, // 42: gripql.HasExpression.condition:type_name -> gripql.HasCondition + 49, // 43: gripql.HasCondition.value:type_name -> google.protobuf.Value + 0, // 44: gripql.HasCondition.condition:type_name -> gripql.Condition + 19, // 45: gripql.Jump.expression:type_name -> gripql.HasExpression + 49, // 46: gripql.Set.value:type_name -> google.protobuf.Value + 50, // 47: gripql.Vertex.data:type_name -> google.protobuf.Struct + 50, // 48: gripql.Edge.data:type_name -> google.protobuf.Struct + 24, // 49: gripql.QueryResult.vertex:type_name -> gripql.Vertex + 25, // 50: gripql.QueryResult.edge:type_name -> gripql.Edge + 17, // 51: gripql.QueryResult.aggregations:type_name -> gripql.NamedAggregationResult + 49, // 52: gripql.QueryResult.render:type_name -> google.protobuf.Value + 48, // 53: gripql.QueryResult.path:type_name -> google.protobuf.ListValue + 6, // 54: gripql.ExtendQuery.query:type_name -> gripql.GraphStatement + 1, // 55: gripql.JobStatus.state:type_name -> gripql.JobState + 6, // 56: gripql.JobStatus.query:type_name -> gripql.GraphStatement + 24, // 57: gripql.GraphElement.vertex:type_name -> gripql.Vertex + 25, // 58: gripql.GraphElement.edge:type_name -> gripql.Edge + 35, // 59: gripql.ListIndicesResponse.indices:type_name -> gripql.IndexID + 46, // 60: gripql.TableInfo.link_map:type_name -> gripql.TableInfo.LinkMapEntry + 47, // 61: gripql.PluginConfig.config:type_name -> gripql.PluginConfig.ConfigEntry + 4, // 62: gripql.Query.Traversal:input_type -> gripql.GraphQuery + 34, // 63: gripql.Query.GetVertex:input_type -> gripql.ElementID + 34, // 64: gripql.Query.GetEdge:input_type -> gripql.ElementID + 33, // 65: gripql.Query.GetTimestamp:input_type -> gripql.GraphID + 33, // 66: gripql.Query.GetSchema:input_type -> gripql.GraphID + 33, // 67: gripql.Query.GetMapping:input_type -> gripql.GraphID + 37, // 68: gripql.Query.ListGraphs:input_type -> gripql.Empty + 33, // 69: gripql.Query.ListIndices:input_type -> gripql.GraphID + 33, // 70: gripql.Query.ListLabels:input_type -> gripql.GraphID + 37, // 71: gripql.Query.ListTables:input_type -> gripql.Empty + 4, // 72: gripql.Job.Submit:input_type -> gripql.GraphQuery + 33, // 73: gripql.Job.ListJobs:input_type -> gripql.GraphID + 4, // 74: gripql.Job.SearchJobs:input_type -> gripql.GraphQuery + 27, // 75: gripql.Job.DeleteJob:input_type -> gripql.QueryJob + 27, // 76: gripql.Job.GetJob:input_type -> gripql.QueryJob + 27, // 77: gripql.Job.ViewJob:input_type -> gripql.QueryJob + 28, // 78: gripql.Job.ResumeJob:input_type -> gripql.ExtendQuery + 32, // 79: gripql.Edit.AddVertex:input_type -> gripql.GraphElement + 32, // 80: gripql.Edit.AddEdge:input_type -> gripql.GraphElement + 32, // 81: gripql.Edit.BulkAdd:input_type -> gripql.GraphElement + 33, // 82: gripql.Edit.AddGraph:input_type -> gripql.GraphID + 33, // 83: gripql.Edit.DeleteGraph:input_type -> gripql.GraphID + 34, // 84: gripql.Edit.DeleteVertex:input_type -> gripql.ElementID + 34, // 85: gripql.Edit.DeleteEdge:input_type -> gripql.ElementID + 35, // 86: gripql.Edit.AddIndex:input_type -> gripql.IndexID + 35, // 87: gripql.Edit.DeleteIndex:input_type -> gripql.IndexID + 3, // 88: gripql.Edit.AddSchema:input_type -> gripql.Graph + 33, // 89: gripql.Edit.SampleSchema:input_type -> gripql.GraphID + 3, // 90: gripql.Edit.AddMapping:input_type -> gripql.Graph + 42, // 91: gripql.Configure.StartPlugin:input_type -> gripql.PluginConfig + 37, // 92: gripql.Configure.ListPlugins:input_type -> gripql.Empty + 37, // 93: gripql.Configure.ListDrivers:input_type -> gripql.Empty + 26, // 94: gripql.Query.Traversal:output_type -> gripql.QueryResult + 24, // 95: gripql.Query.GetVertex:output_type -> gripql.Vertex + 25, // 96: gripql.Query.GetEdge:output_type -> gripql.Edge + 36, // 97: gripql.Query.GetTimestamp:output_type -> gripql.Timestamp + 3, // 98: gripql.Query.GetSchema:output_type -> gripql.Graph + 3, // 99: gripql.Query.GetMapping:output_type -> gripql.Graph + 38, // 100: gripql.Query.ListGraphs:output_type -> gripql.ListGraphsResponse + 39, // 101: gripql.Query.ListIndices:output_type -> gripql.ListIndicesResponse + 40, // 102: gripql.Query.ListLabels:output_type -> gripql.ListLabelsResponse + 41, // 103: gripql.Query.ListTables:output_type -> gripql.TableInfo + 27, // 104: gripql.Job.Submit:output_type -> gripql.QueryJob + 27, // 105: gripql.Job.ListJobs:output_type -> gripql.QueryJob + 29, // 106: gripql.Job.SearchJobs:output_type -> gripql.JobStatus + 29, // 107: gripql.Job.DeleteJob:output_type -> gripql.JobStatus + 29, // 108: gripql.Job.GetJob:output_type -> gripql.JobStatus + 26, // 109: gripql.Job.ViewJob:output_type -> gripql.QueryResult + 26, // 110: gripql.Job.ResumeJob:output_type -> gripql.QueryResult + 30, // 111: gripql.Edit.AddVertex:output_type -> gripql.EditResult + 30, // 112: gripql.Edit.AddEdge:output_type -> gripql.EditResult + 31, // 113: gripql.Edit.BulkAdd:output_type -> gripql.BulkEditResult + 30, // 114: gripql.Edit.AddGraph:output_type -> gripql.EditResult + 30, // 115: gripql.Edit.DeleteGraph:output_type -> gripql.EditResult + 30, // 116: gripql.Edit.DeleteVertex:output_type -> gripql.EditResult + 30, // 117: gripql.Edit.DeleteEdge:output_type -> gripql.EditResult + 30, // 118: gripql.Edit.AddIndex:output_type -> gripql.EditResult + 30, // 119: gripql.Edit.DeleteIndex:output_type -> gripql.EditResult + 30, // 120: gripql.Edit.AddSchema:output_type -> gripql.EditResult + 3, // 121: gripql.Edit.SampleSchema:output_type -> gripql.Graph + 30, // 122: gripql.Edit.AddMapping:output_type -> gripql.EditResult + 43, // 123: gripql.Configure.StartPlugin:output_type -> gripql.PluginStatus + 45, // 124: gripql.Configure.ListPlugins:output_type -> gripql.ListPluginsResponse + 44, // 125: gripql.Configure.ListDrivers:output_type -> gripql.ListDriversResponse + 94, // [94:126] is the sub-list for method output_type + 62, // [62:94] is the sub-list for method input_type + 62, // [62:62] is the sub-list for extension type_name + 62, // [62:62] is the sub-list for extension extendee + 0, // [0:62] is the sub-list for field type_name } func init() { file_gripql_proto_init() } @@ -4459,42 +4236,6 @@ func file_gripql_proto_init() { } } file_gripql_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SelectStatement); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_gripql_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Selection); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_gripql_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Selections); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_gripql_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Jump); i { case 0: return &v.state @@ -4506,7 +4247,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Set); i { case 0: return &v.state @@ -4518,7 +4259,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Increment); i { case 0: return &v.state @@ -4530,7 +4271,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Vertex); i { case 0: return &v.state @@ -4542,7 +4283,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Edge); i { case 0: return &v.state @@ -4554,7 +4295,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*QueryResult); i { case 0: return &v.state @@ -4566,7 +4307,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*QueryJob); i { case 0: return &v.state @@ -4578,7 +4319,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ExtendQuery); i { case 0: return &v.state @@ -4590,7 +4331,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*JobStatus); i { case 0: return &v.state @@ -4602,7 +4343,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*EditResult); i { case 0: return &v.state @@ -4614,7 +4355,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BulkEditResult); i { case 0: return &v.state @@ -4626,7 +4367,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GraphElement); i { case 0: return &v.state @@ -4638,7 +4379,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*GraphID); i { case 0: return &v.state @@ -4650,7 +4391,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ElementID); i { case 0: return &v.state @@ -4662,7 +4403,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*IndexID); i { case 0: return &v.state @@ -4674,7 +4415,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Timestamp); i { case 0: return &v.state @@ -4686,7 +4427,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Empty); i { case 0: return &v.state @@ -4698,7 +4439,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListGraphsResponse); i { case 0: return &v.state @@ -4710,7 +4451,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListIndicesResponse); i { case 0: return &v.state @@ -4722,7 +4463,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListLabelsResponse); i { case 0: return &v.state @@ -4734,7 +4475,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*TableInfo); i { case 0: return &v.state @@ -4746,7 +4487,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PluginConfig); i { case 0: return &v.state @@ -4758,7 +4499,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PluginStatus); i { case 0: return &v.state @@ -4770,7 +4511,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListDriversResponse); i { case 0: return &v.state @@ -4782,7 +4523,7 @@ func file_gripql_proto_init() { return nil } } - file_gripql_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { + file_gripql_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ListPluginsResponse); i { case 0: return &v.state @@ -4843,15 +4584,10 @@ func file_gripql_proto_init() { (*HasExpression_Not)(nil), (*HasExpression_Condition)(nil), } - file_gripql_proto_msgTypes[19].OneofWrappers = []interface{}{ - (*Selection_Vertex)(nil), - (*Selection_Edge)(nil), - } - file_gripql_proto_msgTypes[26].OneofWrappers = []interface{}{ + file_gripql_proto_msgTypes[23].OneofWrappers = []interface{}{ (*QueryResult_Vertex)(nil), (*QueryResult_Edge)(nil), (*QueryResult_Aggregations)(nil), - (*QueryResult_Selections)(nil), (*QueryResult_Render)(nil), (*QueryResult_Count)(nil), (*QueryResult_Path)(nil), @@ -4862,7 +4598,7 @@ func file_gripql_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_gripql_proto_rawDesc, NumEnums: 3, - NumMessages: 49, + NumMessages: 45, NumExtensions: 0, NumServices: 4, }, diff --git a/gripql/gripql.proto b/gripql/gripql.proto index 0e990fe9..a192859a 100644 --- a/gripql/gripql.proto +++ b/gripql/gripql.proto @@ -40,7 +40,7 @@ message GraphStatement { google.protobuf.ListValue out_e_null = 19; string as = 20; - SelectStatement select = 21; + string select = 21; uint32 limit = 24; uint32 skip = 25; Range range = 26; @@ -160,21 +160,6 @@ enum Condition { CONTAINS = 12; } -message SelectStatement { - repeated string marks = 1; -} - -message Selection { - oneof result { - Vertex vertex = 1; - Edge edge = 2; - } -} - -message Selections { - map selections = 1; -} - message Jump { string mark = 1; HasExpression expression = 2; @@ -210,7 +195,6 @@ message QueryResult { Vertex vertex = 1; Edge edge = 2; NamedAggregationResult aggregations = 3; - Selections selections = 4; google.protobuf.Value render = 5; uint32 count = 6; google.protobuf.ListValue path = 7; diff --git a/gripql/inspect/inspect.go b/gripql/inspect/inspect.go index ca376824..3ebe89da 100644 --- a/gripql/inspect/inspect.go +++ b/gripql/inspect/inspect.go @@ -88,16 +88,6 @@ func PipelineStepOutputs(stmts []*gripql.GraphStatement) map[string][]string { switch gs.GetStatement().(type) { case *gripql.GraphStatement_Count: onLast = false - case *gripql.GraphStatement_Select: - if onLast { - sel := gs.GetSelect().Marks - for _, s := range sel { - if a, ok := asMap[s]; ok { - out[a] = []string{"*"} - } - } - onLast = false - } case *gripql.GraphStatement_Distinct: //if there is a distinct step, we need to load data, but only for requested fields fields := protoutil.AsStringList(gs.GetDistinct()) diff --git a/gripql/python/gripql/query.py b/gripql/python/gripql/query.py index 62563d0b..2657ba18 100644 --- a/gripql/python/gripql/query.py +++ b/gripql/python/gripql/query.py @@ -232,21 +232,12 @@ def as_(self, name): """ return self.__append({"as": name}) - def select(self, marks): + def select(self, name): """ - Returns rows of marked elements, with one item for each mark. + Move traveler back to a previously marked position - "marks" is a list of mark names. - The rows returned are all combinations of marks, e.g. - [ - [A1, B1], - [A1, B2], - [A2, B1], - [A2, B2], - ] """ - marks = _wrap_str_value(marks) - return self.__append({"select": {"marks": marks}}) + return self.__append({"select": name}) def limit(self, n): """ diff --git a/gripql/query.go b/gripql/query.go index b17c45cd..3f1cb6f2 100644 --- a/gripql/query.go +++ b/gripql/query.go @@ -159,9 +159,8 @@ func (q *Query) As(id string) *Query { } // Select retreieves previously marked elemets -func (q *Query) Select(id ...string) *Query { - idList := SelectStatement{Marks: id} - return q.with(&GraphStatement{Statement: &GraphStatement_Select{&idList}}) +func (q *Query) Select(name string) *Query { + return q.with(&GraphStatement{Statement: &GraphStatement_Select{name}}) } // Fields selects which properties are returned in the result. @@ -280,7 +279,7 @@ func (q *Query) String() string { add("As", stmt.As) case *GraphStatement_Select: - add("Select", stmt.Select.Marks...) + add("Select", stmt.Select) case *GraphStatement_Fields: fields := protoutil.AsStringList(stmt.Fields) diff --git a/gripql/schema/scan.go b/gripql/schema/scan.go index 85e2b257..a6a417c4 100644 --- a/gripql/schema/scan.go +++ b/gripql/schema/scan.go @@ -1,8 +1,6 @@ package schema import ( - "fmt" - "github.com/bmeg/grip/gripql" "github.com/bmeg/grip/log" "github.com/bmeg/grip/util" @@ -60,41 +58,45 @@ func ScanSchema(conn gripql.Client, graph string, sampleCount uint32, exclude [] } } + //TODO: fix this bit eList := []*gripql.Edge{} - for _, elabel := range labelRes.EdgeLabels { - if stringInSlice(elabel, exclude) { - continue - } - log.Infof("Scanning edge %s\n", elabel) - edgeQuery := gripql.E().HasLabel(elabel).Limit(sampleCount).As("edge").Out().Fields().As("to").Select("edge").In().Fields().As("from").Select("edge", "from", "to") - edgeRes, err := conn.Traversal(&gripql.GraphQuery{Graph: graph, Query: edgeQuery.Statements}) - if err == nil { - labelSchema := edgeMap{} - for row := range edgeRes { - sel := row.GetSelections().Selections - edge := sel["edge"].GetEdge() - src := sel["from"].GetVertex() - dst := sel["to"].GetVertex() - ds := gripql.GetDataFieldTypes(edge.Data.AsMap()) - k := edgeKey{to: dst.Label, from: src.Label, label: edge.Label} - if p, ok := labelSchema[k]; ok { - labelSchema[k] = util.MergeMaps(p, ds) - } else { - labelSchema[k] = ds - } + /* + for _, elabel := range labelRes.EdgeLabels { + if stringInSlice(elabel, exclude) { + continue } - for k, v := range labelSchema { - sValue, _ := structpb.NewStruct(v.(map[string]interface{})) - eSchema := &gripql.Edge{ - Gid: fmt.Sprintf("(%s)-%s->(%s)", k.from, k.label, k.to), - Label: k.label, - From: k.from, - To: k.to, - Data: sValue, + log.Infof("Scanning edge %s\n", elabel) + edgeQuery := gripql.E().HasLabel(elabel).Limit(sampleCount).As("edge").Out().Fields().As("to").Select("edge").In().Fields().As("from").Select("edge", "from", "to") + edgeRes, err := conn.Traversal(&gripql.GraphQuery{Graph: graph, Query: edgeQuery.Statements}) + if err == nil { + labelSchema := edgeMap{} + for row := range edgeRes { + sel := row.GetSelections().Selections + edge := sel["edge"].GetEdge() + src := sel["from"].GetVertex() + dst := sel["to"].GetVertex() + ds := gripql.GetDataFieldTypes(edge.Data.AsMap()) + k := edgeKey{to: dst.Label, from: src.Label, label: edge.Label} + if p, ok := labelSchema[k]; ok { + labelSchema[k] = util.MergeMaps(p, ds) + } else { + labelSchema[k] = ds + } + } + for k, v := range labelSchema { + sValue, _ := structpb.NewStruct(v.(map[string]interface{})) + eSchema := &gripql.Edge{ + Gid: fmt.Sprintf("(%s)-%s->(%s)", k.from, k.label, k.to), + Label: k.label, + From: k.from, + To: k.to, + Data: sValue, + } + eList = append(eList, eSchema) } - eList = append(eList, eSchema) } } - } + */ + return &gripql.Graph{Graph: graph, Vertices: vList, Edges: eList}, nil } diff --git a/mongo/compile.go b/mongo/compile.go index 34f84fa2..1b83c1fd 100644 --- a/mongo/compile.go +++ b/mongo/compile.go @@ -666,42 +666,30 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile if lastType != gdbi.VertexData && lastType != gdbi.EdgeData { return &Pipeline{}, fmt.Errorf(`"select" statement is only valid for edge or vertex types not: %s`, lastType.String()) } - switch len(stmt.Select.Marks) { - case 0: - return &Pipeline{}, fmt.Errorf(`"select" statement has an empty list of mark names`) - case 1: - mark := "$marks." + stmt.Select.Marks[0] - switch markTypes[stmt.Select.Marks[0]] { - case gdbi.VertexData: - query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - "_id": mark + "._id", - "label": mark + ".label", - "data": mark + ".data", - "marks": 1, - "path": "$path", - //"path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"vertex": mark + "._id"}}}}, - }}}) - lastType = gdbi.VertexData - case gdbi.EdgeData: - query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - "_id": mark + "._id", - "label": mark + ".label", - "from": mark + ".from", - "to": mark + ".to", - "data": mark + ".data", - "marks": 1, - "path": "$path", - //"path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"edge": mark + "._id"}}}}, - }}}) - lastType = gdbi.EdgeData - } - default: - selection := bson.M{} - for _, mark := range stmt.Select.Marks { - selection["marks."+mark] = 1 - } - query = append(query, bson.D{primitive.E{Key: "$project", Value: selection}}) - lastType = gdbi.SelectionData + mark := "$marks." + stmt.Select + switch markTypes[stmt.Select] { + case gdbi.VertexData: + query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ + "_id": mark + "._id", + "label": mark + ".label", + "data": mark + ".data", + "marks": 1, + "path": "$path", + //"path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"vertex": mark + "._id"}}}}, + }}}) + lastType = gdbi.VertexData + case gdbi.EdgeData: + query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ + "_id": mark + "._id", + "label": mark + ".label", + "from": mark + ".from", + "to": mark + ".to", + "data": mark + ".data", + "marks": 1, + "path": "$path", + //"path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"edge": mark + "._id"}}}}, + }}}) + lastType = gdbi.EdgeData } case *gripql.GraphStatement_Render: diff --git a/website/content/docs/queries/operations.md b/website/content/docs/queries/operations.md index 2f36d84c..0c90d310 100644 --- a/website/content/docs/queries/operations.md +++ b/website/content/docs/queries/operations.md @@ -14,11 +14,13 @@ Start query from Vertex ```python G.query().V() ``` + Returns all vertices in graph ```python -G.query().V(["vertex1]") +G.query().V(["vertex1"]) ``` + Returns: ```json {"gid" : "vertex1", "label":"TestVertex", "data":{}} @@ -37,7 +39,7 @@ G.query().E(["edge1"]) ``` Returns: ```json -{"gid" : "edge1", "label":"TestEdge", From: "vertex1", To: "vertex2", data":{}} +{"gid" : "edge1", "label":"TestEdge", "from": "vertex1", "to": "vertex2", "data":{}} ``` @@ -176,9 +178,9 @@ G.query().V().as_("a").out().as_("b") ``` ## .select([names]) -Output previously marked elements +Move traveler to previously marked position ```python -G.query().V().mark("a").out().mark("b").select(["a", "b"]) +G.query().V().mark("a").out().mark("b").select("a") ``` ## .limit(count) From 531cdb935e2dbc775e6976ebda395989fd094794 Mon Sep 17 00:00:00 2001 From: Kyle Ellrott Date: Wed, 7 Feb 2024 22:49:49 -0800 Subject: [PATCH 07/23] Fixing issue with serialization of base traveler. Added a bunch of runtime logging for pipelines --- conformance/tests/ot_job.py | 8 +++++-- conformance/tests/ot_mark.py | 2 +- engine/core/processors.go | 4 ++-- engine/logic/match.go | 36 ++++++++++++++-------------- engine/manager.go | 3 +-- engine/pipeline/pipe_logger.go | 43 ++++++++++++++++++++++++++++++++++ engine/pipeline/pipes.go | 42 +++++++++++++++++++++++++++------ gdbi/interface.go | 6 ++--- gdbi/jsonpath.go | 4 ++-- gdbi/traveler.go | 16 ++++++++----- gripql/inspect/inspect.go | 8 +++++++ jobstorage/storage.go | 25 +++++++++++--------- mongo/processor.go | 2 +- server/job_manager.go | 5 ++-- 14 files changed, 147 insertions(+), 57 deletions(-) create mode 100644 engine/pipeline/pipe_logger.go diff --git a/conformance/tests/ot_job.py b/conformance/tests/ot_job.py index 3f7e6187..a9fcd66b 100644 --- a/conformance/tests/ot_job.py +++ b/conformance/tests/ot_job.py @@ -41,15 +41,19 @@ def test_job(man): errors.append("Job not found in search: %d" % (count)) fullResults = [] + fullCount = 0 for res in G.query().V().hasLabel("Planet").out().out().count(): fullResults.append(res) + fullCount = res["count"] resumedResults = [] for res in G.resume(job["id"]).out().count().execute(): resumedResults.append(res) + if res["count"] != fullCount: + errors.append("Incorrect saved count returned: %d != %d" % (res["count"], fullCount)) if len(fullResults) != len(resumedResults): - errors.append( "Missmatch on resumed result" ) + errors.append( """Missmatch on resumed result: G.query().V().hasLabel("Planet").out().out().count()""" ) fullResults = [] for res in G.query().V().hasLabel("Planet").as_("a").out().out().select("a"): @@ -63,7 +67,7 @@ def test_job(man): resumedResults.sort(key=lambda x:x["gid"]) if len(fullResults) != len(resumedResults): - errors.append( "Missmatch on resumed result" ) + errors.append( """Missmatch on resumed result: G.query().V().hasLabel("Planet").as_("a").out().out().select("a")""" ) for a, b in zip(fullResults, resumedResults): if a != b: diff --git a/conformance/tests/ot_mark.py b/conformance/tests/ot_mark.py index e33c3657..667b53de 100644 --- a/conformance/tests/ot_mark.py +++ b/conformance/tests/ot_mark.py @@ -57,7 +57,7 @@ def test_mark_edge_select(man): count = 0 for row in G.query().V("Film:1").as_("a").outE("planets").as_( - "b").out().as_("c").select(["a", "b", "c"]): + "b").out().as_("c").render({"a":"$a", "b":"$b", "c":"$c"}): count += 1 if len(row) != 3: errors.append("Incorrect number of marks returned") diff --git a/engine/core/processors.go b/engine/core/processors.go index baa31243..695e99f9 100644 --- a/engine/core/processors.go +++ b/engine/core/processors.go @@ -799,13 +799,13 @@ func (s *Selector) Process(ctx context.Context, man gdbi.Manager, in gdbi.InPipe out <- t continue } - res := map[string]gdbi.DataRef{} + res := map[string]*gdbi.DataElement{} for _, mark := range s.marks { val := t.GetMark(mark) if val == nil { val = &gdbi.DataElement{} } - res[mark] = val + res[mark] = val.Get() } out <- &gdbi.BaseTraveler{Selections: res} } diff --git a/engine/logic/match.go b/engine/logic/match.go index 63dde0f3..88a6be6e 100644 --- a/engine/logic/match.go +++ b/engine/logic/match.go @@ -70,26 +70,26 @@ func MatchesCondition(trav gdbi.Traveler, cond *gripql.HasCondition) bool { case gripql.Condition_INSIDE: vals, err := cast.ToSliceE(condVal) if err != nil { - log.Errorf("Error: could not cast INSIDE condition value: %v", err) + log.Debugf("UserError: could not cast INSIDE condition value: %v", err) return false } if len(vals) != 2 { - log.Errorf("Error: expected slice of length 2 not %v for INSIDE condition value", len(vals)) + log.Debugf("UserError: expected slice of length 2 not %v for INSIDE condition value", len(vals)) return false } lower, err := cast.ToFloat64E(vals[0]) if err != nil { - log.Errorf("Error: could not cast lower INSIDE condition value: %v", err) + log.Debugf("UserError: could not cast lower INSIDE condition value: %v", err) return false } upper, err := cast.ToFloat64E(vals[1]) if err != nil { - log.Errorf("Error: could not cast upper INSIDE condition value: %v", err) + log.Debugf("UserError: could not cast upper INSIDE condition value: %v", err) return false } valF, err := cast.ToFloat64E(val) if err != nil { - log.Errorf("Error: could not cast INSIDE value: %v", err) + log.Debugf("UserError: could not cast INSIDE value: %v", err) return false } return valF > lower && valF < upper @@ -97,26 +97,26 @@ func MatchesCondition(trav gdbi.Traveler, cond *gripql.HasCondition) bool { case gripql.Condition_OUTSIDE: vals, err := cast.ToSliceE(condVal) if err != nil { - log.Errorf("Error: could not cast OUTSIDE condition value: %v", err) + log.Debugf("UserError: could not cast OUTSIDE condition value: %v", err) return false } if len(vals) != 2 { - log.Errorf("Error: expected slice of length 2 not %v for OUTSIDE condition value", len(vals)) + log.Debugf("UserError: expected slice of length 2 not %v for OUTSIDE condition value", len(vals)) return false } lower, err := cast.ToFloat64E(vals[0]) if err != nil { - log.Errorf("Error: could not cast lower OUTSIDE condition value: %v", err) + log.Debugf("UserError: could not cast lower OUTSIDE condition value: %v", err) return false } upper, err := cast.ToFloat64E(vals[1]) if err != nil { - log.Errorf("Error: could not cast upper OUTSIDE condition value: %v", err) + log.Debugf("UserError: could not cast upper OUTSIDE condition value: %v", err) return false } valF, err := cast.ToFloat64E(val) if err != nil { - log.Errorf("Error: could not cast OUTSIDE value: %v", err) + log.Debugf("UserError: could not cast OUTSIDE value: %v", err) return false } return valF < lower || valF > upper @@ -124,26 +124,26 @@ func MatchesCondition(trav gdbi.Traveler, cond *gripql.HasCondition) bool { case gripql.Condition_BETWEEN: vals, err := cast.ToSliceE(condVal) if err != nil { - log.Errorf("Error: could not cast BETWEEN condition value: %v", err) + log.Debugf("UserError: could not cast BETWEEN condition value: %v", err) return false } if len(vals) != 2 { - log.Errorf("Error: expected slice of length 2 not %v for BETWEEN condition value", len(vals)) + log.Debugf("UserError: expected slice of length 2 not %v for BETWEEN condition value", len(vals)) return false } lower, err := cast.ToFloat64E(vals[0]) if err != nil { - log.Errorf("Error: could not cast lower BETWEEN condition value: %v", err) + log.Debugf("UserError: could not cast lower BETWEEN condition value: %v", err) return false } upper, err := cast.ToFloat64E(vals[1]) if err != nil { - log.Errorf("Error: could not cast upper BETWEEN condition value: %v", err) + log.Debugf("UserError: could not cast upper BETWEEN condition value: %v", err) return false } valF, err := cast.ToFloat64E(val) if err != nil { - log.Errorf("Error: could not cast BETWEEN value: %v", err) + log.Debugf("UserError: could not cast BETWEEN value: %v", err) return false } return valF >= lower && valF < upper @@ -162,7 +162,7 @@ func MatchesCondition(trav gdbi.Traveler, cond *gripql.HasCondition) bool { found = false default: - log.Errorf("Error: expected slice not %T for WITHIN condition value", condVal) + log.Debugf("UserError: expected slice not %T for WITHIN condition value", condVal) } return found @@ -181,7 +181,7 @@ func MatchesCondition(trav gdbi.Traveler, cond *gripql.HasCondition) bool { found = false default: - log.Errorf("Error: expected slice not %T for WITHOUT condition value", condVal) + log.Debugf("UserError: expected slice not %T for WITHOUT condition value", condVal) } @@ -201,7 +201,7 @@ func MatchesCondition(trav gdbi.Traveler, cond *gripql.HasCondition) bool { found = false default: - log.Errorf("Error: unknown condition value type %T for CONTAINS condition", val) + log.Debugf("UserError: unknown condition value type %T for CONTAINS condition", val) } return found diff --git a/engine/manager.go b/engine/manager.go index 9317e2f5..6a425b71 100644 --- a/engine/manager.go +++ b/engine/manager.go @@ -1,7 +1,6 @@ package engine import ( - "io/ioutil" "os" "github.com/bmeg/grip/gdbi" @@ -21,7 +20,7 @@ type manager struct { } func (bm *manager) GetTempKV() kvi.KVInterface { - td, _ := ioutil.TempDir(bm.workDir, "kvTmp") + td, _ := os.MkdirTemp(bm.workDir, "kvTmp") kv, _ := badgerdb.NewKVInterface(td, kvi.Options{}) bm.kvs = append(bm.kvs, kv) diff --git a/engine/pipeline/pipe_logger.go b/engine/pipeline/pipe_logger.go new file mode 100644 index 00000000..65bcd7eb --- /dev/null +++ b/engine/pipeline/pipe_logger.go @@ -0,0 +1,43 @@ +package pipeline + +import ( + "github.com/bmeg/grip/gdbi" + "github.com/bmeg/grip/log" +) + +type StepLogger struct { + Counts uint64 + in, out chan gdbi.Traveler +} + +type PipelineLogger struct { + steps map[string]*StepLogger +} + +func NewPipelineLogger() *PipelineLogger { + return &PipelineLogger{steps: map[string]*StepLogger{}} +} + +func (pl *PipelineLogger) AddStep(name string, in chan gdbi.Traveler) chan gdbi.Traveler { + s := &StepLogger{ + Counts: 0, + in: in, + out: make(chan gdbi.Traveler, 10), + } + go func(a *StepLogger) { + defer close(a.out) + for i := range a.in { + a.Counts++ + a.out <- i + } + }(s) + pl.steps[name] = s + return s.out +} + +func (pl *PipelineLogger) Log() { + for n, c := range pl.steps { + log.Debugf("step count: %s %d", n, c.Counts) + } + +} diff --git a/engine/pipeline/pipes.go b/engine/pipeline/pipes.go index a8436f67..e965190e 100644 --- a/engine/pipeline/pipes.go +++ b/engine/pipeline/pipes.go @@ -6,6 +6,7 @@ package pipeline import ( "context" + "fmt" "github.com/bmeg/grip/engine" "github.com/bmeg/grip/engine/logic" @@ -15,13 +16,21 @@ import ( "google.golang.org/protobuf/types/known/structpb" ) +var debug = true + +type RunningPipeline struct { + Outputs gdbi.InPipe + Logger *PipelineLogger +} + // Start begins processing a query pipeline -func Start(ctx context.Context, pipe gdbi.Pipeline, man gdbi.Manager, bufsize int, input gdbi.InPipe, cancel func()) gdbi.InPipe { +func Start(ctx context.Context, pipe gdbi.Pipeline, man gdbi.Manager, bufsize int, input gdbi.InPipe, cancel func()) *RunningPipeline { procs := pipe.Processors() if len(procs) == 0 { + log.Debugf("User query has no steps") ch := make(chan gdbi.Traveler) close(ch) - return ch + return nil } markProcs := map[string]*logic.JumpMark{} @@ -30,24 +39,31 @@ func Start(ctx context.Context, pipe gdbi.Pipeline, man gdbi.Manager, bufsize in markProcs[p.Name] = p } } + + // if there is a jump statement, connect to back to the mark statement for i := range procs { if p, ok := procs[i].(*logic.Jump); ok { if d, ok := markProcs[p.Mark]; ok { p.Init() d.AddInput(p.GetJumpOutput()) } else { - log.Errorf("Missing Jump Mark") + log.Debugf("User query missing Jump Mark") ch := make(chan gdbi.Traveler) close(ch) - return ch + return nil } } } + l := NewPipelineLogger() + in := make(chan gdbi.Traveler, bufsize) final := make(chan gdbi.Traveler, bufsize) out := final for i := len(procs) - 1; i >= 0; i-- { + if debug { + in = l.AddStep(fmt.Sprintf("%T_%d", procs[i], i), in) + } ctx = procs[i].Process(ctx, man, in, out) out = in in = make(chan gdbi.Traveler, bufsize) @@ -55,13 +71,16 @@ func Start(ctx context.Context, pipe gdbi.Pipeline, man gdbi.Manager, bufsize in go func() { if input != nil { + inputCount := uint64(0) for i := range input { if ctx.Err() == context.Canceled { //cancel upstream cancel() } + inputCount++ out <- i } + log.Debugf("Stream input count: %d", inputCount) } else { // Write an empty traveler to input // to trigger the computation. @@ -71,7 +90,10 @@ func Start(ctx context.Context, pipe gdbi.Pipeline, man gdbi.Manager, bufsize in close(in) close(out) }() - return final + return &RunningPipeline{ + Outputs: final, + Logger: l, + } } // Run starts a pipeline and converts the output to server output structures @@ -84,7 +106,8 @@ func Run(ctx context.Context, pipe gdbi.Pipeline, workdir string) <-chan *gripql dataType := pipe.DataType() markTypes := pipe.MarkTypes() man := engine.NewManager(workdir) - for t := range Start(ctx, pipe, man, bufsize, nil, nil) { + rPipe := Start(ctx, pipe, man, bufsize, nil, nil) + for t := range rPipe.Outputs { if !t.IsSignal() { resch <- Convert(graph, dataType, markTypes, t) } @@ -104,11 +127,16 @@ func Resume(ctx context.Context, pipe gdbi.Pipeline, workdir string, input gdbi. dataType := pipe.DataType() markTypes := pipe.MarkTypes() man := engine.NewManager(workdir) - for t := range Start(ctx, pipe, man, bufsize, input, cancel) { + log.Debugf("resuming: out %s", dataType) + rPipe := Start(ctx, pipe, man, bufsize, input, cancel) + for t := range rPipe.Outputs { if !t.IsSignal() { resch <- Convert(graph, dataType, markTypes, t) } } + if debug { + rPipe.Logger.Log() + } man.Cleanup() }() return resch diff --git a/gdbi/interface.go b/gdbi/interface.go index 1f5a1de6..331392d5 100644 --- a/gdbi/interface.go +++ b/gdbi/interface.go @@ -78,9 +78,9 @@ type Signal struct { // Traveler is a query element that traverse the graph type BaseTraveler struct { - Current DataRef - Marks map[string]DataRef - Selections map[string]DataRef + Current *DataElement + Marks map[string]*DataElement + Selections map[string]*DataElement Aggregation *Aggregate Count uint32 Render interface{} diff --git a/gdbi/jsonpath.go b/gdbi/jsonpath.go index 91228f0e..01f9a2fb 100644 --- a/gdbi/jsonpath.go +++ b/gdbi/jsonpath.go @@ -2,7 +2,7 @@ package gdbi import ( // "fmt" - "fmt" + "strings" "github.com/bmeg/grip/log" @@ -91,7 +91,7 @@ func TravelerPathLookup(traveler Traveler, path string) interface{} { field := travelerpath.GetJSONPath(path) doc := GetDoc(traveler, namespace) if field == "" { - fmt.Printf("Null field, return %#v\n", doc) + //fmt.Printf("Null field, return %#v\n", doc) return doc } res, err := jsonpath.JsonPathLookup(doc, field) diff --git a/gdbi/traveler.go b/gdbi/traveler.go index 35f8dec7..d918778b 100644 --- a/gdbi/traveler.go +++ b/gdbi/traveler.go @@ -28,7 +28,7 @@ const ( // AddCurrent creates a new copy of the travel with new 'current' value func (t *BaseTraveler) AddCurrent(r DataRef) Traveler { o := BaseTraveler{ - Marks: map[string]DataRef{}, + Marks: map[string]*DataElement{}, Path: make([]DataElementID, len(t.Path)+1), Signal: t.Signal, } @@ -47,15 +47,15 @@ func (t *BaseTraveler) AddCurrent(r DataRef) Traveler { } else { o.Path[len(t.Path)] = DataElementID{Vertex: rd.ID} } + o.Current = r.Get() } - o.Current = r return &o } // AddCurrent creates a new copy of the travel with new 'current' value func (t *BaseTraveler) Copy() Traveler { o := BaseTraveler{ - Marks: map[string]DataRef{}, + Marks: map[string]*DataElement{}, Path: make([]DataElementID, len(t.Path)), Signal: t.Signal, } @@ -108,11 +108,11 @@ func (t *BaseTraveler) ListMarks() []string { // AddMark adds a result to travels state map using `label` as the name func (t *BaseTraveler) AddMark(label string, r DataRef) Traveler { - o := BaseTraveler{Marks: map[string]DataRef{}, Path: make([]DataElementID, len(t.Path))} + o := BaseTraveler{Marks: map[string]*DataElement{}, Path: make([]DataElementID, len(t.Path))} for k, v := range t.Marks { o.Marks[k] = v } - o.Marks[label] = r + o.Marks[label] = r.Get() for i := range t.Path { o.Path[i] = t.Path[i] } @@ -139,7 +139,11 @@ func (t *BaseTraveler) GetCount() uint32 { } func (t *BaseTraveler) GetSelections() map[string]DataRef { - return t.Selections + out := map[string]DataRef{} + for k, v := range t.Selections { + out[k] = v + } + return out } func (t *BaseTraveler) GetRender() interface{} { diff --git a/gripql/inspect/inspect.go b/gripql/inspect/inspect.go index 3ebe89da..00530b0f 100644 --- a/gripql/inspect/inspect.go +++ b/gripql/inspect/inspect.go @@ -88,6 +88,14 @@ func PipelineStepOutputs(stmts []*gripql.GraphStatement) map[string][]string { switch gs.GetStatement().(type) { case *gripql.GraphStatement_Count: onLast = false + case *gripql.GraphStatement_Select: + if onLast { + sel := gs.GetSelect() + if a, ok := asMap[sel]; ok { + out[a] = []string{"*"} + } + onLast = false + } case *gripql.GraphStatement_Distinct: //if there is a distinct step, we need to load data, but only for requested fields fields := protoutil.AsStringList(gs.GetDistinct()) diff --git a/jobstorage/storage.go b/jobstorage/storage.go index b0a587a4..3d263077 100644 --- a/jobstorage/storage.go +++ b/jobstorage/storage.go @@ -5,8 +5,7 @@ import ( "context" "encoding/json" "fmt" - "io/ioutil" - "log" + "io" "os" "path/filepath" "sync" @@ -14,6 +13,7 @@ import ( "github.com/bmeg/grip/gdbi" "github.com/bmeg/grip/gripql" + "github.com/bmeg/grip/log" "github.com/kennygrant/sanitize" ) @@ -59,21 +59,21 @@ func NewFSJobStorage(path string) *FSResults { graphName := filepath.Base(graphDir) file, err := os.Open(j) if err == nil { - sData, err := ioutil.ReadAll(file) + sData, err := io.ReadAll(file) if err == nil { job := Job{} err := json.Unmarshal(sData, &job) if err == nil { - log.Printf("Found job %s %s", graphName, jobName) + log.Infof("Found job %s %s", graphName, jobName) out.jobs.Store(jobKey(graphName, jobName), &job) } else { - log.Printf("Error Unmarshaling job data: %s", err) + log.Infof("Error Unmarshaling job data: %s", err) } } else { - log.Printf("Error reading job data: %s", err) + log.Infof("Error reading job data: %s", err) } } else { - log.Printf("Error opening job data: %s", err) + log.Infof("Error opening job data: %s", err) } } return &out @@ -122,7 +122,7 @@ func (fs *FSResults) Spool(graph string, stream *Stream) (string, error) { if _, err := os.Stat(graphDir); os.IsNotExist(err) { os.MkdirAll(graphDir, 0700) } - spoolDir, err := ioutil.TempDir(graphDir, "job-") + spoolDir, err := os.MkdirTemp(graphDir, "job-") if err != nil { return "", err } @@ -147,7 +147,7 @@ func (fs *FSResults) Spool(graph string, stream *Stream) (string, error) { tbStream := MarshalStream(stream.Pipe, 4) //TODO: make worker count configurable go func() { job.Status.State = gripql.JobState_RUNNING - log.Printf("Starting Job: %#v", job) + log.Infof("Starting Job: %#v", job) defer resultFile.Close() for i := range tbStream { resultFile.Write(i) @@ -163,10 +163,10 @@ func (fs *FSResults) Spool(graph string, stream *Stream) (string, error) { if err == nil { statusFile.Write([]byte(fmt.Sprintf("%s\n", out))) } - log.Printf("Job Done: %s (%d results)", jobName, job.Status.Count) + log.Infof("Job Done: %s (%d results)", jobName, job.Status.Count) } else { job.Status.State = gripql.JobState_ERROR - log.Printf("Job Error: %s %s", jobName, err) + log.Infof("Job Error: %s %s", jobName, err) } }() return jobName, nil @@ -190,14 +190,17 @@ func (fs *FSResults) Stream(ctx context.Context, graph, id string) (*Stream, err bufSize := 1024 * 1024 * 32 buf := make([]byte, bufSize) scan.Buffer(buf, bufSize) + count := uint64(0) for scan.Scan() { if ctx.Err() == context.Canceled { return } c := make([]byte, len(scan.Bytes())) copy(c, scan.Bytes()) + count++ os <- c } + log.Infof("Stored job with %d records read", count) }() return &Stream{ Pipe: out, diff --git a/mongo/processor.go b/mongo/processor.go index 783f21f1..4f2b72dd 100644 --- a/mongo/processor.go +++ b/mongo/processor.go @@ -88,7 +88,7 @@ func (proc *Processor) Process(ctx context.Context, man gdbi.Manager, in gdbi.In out <- eo case gdbi.SelectionData: - selections := map[string]gdbi.DataRef{} + selections := map[string]*gdbi.DataElement{} if marks, ok := result["marks"]; ok { if marks, ok := marks.(map[string]interface{}); ok { for k, v := range marks { diff --git a/server/job_manager.go b/server/job_manager.go index 081b8554..1e80cadc 100644 --- a/server/job_manager.go +++ b/server/job_manager.go @@ -37,7 +37,7 @@ func (server *GripServer) Submit(ctx context.Context, query *gripql.GraphQuery) &jobstorage.Stream{ DataType: dataType, MarkTypes: markTypes, - Pipe: res, + Pipe: res.Outputs, Query: query.Query, }) return &gripql.QueryJob{ @@ -125,9 +125,10 @@ func (server *GripServer) ResumeJob(query *gripql.ExtendQuery, srv gripql.Job_Re return err } compiler := graph.Compiler() - log.Infof("Compiling resume pipeline: %s", stream.DataType) + log.Debugf("Compiling resume pipeline: %s -> %s", stream.DataType, query.String()) pipe, err := compiler.Compile(query.Query, &gdbi.CompileOptions{PipelineExtension: stream.DataType, ExtensionMarkTypes: stream.MarkTypes}) if err != nil { + log.Debugf("User query compile error: %s", err) cancel() go func() { for range stream.Pipe { From ee443ff8c41337bb976b0fe120e198f3f6644dda Mon Sep 17 00:00:00 2001 From: Kyle Ellrott Date: Thu, 8 Feb 2024 16:19:51 -0800 Subject: [PATCH 08/23] Debugging output check optimizer and cleaning up debug logging --- conformance/tests/ot_bulk.py | 4 +- conformance/tests/ot_count.py | 4 +- conformance/tests/ot_job.py | 2 +- conformance/tests/ot_labels.py | 2 +- conformance/tests/ot_null.py | 4 +- engine/logic/jump.go | 16 +- gdbi/queue.go | 9 +- gdbi/traveler.go | 17 +- gripql/inspect/inspect.go | 11 + gripql/javascript/Makefile | 5 - gripql/javascript/gripql.js | 4 +- gripql/javascript/gripqljs.go | 481 +-------------------------------- log/logger.go | 4 +- travelerpath/jsonpath.go | 42 +++ 14 files changed, 94 insertions(+), 511 deletions(-) delete mode 100644 gripql/javascript/Makefile diff --git a/conformance/tests/ot_bulk.py b/conformance/tests/ot_bulk.py index bf12556e..49080af8 100644 --- a/conformance/tests/ot_bulk.py +++ b/conformance/tests/ot_bulk.py @@ -22,7 +22,7 @@ def test_bulkload(man): bulk.addEdge("4", "5", "created", {"weight": 1.0}) err = bulk.execute() - print(err) + #print(err) if err.get("errorCount", 0) != 0: print(err) errors.append("Bulk insertion error") @@ -67,5 +67,5 @@ def test_bulkload_validate(man): if err["errorCount"] == 0: errors.append("Validation error not detected") - print(err) + #print(err) return errors diff --git a/conformance/tests/ot_count.py b/conformance/tests/ot_count.py index 63fab79d..20391965 100644 --- a/conformance/tests/ot_count.py +++ b/conformance/tests/ot_count.py @@ -12,7 +12,7 @@ def test_count(man): errors.append("Fail: G.query().V().count() %s != %s" % (i[0]["count"], 39)) i = list(G.query().V("non-existent").count()) - print(i) + #print(i) if len(i) < 1: errors.append("Fail: nothing returned for O.query().V(\"non-existent\").count()") elif i[0]["count"] != 0: @@ -41,7 +41,7 @@ def test_count_when_no_data(man): G = man.writeTest() i = list(G.query().V().count()) - print(i) + #print(i) if len(i) < 1: errors.append("Fail: nothing returned for G.query().V().count()") elif i[0]["count"] != 0: diff --git a/conformance/tests/ot_job.py b/conformance/tests/ot_job.py index a9fcd66b..786bf030 100644 --- a/conformance/tests/ot_job.py +++ b/conformance/tests/ot_job.py @@ -18,7 +18,7 @@ def test_job(man): while True: cJob = G.getJob(job["id"]) - print(cJob) + #print(cJob) if cJob['state'] not in ["RUNNING", "QUEUED"]: break time.sleep(1) diff --git a/conformance/tests/ot_labels.py b/conformance/tests/ot_labels.py index ff802d1a..d610c3b5 100644 --- a/conformance/tests/ot_labels.py +++ b/conformance/tests/ot_labels.py @@ -6,7 +6,7 @@ def test_list_labels(man): G = man.setGraph("swapi") resp = G.listLabels() - print(resp) + #print(resp) if len(resp["vertexLabels"]) != 6: errors.append("listLabels returned an unexpected number of vertex labels; %d != 2" % (len(resp["vertex_labels"]))) diff --git a/conformance/tests/ot_null.py b/conformance/tests/ot_null.py index 51d5fc93..392fd233 100644 --- a/conformance/tests/ot_null.py +++ b/conformance/tests/ot_null.py @@ -24,13 +24,13 @@ def test_returnNil(man): #print("query 1") count_1 = 0 for i in G.query().V().hasLabel("Character").outNull("starships"): - print(i) + #print(i) count_1 += 1 #print("query 1") count_1 = 0 for i in G.query().V().hasLabel("Character").outENull("starships"): - print(i) + #print(i) count_1 += 1 return errors diff --git a/engine/logic/jump.go b/engine/logic/jump.go index dc4f0d35..b2fd383a 100644 --- a/engine/logic/jump.go +++ b/engine/logic/jump.go @@ -2,11 +2,11 @@ package logic import ( "context" - "fmt" "time" "github.com/bmeg/grip/gdbi" "github.com/bmeg/grip/gripql" + "github.com/bmeg/grip/log" ) // MarkJump creates mark where jump instruction can send travelers @@ -30,7 +30,7 @@ func (s *JumpMark) Process(ctx context.Context, man gdbi.Manager, in gdbi.InPipe case msg, ok := <-s.inputs[i]: if !ok { //jump point has closed, remove it from list - fmt.Printf("j closed %d \n", i) + log.Debugf("j closed %d \n", i) closeList = append(closeList, i) } else { //jump traveler recieved, pass on and skip reading input this cycle @@ -52,7 +52,7 @@ func (s *JumpMark) Process(ctx context.Context, man gdbi.Manager, in gdbi.InPipe case msg, ok := <-in: if !ok { //main input has closed, move onto closing phase - fmt.Printf("Got input close, messages: %d\n", mCount) + log.Debugf("Got input close, messages: %d\n", mCount) inputOpen = false } else { out <- msg @@ -72,7 +72,7 @@ func (s *JumpMark) Process(ctx context.Context, man gdbi.Manager, in gdbi.InPipe //are we waiting for a signal. This is canceled if new travelers are received. signalOutdated := false signalActive := false - fmt.Printf("Starting preclose\n") + log.Debugf("Starting preclose\n") for closed := false; !closed; { closeList := []int{} jumperFound := false @@ -81,7 +81,7 @@ func (s *JumpMark) Process(ctx context.Context, man gdbi.Manager, in gdbi.InPipe case msg, ok := <-s.inputs[i]: if !ok { //jump point has closed, remove it from list - fmt.Printf("j closed %d \n", i) + log.Debugf("j closed %d \n", i) closeList = append(closeList, i) } else { //jump traveler recieved, pass on and skip reading input this cycle @@ -112,10 +112,10 @@ func (s *JumpMark) Process(ctx context.Context, man gdbi.Manager, in gdbi.InPipe signalActive = true signalOutdated = false returnCount = 0 - fmt.Printf("Sending Signal %d\n", curID) + log.Debugf("Sending Signal %d\n", curID) out <- &gdbi.BaseTraveler{Signal: &gdbi.Signal{ID: curID, Dest: s.Name}} } else if signalActive && returnCount == len(s.inputs) { - fmt.Printf("Received %d of %d signals, closing after %d messages\n", returnCount, len(s.inputs), mCount) + log.Debugf("Received %d of %d signals, closing after %d messages\n", returnCount, len(s.inputs), mCount) closed = true } } @@ -184,7 +184,7 @@ func (s *Jump) Process(ctx context.Context, man gdbi.Manager, in gdbi.InPipe, ou mCount++ } } - fmt.Printf("Closing jump, messages: %d\n", mCount) + log.Debugf("Closing jump, messages: %d\n", mCount) }() return ctx } diff --git a/gdbi/queue.go b/gdbi/queue.go index 0c213691..a5164a01 100644 --- a/gdbi/queue.go +++ b/gdbi/queue.go @@ -1,8 +1,9 @@ package gdbi import ( - "fmt" "sync" + + "github.com/bmeg/grip/log" ) type MemQueue struct { @@ -30,7 +31,7 @@ func NewQueue() Queue { m.Lock() inCount++ if i.IsSignal() { - //fmt.Printf("Queue got signal %d\n", i.Signal.ID) + log.Debugf("Queue got signal %d\n", i.GetSignal().ID) } //fmt.Printf("Queue Size: %d %d / %d\n", len(queue), inCount, outCount) queue = append(queue, i) @@ -57,8 +58,8 @@ func NewQueue() Queue { outCount++ } } - fmt.Printf("Closing Queue Size: %d %d / %d\n", len(queue), inCount, outCount) - fmt.Printf("Closing Buffered Queue\n") + log.Debugf("Closing Queue Size: %d %d / %d\n", len(queue), inCount, outCount) + log.Debugf("Closing Buffered Queue\n") }() return &o } diff --git a/gdbi/traveler.go b/gdbi/traveler.go index d918778b..7d923734 100644 --- a/gdbi/traveler.go +++ b/gdbi/traveler.go @@ -205,13 +205,16 @@ func (elem *DataElement) ToEdge() *gripql.Edge { // ToDict converts data element to generic map func (elem *DataElement) ToDict() map[string]interface{} { - out := map[string]interface{}{ - "gid": "", - "label": "", - "to": "", - "from": "", - "data": map[string]interface{}{}, - } + /* + out := map[string]interface{}{ + "gid": "", + "label": "", + "to": "", + "from": "", + "data": map[string]interface{}{}, + } + */ + out := map[string]interface{}{} if elem == nil { return out } diff --git a/gripql/inspect/inspect.go b/gripql/inspect/inspect.go index 00530b0f..64ebda44 100644 --- a/gripql/inspect/inspect.go +++ b/gripql/inspect/inspect.go @@ -96,6 +96,17 @@ func PipelineStepOutputs(stmts []*gripql.GraphStatement) map[string][]string { } onLast = false } + + case *gripql.GraphStatement_Render: + val := gs.GetRender().AsInterface() + names := travelerpath.GetAllNamespaces(val) + for _, n := range names { + if a, ok := asMap[n]; ok { + out[a] = []string{"*"} + } + } + onLast = false + case *gripql.GraphStatement_Distinct: //if there is a distinct step, we need to load data, but only for requested fields fields := protoutil.AsStringList(gs.GetDistinct()) diff --git a/gripql/javascript/Makefile b/gripql/javascript/Makefile deleted file mode 100644 index 8efdc848..00000000 --- a/gripql/javascript/Makefile +++ /dev/null @@ -1,5 +0,0 @@ - -# go install github.com/go-bindata/go-bindata/... - -build: - go-bindata -nocompress -pkg gripqljs -o gripqljs.go gripql.js diff --git a/gripql/javascript/gripql.js b/gripql/javascript/gripql.js index 8164e3f9..f1d1e212 100644 --- a/gripql/javascript/gripql.js +++ b/gripql/javascript/gripql.js @@ -76,8 +76,8 @@ function query() { this.query.push({'as': name}) return this }, - select: function(marks) { - this.query.push({'select': {'marks': process(marks)}}) + select: function(name) { + this.query.push({'select': name}) return this }, limit: function(n) { diff --git a/gripql/javascript/gripqljs.go b/gripql/javascript/gripqljs.go index 4b2386c2..dc89e3d0 100644 --- a/gripql/javascript/gripqljs.go +++ b/gripql/javascript/gripqljs.go @@ -1,482 +1,13 @@ -// Code generated for package gripqljs by go-bindata DO NOT EDIT. (@generated) -// sources: -// gripql.js package gripqljs import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - "strings" - "time" + "embed" ) -type asset struct { - bytes []byte - info os.FileInfo -} - -type bindataFileInfo struct { - name string - size int64 - mode os.FileMode - modTime time.Time -} - -// Name return file name -func (fi bindataFileInfo) Name() string { - return fi.name -} - -// Size return file size -func (fi bindataFileInfo) Size() int64 { - return fi.size -} - -// Mode return file mode -func (fi bindataFileInfo) Mode() os.FileMode { - return fi.mode -} - -// Mode return file modify time -func (fi bindataFileInfo) ModTime() time.Time { - return fi.modTime -} - -// IsDir return file whether a directory -func (fi bindataFileInfo) IsDir() bool { - return fi.mode&os.ModeDir != 0 -} - -// Sys return file is sys mode -func (fi bindataFileInfo) Sys() interface{} { - return nil -} - -var _gripqlJs = []byte(`function process(val) { - if (!val) { - val = [] - } else if (typeof val == "string" || typeof val == "number") { - val = [val] - } else if (!Array.isArray(val)) { - throw "not something we know how to process into an array" - } - return val -} - -function query() { - return { - query: [], - V: function(id) { - this.query.push({'v': process(id)}) - return this - }, - E: function(id) { - this.query.push({'e': process(id)}) - return this - }, - out: function(label) { - this.query.push({'out': process(label)}) - return this - }, - outNull: function(label) { - this.query.push({'outNull': process(label)}) - return this - }, - in_: function(label) { - this.query.push({'in': process(label)}) - return this - }, - inNull: function(label) { - this.query.push({'inNull': process(label)}) - return this - }, - both: function(label) { - this.query.push({'both': process(label)}) - return this - }, - outV: function(label) { - this.query.push({'outV': process(label)}) - return this - }, - inV: function(label) { - this.query.push({'inV': process(label)}) - return this - }, - bothV: function(label) { - this.query.push({'bothV': process(label)}) - return this - }, - outE: function(label) { - this.query.push({'outE': process(label)}) - return this - }, - outENull: function(label) { - this.query.push({'outENull': process(label)}) - return this - }, - inE: function(label) { - this.query.push({'inE': process(label)}) - return this - }, - inENull: function(label) { - this.query.push({'inENull': process(label)}) - return this - }, - bothE: function(label) { - this.query.push({'bothE': process(label)}) - return this - }, - as_: function(name) { - this.query.push({'as': name}) - return this - }, - select: function(marks) { - this.query.push({'select': {'marks': process(marks)}}) - return this - }, - limit: function(n) { - this.query.push({'limit': n}) - return this - }, - skip: function(n) { - this.query.push({'skip': n}) - return this - }, - range: function(start, stop) { - this.query.push({'range': {'start': start, 'stop': stop}}) - return this - }, - count: function() { - this.query.push({'count': ''}) - return this - }, - distinct: function(val) { - this.query.push({'distinct': process(val)}) - return this - }, - fields: function(fields) { - this.query.push({'fields': fields}) - return this - }, - render: function(r) { - this.query.push({'render': r}) - return this - }, - has: function(expression) { - this.query.push({'has': expression}) - return this - }, - hasLabel: function(label) { - this.query.push({'hasLabel': process(label)}) - return this - }, - hasId: function(id) { - this.query.push({'hasId': process(id)}) - return this - }, - hasKey: function(key) { - this.query.push({'hasKey': process(key)}) - return this - }, - set: function(key, value) { - this.query.push({'set':{'key':key, 'value':value}}) - return this - }, - increment: function(key, value) { - this.query.push({'increment':{'key':key, 'value':value}}) - return this - }, - jump: function(mark, expression, emit) { - this.query.push({"jump": {"mark":mark, "expression" : expression, "emit":emit}}) - return this - }, - mark: function(name){ - this.query.push({"mark": name}) - return this - }, - aggregate: function() { - this.query.push({'aggregate': {'aggregations': Array.prototype.slice.call(arguments)}}) - return this - } - } -} - -// Where operators -function and_() { - return {'and': {'expressions': Array.prototype.slice.call(arguments)}} -} - -function or_() { - return {'or': {'expressions': Array.prototype.slice.call(arguments)}} -} - -function not_(expression) { - return {'not': expression} -} - -function eq(key, value) { - return {'condition': {'key': key, 'value': value, 'condition': 'EQ'}} -} - -function neq(key, value) { - return {'condition': {'key': key, 'value': value, 'condition': 'NEQ'}} -} - -function gt(key, value) { - return {'condition': {'key': key, 'value': value, 'condition': 'GT'}} -} - -function gte(key, value) { - return {'condition': {'key': key, 'value': value, 'condition': 'GTE'}} -} - -function lt(key, value) { - return {'condition': {'key': key, 'value': value, 'condition': 'LT'}} -} - -function lte(key, value) { - return {'condition': {'key': key, 'value': value, 'condition': 'LTE'}} -} - -function inside(key, values) { - return {'condition': {'key': key, 'value': process(values), 'condition': 'INSIDE'}} -} - -function outside(key, values) { - return {'condition': {'key': key, 'value': process(values), 'condition': 'OUTSIDE'}} -} - -function between(key, values) { - return {'condition': {'key': key, 'value': process(values), 'condition': 'BETWEEN'}} -} -function within(key, values) { - return {'condition': {'key': key, 'value': process(values), 'condition': 'WITHIN'}} -} - -function without(key, values) { - return {'condition': {'key': key, 'value': process(values), 'condition': 'WITHOUT'}} -} - -function contains(key, value) { - return {'condition': {'key': key, 'value': value, 'condition': 'CONTAINS'}} -} - -// Aggregation builders -function term(name, field, size) { - agg = { - "name": name, - "term": {"field": field} - } - if (size) { - if (typeof size != "number") { - throw "expected size to be a number" - } - agg["term"]["size"] = size - } - return agg -} - -function percentile(name, field, percents) { - if (!percents) { - percents = [1, 5, 25, 50, 75, 95, 99] - } else { - percents = process(percents) - } - - if (!percents.every(function(x){ return typeof x == "number" })) { - throw "percents expected to be an array of numbers" - } - - return { - "name": name, - "percentile": { - "field": field, "percents": percents - } - } -} - -function histogram(name, field, interval) { - if (interval) { - if (typeof interval != "number") { - throw "expected interval to be a number" - } - } - return { - "name": name, - "histogram": { - "field": field, "interval": interval - } - } -} - -function V(id) { - return query().V(id) -} - -function E(id) { - return query().E(id) -} -`) - -func gripqlJsBytes() ([]byte, error) { - return _gripqlJs, nil -} - -func gripqlJs() (*asset, error) { - bytes, err := gripqlJsBytes() - if err != nil { - return nil, err - } - - info := bindataFileInfo{name: "gripql.js", size: 5921, mode: os.FileMode(420), modTime: time.Unix(1689808257, 0)} - a := &asset{bytes: bytes, info: info} - return a, nil -} - -// Asset loads and returns the asset for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func Asset(name string) ([]byte, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) - } - return a.bytes, nil - } - return nil, fmt.Errorf("Asset %s not found", name) -} - -// MustAsset is like Asset but panics when Asset would return an error. -// It simplifies safe initialization of global variables. -func MustAsset(name string) []byte { - a, err := Asset(name) - if err != nil { - panic("asset: Asset(" + name + "): " + err.Error()) - } - - return a -} - -// AssetInfo loads and returns the asset info for the given name. -// It returns an error if the asset could not be found or -// could not be loaded. -func AssetInfo(name string) (os.FileInfo, error) { - cannonicalName := strings.Replace(name, "\\", "/", -1) - if f, ok := _bindata[cannonicalName]; ok { - a, err := f() - if err != nil { - return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) - } - return a.info, nil - } - return nil, fmt.Errorf("AssetInfo %s not found", name) -} - -// AssetNames returns the names of the assets. -func AssetNames() []string { - names := make([]string, 0, len(_bindata)) - for name := range _bindata { - names = append(names, name) - } - return names -} - -// _bindata is a table, holding each asset generator, mapped to its name. -var _bindata = map[string]func() (*asset, error){ - "gripql.js": gripqlJs, -} - -// AssetDir returns the file names below a certain -// directory embedded in the file by go-bindata. -// For example if you run go-bindata on data/... and data contains the -// following hierarchy: -// data/ -// foo.txt -// img/ -// a.png -// b.png -// then AssetDir("data") would return []string{"foo.txt", "img"} -// AssetDir("data/img") would return []string{"a.png", "b.png"} -// AssetDir("foo.txt") and AssetDir("notexist") would return an error -// AssetDir("") will return []string{"data"}. -func AssetDir(name string) ([]string, error) { - node := _bintree - if len(name) != 0 { - cannonicalName := strings.Replace(name, "\\", "/", -1) - pathList := strings.Split(cannonicalName, "/") - for _, p := range pathList { - node = node.Children[p] - if node == nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - } - } - if node.Func != nil { - return nil, fmt.Errorf("Asset %s not found", name) - } - rv := make([]string, 0, len(node.Children)) - for childName := range node.Children { - rv = append(rv, childName) - } - return rv, nil -} - -type bintree struct { - Func func() (*asset, error) - Children map[string]*bintree -} - -var _bintree = &bintree{nil, map[string]*bintree{ - "gripql.js": &bintree{gripqlJs, map[string]*bintree{}}, -}} - -// RestoreAsset restores an asset under the given directory -func RestoreAsset(dir, name string) error { - data, err := Asset(name) - if err != nil { - return err - } - info, err := AssetInfo(name) - if err != nil { - return err - } - err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) - if err != nil { - return err - } - err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) - if err != nil { - return err - } - err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) - if err != nil { - return err - } - return nil -} - -// RestoreAssets restores an asset under the given directory recursively -func RestoreAssets(dir, name string) error { - children, err := AssetDir(name) - // File - if err != nil { - return RestoreAsset(dir, name) - } - // Dir - for _, child := range children { - err = RestoreAssets(dir, filepath.Join(name, child)) - if err != nil { - return err - } - } - return nil -} +//go:embed gripql.js +var js embed.FS -func _filePath(dir, name string) string { - cannonicalName := strings.Replace(name, "\\", "/", -1) - return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) +func Asset(path string) (string, error) { + data, err := js.ReadFile(path) + return string(data), err } diff --git a/log/logger.go b/log/logger.go index 8874179e..9bb84edf 100644 --- a/log/logger.go +++ b/log/logger.go @@ -191,8 +191,8 @@ func (f *textFormatter) Format(entry *logrus.Entry) ([]byte, error) { fmt.Fprintf(b, "%s%-20s %v\n", f.Indent, aurora.Colorize(k, levelColor), v) } - - b.WriteByte('\n') + b.WriteString("-=-=-\n") + //b.WriteByte('\n') return b.Bytes(), nil } diff --git a/travelerpath/jsonpath.go b/travelerpath/jsonpath.go index 705293bc..9bce43c2 100644 --- a/travelerpath/jsonpath.go +++ b/travelerpath/jsonpath.go @@ -53,3 +53,45 @@ func GetJSONPath(path string) string { parts = append([]string{"$"}, parts...) return strings.Join(parts, ".") } + +func distinct(x []string) []string { + c := map[string]bool{} + for _, k := range x { + c[k] = true + } + out := []string{} + for k := range c { + out = append(out, k) + } + return out +} + +func GetAllNamespaces(d any) []string { + out := []string{} + + if x, ok := d.([]any); ok { + for _, c := range x { + l := GetAllNamespaces(c) + if len(l) > 0 { + out = append(out, l...) + } + } + return distinct(out) + } else if x, ok := d.(map[string]any); ok { + for k, v := range x { + if strings.HasPrefix(k, "$") { + out = append(out, GetNamespace(k)) + } + l := GetAllNamespaces(v) + if len(l) > 0 { + out = append(out, l...) + } + } + return distinct(out) + } else if x, ok := d.(string); ok { + if strings.HasPrefix(x, "$") { + out = append(out, GetNamespace(x)) + } + } + return out +} From c3798d03b062184bd06c104893b65a82cc066dba Mon Sep 17 00:00:00 2001 From: Kyle Ellrott Date: Thu, 8 Feb 2024 16:28:07 -0800 Subject: [PATCH 09/23] Adjusting unit tests to remove outdated elements --- {test => grids/test}/pathcompile_test.go | 0 test/processors_test.go | 65 ------------------------ 2 files changed, 65 deletions(-) rename {test => grids/test}/pathcompile_test.go (100%) diff --git a/test/pathcompile_test.go b/grids/test/pathcompile_test.go similarity index 100% rename from test/pathcompile_test.go rename to grids/test/pathcompile_test.go diff --git a/test/processors_test.go b/test/processors_test.go index fb146a63..4002fac3 100644 --- a/test/processors_test.go +++ b/test/processors_test.go @@ -354,41 +354,6 @@ func TestEngine(t *testing.T) { Q.V("users:11").As("a").OutE().As("b").Out().Has(gripql.Neq("_gid", "purchases:4")).Select("b").Out(), pick("purchases:26"), }, - { - Q.V("users:1").As("a").Out().As("b").Select("a", "b"), - pickSelection(map[string]interface{}{ - "a": getVertex("users:1"), - "b": getVertex("purchases:57"), - }), - }, - { - Q.V("users:1").Fields().As("a").Out().Fields().As("b").Select("a", "b"), - pickSelection(map[string]interface{}{ - "a": vertex("users:1", "users", nil), - "b": vertex("purchases:57", "purchases", nil), - }), - }, - { - Q.V("users:1").Fields("-created_at", "-deleted_at", "-details", "-id", "-password").As("a").Out().Fields().As("b").Select("a", "b"), - pickSelection(map[string]interface{}{ - "a": vertex("users:1", "users", data{"email": "Earlean.Bonacci@yahoo.com"}), - "b": vertex("purchases:57", "purchases", nil), - }), - }, - { - Q.V("users:1").Fields().As("a").Out().Fields("state").As("b").Select("a", "b"), - pickSelection(map[string]interface{}{ - "a": vertex("users:1", "users", nil), - "b": vertex("purchases:57", "purchases", data{"state": "IL"}), - }), - }, - { - Q.V("users:1").As("a").Fields().Out().As("b").Fields().Select("a", "b"), - pickSelection(map[string]interface{}{ - "a": getVertex("users:1"), - "b": getVertex("purchases:57"), - }), - }, { Q.V("users:1").As("a").Out().As("b"). Render(map[string]interface{}{"user_id": "$a._gid", "purchase_id": "$b._gid", "purchaser": "$b.name"}), @@ -554,36 +519,6 @@ func pickAllEdges() checker { return compare(expect) } -func pickSelection(selection map[string]interface{}) checker { - s := map[string]*gripql.Selection{} - for mark, ival := range selection { - switch val := ival.(type) { - case *gripql.Vertex: - s[mark] = &gripql.Selection{ - Result: &gripql.Selection_Vertex{ - Vertex: val, - }, - } - case *gripql.Edge: - s[mark] = &gripql.Selection{ - Result: &gripql.Selection_Edge{ - Edge: val, - }, - } - default: - panic(fmt.Sprintf("unhandled type %T", ival)) - } - } - expect := []*gripql.QueryResult{ - { - Result: &gripql.QueryResult_Selections{ - Selections: &gripql.Selections{Selections: s}, - }, - }, - } - return compare(expect) -} - func count(i int) checker { expect := []*gripql.QueryResult{ { From d526ab640e269d11c329c6723cbc87e273ea3c0a Mon Sep 17 00:00:00 2001 From: Kyle Ellrott Date: Fri, 9 Feb 2024 08:52:08 -0800 Subject: [PATCH 10/23] Starting to refactor mongo data storage, to eliminate using the `data` element and put all data at the top level, with key fields as underscores (_label, _to, _from) --- mongo/compile.go | 227 +++++++++++++++++++----------------------- mongo/compile_test.go | 2 +- mongo/convert.go | 61 +++++++----- mongo/graph.go | 70 ++++++------- mongo/index.go | 6 +- mongo/processor.go | 37 ++++--- 6 files changed, 200 insertions(+), 203 deletions(-) diff --git a/mongo/compile.go b/mongo/compile.go index 1b83c1fd..206643d4 100644 --- a/mongo/compile.go +++ b/mongo/compile.go @@ -99,15 +99,13 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile startCollection = vertCol ids := protoutil.AsStringList(stmt.V) if len(ids) > 0 { - query = append(query, bson.D{primitive.E{Key: "$match", Value: bson.M{"_id": bson.M{"$in": ids}}}}) + query = append(query, bson.D{primitive.E{Key: "$match", Value: bson.M{FIELD_ID: bson.M{"$in": ids}}}}) } query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - "_id": "$_id", - "label": "$label", - "data": "$data", - "marks": "$marks", - "path": []interface{}{bson.M{"vertex": "$_id"}}, + FIELD_CURRENT: "$$CURRENT", + "marks": "$marks", + "path": []interface{}{bson.M{"vertex": "$_id"}}, }, }}) lastType = gdbi.VertexData @@ -119,19 +117,16 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile startCollection = edgeCol ids := protoutil.AsStringList(stmt.E) if len(ids) > 0 { - query = append(query, bson.D{primitive.E{Key: "$match", Value: bson.M{"_id": bson.M{"$in": ids}}}}) + query = append(query, bson.D{primitive.E{Key: "$match", Value: bson.M{FIELD_ID: bson.M{"$in": ids}}}}) } query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - "_id": "$_id", - "to": "$to", - "from": "$from", - "label": "$label", - "data": "$data", - "marks": "$marks", - "path": []interface{}{bson.M{"edge": "$_id"}}, + FIELD_CURRENT: "$$CURRENT", + "marks": "$marks", + "path": []interface{}{bson.M{"edge": FIELD_ID}}, }, }}) + lastType = gdbi.EdgeData case *gripql.GraphStatement_In, *gripql.GraphStatement_InNull: @@ -149,9 +144,9 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile bson.D{primitive.E{ Key: "$lookup", Value: bson.M{ "from": edgeCol, - "localField": "_id", - "foreignField": "to", - "as": "dst", + "localField": FIELD_CURRENT_ID, + "foreignField": FIELD_TO, + "as": FIELD_DST, }, }}, ) @@ -159,12 +154,12 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ "marks": "$marks", "path": "$path", - "dst": bson.M{ + FIELD_DST: bson.M{ "$filter": bson.M{ "input": "$dst", "as": "d", "cond": bson.M{ - "$in": bson.A{"$$d.label", labels}, + "$in": bson.A{"$$d._label", labels}, }, }, }, @@ -176,12 +171,9 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile query = append(query, bson.D{primitive.E{Key: "$unwind", Value: "$dst"}}) } query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - "_id": "$dst._id", - "label": "$dst.label", - "to": "$dst.to", - "from": "$dst.from", - "marks": "$marks", - "path": "$path", + FIELD_CURRENT: "$dst", + "marks": "$marks", + "path": "$path", }}}) } else { if len(labels) > 0 { @@ -192,8 +184,8 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile bson.D{primitive.E{ Key: "$lookup", Value: bson.M{ "from": vertCol, - "localField": "from", - "foreignField": "_id", + "localField": FIELD_CURRENT_FROM, + "foreignField": FIELD_ID, "as": "dst", }, }}, @@ -204,11 +196,9 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile query = append(query, bson.D{primitive.E{Key: "$unwind", Value: "$dst"}}) } query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - "_id": "$dst._id", - "label": "$dst.label", - "data": "$dst.data", - "marks": "$marks", - "path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"vertex": "$dst._id"}}}}, + FIELD_CURRENT: "$dst", + "marks": "$marks", + "path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"vertex": "$dst._id"}}}}, }}}) lastType = gdbi.VertexData @@ -227,8 +217,8 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile bson.D{primitive.E{ Key: "$lookup", Value: bson.M{ "from": edgeCol, - "localField": "_id", - "foreignField": "from", + "localField": FIELD_CURRENT_ID, + "foreignField": FIELD_FROM, "as": "dst", }, }}, @@ -242,7 +232,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile "input": "$dst", "as": "d", "cond": bson.M{ - "$in": bson.A{"$$d.label", labels}, + "$in": bson.A{"$$d._label", labels}, }, }, }, @@ -254,16 +244,13 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile query = append(query, bson.D{primitive.E{Key: "$unwind", Value: "$dst"}}) } query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - "_id": "$dst._id", - "label": "$dst.label", - "to": "$dst.to", - "from": "$dst.from", - "marks": "$marks", - "path": "$path", + FIELD_CURRENT: "$dst", + "marks": "$marks", + "path": "$path", }}}) } else { if len(labels) > 0 { - query = append(query, bson.D{primitive.E{Key: "$match", Value: bson.M{"label": bson.M{"$in": labels}}}}) + query = append(query, bson.D{primitive.E{Key: "$match", Value: bson.M{FIELD_LABEL: bson.M{"$in": labels}}}}) } } @@ -271,8 +258,8 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile bson.D{primitive.E{ Key: "$lookup", Value: bson.M{ "from": vertCol, - "localField": "to", - "foreignField": "_id", + "localField": FIELD_CURRENT_TO, + "foreignField": FIELD_ID, "as": "dst", }, }}, @@ -283,9 +270,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile query = append(query, bson.D{primitive.E{Key: "$unwind", Value: "$dst"}}) } query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - "_id": "$dst._id", - "label": "$dst.label", - "data": "$dst.data", + "data": "$dst", "marks": "$marks", "path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"vertex": "$dst._id"}}}}, }}}) @@ -301,14 +286,14 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile bson.D{primitive.E{ Key: "$lookup", Value: bson.M{ "from": edgeCol, - "let": bson.M{"vid": "$_id", "marks": "$marks"}, + "let": bson.M{"vid": "$data._id", "marks": "$marks"}, "pipeline": []bson.M{ { "$match": bson.M{ "$expr": bson.M{ "$or": []bson.M{ - {"$eq": []string{"$to", "$$vid"}}, - {"$eq": []string{"$from", "$$vid"}}, + {"$eq": []string{"$_to", "$$vid"}}, + {"$eq": []string{"$_from", "$$vid"}}, }, }, }, @@ -323,24 +308,22 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile ) query = append(query, bson.D{primitive.E{Key: "$unwind", Value: "$dst"}}) query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - "_id": "$dst._id", - "label": "$dst.label", - "data": "$dst.data", - "to": "$dst.to", - "from": "$dst.from", - "marks": "$marks", - "vid": "$_id", - "path": "$path", + FIELD_CURRENT: "$dst", + "marks": "$marks", + "vid": "$data._id", + "path": "$path", }}}) } + // filter outgoing edges by label is needed if len(labels) > 0 { - query = append(query, bson.D{primitive.E{Key: "$match", Value: bson.M{"label": bson.M{"$in": labels}}}}) + query = append(query, bson.D{primitive.E{Key: "$match", Value: bson.M{"data._label": bson.M{"$in": labels}}}}) } + // lookup the vertex on the other end of that edge query = append(query, bson.D{primitive.E{ Key: "$lookup", Value: bson.M{ "from": vertCol, - "let": bson.M{"to": "$to", "from": "$from", "marks": "$marks", "vid": "$vid"}, + "let": bson.M{"to": "$data._to", "from": "$data._from", "marks": "$marks", "vid": "$vid"}, "pipeline": []bson.M{ { "$match": bson.M{ @@ -366,11 +349,9 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile ) query = append(query, bson.D{primitive.E{Key: "$unwind", Value: "$dst"}}) query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - "_id": "$dst._id", - "label": "$dst.label", - "data": "$dst.data", - "marks": "$marks", - "path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"vertex": "$dst._id"}}}}, + FIELD_CURRENT: "$dst", + "marks": "$marks", + "path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"vertex": "$dst._id"}}}}, }}}) lastType = gdbi.VertexData @@ -388,8 +369,8 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile bson.D{primitive.E{ Key: "$lookup", Value: bson.M{ "from": edgeCol, - "localField": "_id", - "foreignField": "to", + "localField": FIELD_ID, + "foreignField": FIELD_TO, "as": "dst", }, }}, @@ -403,7 +384,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile "input": "$dst", "as": "d", "cond": bson.M{ - "$in": bson.A{"$$d.label", labels}, + "$in": bson.A{"$$d._label", labels}, }, }, }, @@ -415,13 +396,13 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile query = append(query, bson.D{primitive.E{Key: "$unwind", Value: "$dst"}}) } query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - "_id": "$dst._id", - "label": "$dst.label", - "data": "$dst.data", - "to": "$dst.to", - "from": "$dst.from", - "marks": "$marks", - "path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"edge": "$dst._id"}}}}, + FIELD_ID: "$dst._id", + FIELD_LABEL: "$dst._label", + FIELD_TO: "$dst._to", + FIELD_FROM: "$dst._from", + "data": "$dst", + "marks": "$marks", + "path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"edge": "$dst._id"}}}}, }}}) lastType = gdbi.EdgeData @@ -440,8 +421,8 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile bson.D{primitive.E{ Key: "$lookup", Value: bson.M{ "from": edgeCol, - "localField": "_id", - "foreignField": "from", + "localField": FIELD_ID, + "foreignField": FIELD_FROM, "as": "dst", }, }}, @@ -455,7 +436,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile "input": "$dst", "as": "d", "cond": bson.M{ - "$in": bson.A{"$$d.label", labels}, + "$in": bson.A{"$$d._label", labels}, }, }, }, @@ -467,13 +448,13 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile query = append(query, bson.D{primitive.E{Key: "$unwind", Value: "$dst"}}) } query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - "_id": "$dst._id", - "label": "$dst.label", - "data": "$dst.data", - "to": "$dst.to", - "from": "$dst.from", - "marks": "$marks", - "path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"edge": "$dst._id"}}}}, + FIELD_ID: "$dst._id", + FIELD_LABEL: "$dst._label", + FIELD_TO: "$dst._to", + FIELD_FROM: "$dst._from", + "data": "$dst", + "marks": "$marks", + "path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"edge": "$dst._id"}}}}, }}}) lastType = gdbi.EdgeData @@ -491,8 +472,8 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile "$match": bson.M{ "$expr": bson.M{ "$or": []bson.M{ - {"$eq": []string{"$to", "$$vid"}}, - {"$eq": []string{"$from", "$$vid"}}, + {"$eq": []string{"$_to", "$$vid"}}, + {"$eq": []string{"$_from", "$$vid"}}, }, }, }, @@ -507,17 +488,17 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile ) query = append(query, bson.D{primitive.E{Key: "$unwind", Value: "$dst"}}) query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - "_id": "$dst._id", - "label": "$dst.label", - "data": "$dst.data", - "to": "$dst.to", - "from": "$dst.from", - "marks": "$marks", - "path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"edge": "$dst._id"}}}}, + FIELD_ID: "$dst._id", + FIELD_LABEL: "$dst._label", + FIELD_TO: "$dst._to", + FIELD_FROM: "$dst._from", + "data": "$dst.data", + "marks": "$marks", + "path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"edge": "$dst._id"}}}}, }}}) labels := protoutil.AsStringList(stmt.BothE) if len(labels) > 0 { - query = append(query, bson.D{primitive.E{Key: "$match", Value: bson.M{"label": bson.M{"$in": labels}}}}) + query = append(query, bson.D{primitive.E{Key: "$match", Value: bson.M{FIELD_LABEL: bson.M{"$in": labels}}}}) } lastType = gdbi.EdgeData @@ -538,7 +519,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile for i, v := range labels { ilabels[i] = v } - has := gripql.Within("_label", ilabels...) + has := gripql.Within(FIELD_LABEL, ilabels...) whereExpr := convertHasExpression(has, false) matchStmt := bson.D{primitive.E{Key: "$match", Value: whereExpr}} query = append(query, matchStmt) @@ -552,7 +533,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile for i, v := range ids { iids[i] = v } - has := gripql.Within("_gid", iids...) + has := gripql.Within(FIELD_ID, iids...) whereExpr := convertHasExpression(has, false) matchStmt := bson.D{primitive.E{Key: "$match", Value: whereExpr}} query = append(query, matchStmt) @@ -597,7 +578,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile } fields := protoutil.AsStringList(stmt.Distinct) if len(fields) == 0 { - fields = append(fields, "_gid") + fields = append(fields, FIELD_ID) } keys := bson.M{} match := bson.M{} @@ -628,21 +609,21 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile switch lastType { case gdbi.VertexData: query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - "_id": "$dst._id", - "label": "$dst.label", - "data": "$dst.data", - "marks": "$dst.marks", - "path": "$dst.path", + FIELD_ID: "$dst._id", + FIELD_LABEL: "$dst._label", + "data": "$dst.data", + "marks": "$dst.marks", + "path": "$dst.path", }}}) case gdbi.EdgeData: query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - "_id": "$dst._id", - "label": "$dst.label", - "data": "$dst.data", - "to": "$dst.to", - "from": "$dst.from", - "marks": "$dst.marks", - "path": "$dst.path", + FIELD_ID: "$dst._id", + FIELD_LABEL: "$dst.label", + FIELD_TO: "$dst.to", + FIELD_FROM: "$dst.from", + "data": "$dst.data", + "marks": "$dst.marks", + "path": "$dst.path", }}}) } @@ -670,23 +651,23 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile switch markTypes[stmt.Select] { case gdbi.VertexData: query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - "_id": mark + "._id", - "label": mark + ".label", - "data": mark + ".data", - "marks": 1, - "path": "$path", + "_id": mark + "._id", + "_label": mark + "._label", + "data": mark + ".data", + "marks": 1, + "path": "$path", //"path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"vertex": mark + "._id"}}}}, }}}) lastType = gdbi.VertexData case gdbi.EdgeData: query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - "_id": mark + "._id", - "label": mark + ".label", - "from": mark + ".from", - "to": mark + ".to", - "data": mark + ".data", - "marks": 1, - "path": "$path", + "_id": mark + "._id", + "_label": mark + "._label", + "_from": mark + "._from", + "_to": mark + "._to", + "data": mark + ".data", + "marks": 1, + "path": "$path", //"path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"edge": mark + "._id"}}}}, }}}) lastType = gdbi.EdgeData @@ -744,7 +725,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile } if len(includeFields) > 0 || len(excludeFields) == 0 { - fieldSelect = bson.M{"_id": 1, "label": 1, "from": 1, "to": 1, "marks": 1} + fieldSelect = bson.M{"_id": 1, "_label": 1, "_from": 1, "_to": 1, "marks": 1} for _, v := range excludeFields { switch v { case "gid": diff --git a/mongo/compile_test.go b/mongo/compile_test.go index 3ea0cba2..b3bf2c6f 100644 --- a/mongo/compile_test.go +++ b/mongo/compile_test.go @@ -42,7 +42,7 @@ func TestDistinctPathing(t *testing.T) { f = travelerpath.GetJSONPath(f) f = strings.TrimPrefix(f, "$.") if f == "gid" { - f = "_id" + f = FIELD_ID } if namespace != travelerpath.Current { f = fmt.Sprintf("marks.%s.%s", namespace, f) diff --git a/mongo/convert.go b/mongo/convert.go index 8abf0926..33301b2d 100644 --- a/mongo/convert.go +++ b/mongo/convert.go @@ -12,11 +12,14 @@ func PackVertex(v *gdbi.Vertex) map[string]interface{} { if v.Data != nil { p = v.Data } - return map[string]interface{}{ - "_id": v.ID, - "label": v.Label, - "data": p, + out := map[string]interface{}{ + "_id": v.ID, + "_label": v.Label, } + for k, v := range p { + out[k] = v + } + return out } // PackEdge takes a GRIP edge and converts it to a mongo doc @@ -25,13 +28,16 @@ func PackEdge(e *gdbi.Edge) map[string]interface{} { if e.Data != nil { p = e.Data } - return map[string]interface{}{ - "_id": e.ID, - "from": e.From, - "to": e.To, - "label": e.Label, - "data": p, + out := map[string]interface{}{ + "_id": e.ID, + "_from": e.From, + "_to": e.To, + "_label": e.Label, + } + for k, v := range p { + out[k] = v } + return out } type pair struct { @@ -44,15 +50,15 @@ type pair struct { func UnpackVertex(i map[string]interface{}) *gdbi.Vertex { o := &gdbi.Vertex{} o.ID = i["_id"].(string) - o.Label = i["label"].(string) - if d, ok := i["data"]; ok { - d = removePrimatives(d) - o.Data = d.(map[string]interface{}) - o.Loaded = true - } else { - o.Loaded = false - o.Data = map[string]interface{}{} + o.Label = i["_label"].(string) + d := removePrimatives(i).(map[string]any) + o.Data = map[string]any{} + for k, v := range d { + if k != "_id" && k != "_label" { + o.Data[k] = v + } } + o.Loaded = true return o } @@ -61,16 +67,17 @@ func UnpackEdge(i map[string]interface{}) *gdbi.Edge { o := &gdbi.Edge{} id := i["_id"] o.ID = id.(string) - o.Label = i["label"].(string) - o.From = i["from"].(string) - o.To = i["to"].(string) - if d, ok := i["data"]; ok { - o.Data = d.(map[string]interface{}) - o.Loaded = true - } else { - o.Loaded = false - o.Data = map[string]interface{}{} + o.Label = i["_label"].(string) + o.From = i["_from"].(string) + o.To = i["_to"].(string) + o.Data = map[string]any{} + d := removePrimatives(i).(map[string]any) + for k, v := range d { + if k != "_id" && k != "_label" && k != "_to" && k != "from" { + o.Data[k] = v + } } + o.Loaded = true return o } diff --git a/mongo/graph.go b/mongo/graph.go index 4554ae5b..eab9957e 100644 --- a/mongo/graph.go +++ b/mongo/graph.go @@ -45,9 +45,9 @@ func (mg *Graph) GetTimestamp() string { func (mg *Graph) GetVertex(id string, load bool) *gdbi.Vertex { opts := options.FindOne() if !load { - opts.SetProjection(map[string]interface{}{"_id": 1, "label": 1}) + opts.SetProjection(map[string]interface{}{FIELD_ID: 1, FIELD_LABEL: 1}) } - result := mg.ar.VertexCollection(mg.graph).FindOne(context.Background(), bson.M{"_id": id}, opts) + result := mg.ar.VertexCollection(mg.graph).FindOne(context.Background(), bson.M{FIELD_ID: id}, opts) if result.Err() != nil { return nil } @@ -63,9 +63,9 @@ func (mg *Graph) GetVertex(id string, load bool) *gdbi.Vertex { func (mg *Graph) GetEdge(id string, load bool) *gdbi.Edge { opts := options.FindOne() if !load { - opts.SetProjection(map[string]interface{}{"_id": 1, "label": 1, "from": 1, "to": 1}) + opts.SetProjection(map[string]interface{}{FIELD_ID: 1, FIELD_LABEL: 1, FIELD_FROM: 1, FIELD_TO: 1}) } - result := mg.ar.EdgeCollection(mg.graph).FindOne(context.TODO(), bson.M{"_id": id}, opts) + result := mg.ar.EdgeCollection(mg.graph).FindOne(context.TODO(), bson.M{FIELD_ID: id}, opts) if result.Err() != nil { return nil } @@ -84,7 +84,7 @@ func (mg *Graph) AddVertex(vertices []*gdbi.Vertex) error { var err error docBatch := make([]mongo.WriteModel, 0, len(vertices)) for _, v := range vertices { - i := mongo.NewReplaceOneModel().SetUpsert(true).SetFilter(bson.M{"_id": v.ID}) + i := mongo.NewReplaceOneModel().SetUpsert(true).SetFilter(bson.M{FIELD_ID: v.ID}) ent := PackVertex(v) i.SetReplacement(ent) docBatch = append(docBatch, i) @@ -105,7 +105,7 @@ func (mg *Graph) AddEdge(edges []*gdbi.Edge) error { var err error docBatch := make([]mongo.WriteModel, 0, len(edges)) for _, edge := range edges { - i := mongo.NewReplaceOneModel().SetUpsert(true).SetFilter(bson.M{"_id": edge.ID}) + i := mongo.NewReplaceOneModel().SetUpsert(true).SetFilter(bson.M{FIELD_ID: edge.ID}) ent := PackEdge(edge) i.SetReplacement(ent) docBatch = append(docBatch, i) @@ -123,7 +123,7 @@ func (mg *Graph) BulkAdd(stream <-chan *gdbi.GraphElement) error { // deleteConnectedEdges deletes edges where `from` or `to` equal `key` func (mg *Graph) deleteConnectedEdges(key string) error { eCol := mg.ar.EdgeCollection(mg.graph) - _, err := eCol.DeleteMany(context.TODO(), bson.M{"$or": []bson.M{{"from": key}, {"to": key}}}) + _, err := eCol.DeleteMany(context.TODO(), bson.M{"$or": []bson.M{{FIELD_FROM: key}, {FIELD_TO: key}}}) if err != nil { return fmt.Errorf("failed to delete edge(s): %s", err) } @@ -134,7 +134,7 @@ func (mg *Graph) deleteConnectedEdges(key string) error { // DelVertex deletes vertex with id `key` func (mg *Graph) DelVertex(key string) error { vCol := mg.ar.VertexCollection(mg.graph) - _, err := vCol.DeleteOne(context.TODO(), bson.M{"_id": key}) + _, err := vCol.DeleteOne(context.TODO(), bson.M{FIELD_ID: key}) if err != nil { return fmt.Errorf("failed to delete vertex %s: %s", key, err) } @@ -149,7 +149,7 @@ func (mg *Graph) DelVertex(key string) error { // DelEdge deletes edge with id `key` func (mg *Graph) DelEdge(key string) error { eCol := mg.ar.EdgeCollection(mg.graph) - _, err := eCol.DeleteOne(context.TODO(), bson.M{"_id": key}) + _, err := eCol.DeleteOne(context.TODO(), bson.M{FIELD_ID: key}) if err != nil { return fmt.Errorf("failed to delete edge %s: %s", key, err) } @@ -166,7 +166,7 @@ func (mg *Graph) GetVertexList(ctx context.Context, load bool) <-chan *gdbi.Vert vCol := mg.ar.VertexCollection(mg.graph) opts := options.Find() if !load { - opts.SetProjection(bson.M{"_id": 1, "label": 1}) + opts.SetProjection(bson.M{FIELD_ID: 1, FIELD_LABEL: 1}) } query, err := vCol.Find(ctx, bson.M{}, opts) if err != nil { @@ -201,7 +201,7 @@ func (mg *Graph) GetEdgeList(ctx context.Context, loadProp bool) <-chan *gdbi.Ed eCol := mg.ar.EdgeCollection(mg.graph) opts := options.Find() if !loadProp { - opts.SetProjection(bson.M{"_id": 1, "to": 1, "from": 1, "label": 1}) + opts.SetProjection(bson.M{FIELD_ID: 1, FIELD_TO: 1, FIELD_FROM: 1, FIELD_LABEL: 1}) } query, err := eCol.Find(ctx, bson.M{}, opts) if err != nil { @@ -216,7 +216,7 @@ func (mg *Graph) GetEdgeList(ctx context.Context, loadProp bool) <-chan *gdbi.Ed default: } if err := query.Decode(&result); err == nil { - if _, ok := result["to"]; ok { + if _, ok := result[FIELD_TO]; ok { e := UnpackEdge(result) o <- e } @@ -248,10 +248,10 @@ func (mg *Graph) GetVertexChannel(ctx context.Context, ids chan gdbi.ElementLook idBatch = append(idBatch, batch[i].ID) } } - query := bson.M{"_id": bson.M{"$in": idBatch}} + query := bson.M{FIELD_ID: bson.M{"$in": idBatch}} opts := options.Find() if !load { - opts.SetProjection(bson.M{"_id": 1, "label": 1}) + opts.SetProjection(bson.M{FIELD_ID: 1, FIELD_LABEL: 1}) } cursor, err := vCol.Find(context.TODO(), query, opts) if err != nil { @@ -305,17 +305,18 @@ func (mg *Graph) GetOutChannel(ctx context.Context, reqChan chan gdbi.ElementLoo batchMapReturnCount[batch[i].ID] = 0 } } - query := []bson.M{{"$match": bson.M{"from": bson.M{"$in": idBatch}}}} + query := []bson.M{{"$match": bson.M{FIELD_FROM: bson.M{"$in": idBatch}}}} if len(edgeLabels) > 0 { - query = append(query, bson.M{"$match": bson.M{"label": bson.M{"$in": edgeLabels}}}) + query = append(query, bson.M{"$match": bson.M{FIELD_LABEL: bson.M{"$in": edgeLabels}}}) } vertCol := fmt.Sprintf("%s_vertices", mg.graph) - query = append(query, bson.M{"$lookup": bson.M{"from": vertCol, "localField": "to", "foreignField": "_id", "as": "dst"}}) + query = append(query, bson.M{"$lookup": bson.M{FIELD_FROM: vertCol, "localField": FIELD_TO, "foreignField": FIELD_ID, "as": "dst"}}) query = append(query, bson.M{"$unwind": "$dst"}) if load { - query = append(query, bson.M{"$project": bson.M{"from": true, "dst._id": true, "dst.label": true, "dst.data": true}}) + //query = append(query, bson.M{"$project": bson.M{FIELD_FROM: true, "dst._id": true, "dst._label": true, "dst.data": true}}) + query = append(query, bson.M{"$project": bson.M{FIELD_FROM: true, "dst": true}}) } else { - query = append(query, bson.M{"$project": bson.M{"from": true, "dst._id": true, "dst.label": true}}) + query = append(query, bson.M{"$project": bson.M{FIELD_FROM: true, "dst._id": true, "dst._label": true}}) } eCol := mg.ar.EdgeCollection(mg.graph) @@ -326,7 +327,7 @@ func (mg *Graph) GetOutChannel(ctx context.Context, reqChan chan gdbi.ElementLoo if err := cursor.Decode(&result); err == nil { if dst, ok := result["dst"].(map[string]interface{}); ok { v := UnpackVertex(dst) - fromID := result["from"].(string) + fromID := result[FIELD_FROM].(string) r := batchMap[fromID] batchMapReturnCount[fromID]++ for _, ri := range r { @@ -384,17 +385,18 @@ func (mg *Graph) GetInChannel(ctx context.Context, reqChan chan gdbi.ElementLook batchMapReturnCount[batch[i].ID] = 0 } } - query := []bson.M{{"$match": bson.M{"to": bson.M{"$in": idBatch}}}} + query := []bson.M{{"$match": bson.M{FIELD_TO: bson.M{"$in": idBatch}}}} if len(edgeLabels) > 0 { - query = append(query, bson.M{"$match": bson.M{"label": bson.M{"$in": edgeLabels}}}) + query = append(query, bson.M{"$match": bson.M{FIELD_LABEL: bson.M{"$in": edgeLabels}}}) } vertCol := fmt.Sprintf("%s_vertices", mg.graph) - query = append(query, bson.M{"$lookup": bson.M{"from": vertCol, "localField": "from", "foreignField": "_id", "as": "src"}}) + query = append(query, bson.M{"$lookup": bson.M{FIELD_FROM: vertCol, "localField": FIELD_FROM, "foreignField": FIELD_ID, "as": "src"}}) query = append(query, bson.M{"$unwind": "$src"}) if load { - query = append(query, bson.M{"$project": bson.M{"to": true, "src._id": true, "src.label": true, "src.data": true}}) + //query = append(query, bson.M{"$project": bson.M{FIELD_TO: true, "src._id": true, "src._label": true, "src.data": true}}) //FIX: .data no longer used + query = append(query, bson.M{"$project": bson.M{FIELD_TO: true, "src._id": true, "src": true}}) } else { - query = append(query, bson.M{"$project": bson.M{"to": true, "src._id": true, "src.label": true}}) + query = append(query, bson.M{"$project": bson.M{FIELD_TO: true, "src._id": true, "src._label": true}}) } eCol := mg.ar.EdgeCollection(mg.graph) @@ -405,7 +407,7 @@ func (mg *Graph) GetInChannel(ctx context.Context, reqChan chan gdbi.ElementLook if err := cursor.Decode(&result); err == nil { if src, ok := result["src"].(map[string]interface{}); ok { v := UnpackVertex(src) - toID := result["to"].(string) + toID := result[FIELD_TO].(string) r := batchMap[toID] batchMapReturnCount[toID]++ for _, ri := range r { @@ -463,9 +465,9 @@ func (mg *Graph) GetOutEdgeChannel(ctx context.Context, reqChan chan gdbi.Elemen batchMapReturnCount[batch[i].ID] = 0 } } - query := []bson.M{{"$match": bson.M{"from": bson.M{"$in": idBatch}}}} + query := []bson.M{{"$match": bson.M{FIELD_FROM: bson.M{"$in": idBatch}}}} if len(edgeLabels) > 0 { - query = append(query, bson.M{"$match": bson.M{"label": bson.M{"$in": edgeLabels}}}) + query = append(query, bson.M{"$match": bson.M{FIELD_LABEL: bson.M{"$in": edgeLabels}}}) } eCol := mg.ar.EdgeCollection(mg.graph) cursor, err := eCol.Aggregate(context.TODO(), query) @@ -474,7 +476,7 @@ func (mg *Graph) GetOutEdgeChannel(ctx context.Context, reqChan chan gdbi.Elemen for cursor.Next(context.TODO()) { if err := cursor.Decode(&result); err == nil { e := UnpackEdge(result) - fromID := result["from"].(string) + fromID := result[FIELD_FROM].(string) r := batchMap[fromID] batchMapReturnCount[fromID]++ for _, ri := range r { @@ -530,9 +532,9 @@ func (mg *Graph) GetInEdgeChannel(ctx context.Context, reqChan chan gdbi.Element batchMapReturnCount[batch[i].ID] = 0 } } - query := []bson.M{{"$match": bson.M{"to": bson.M{"$in": idBatch}}}} + query := []bson.M{{"$match": bson.M{FIELD_TO: bson.M{"$in": idBatch}}}} if len(edgeLabels) > 0 { - query = append(query, bson.M{"$match": bson.M{"label": bson.M{"$in": edgeLabels}}}) + query = append(query, bson.M{"$match": bson.M{FIELD_LABEL: bson.M{"$in": edgeLabels}}}) } eCol := mg.ar.EdgeCollection(mg.graph) cursor, err := eCol.Aggregate(context.TODO(), query) @@ -541,7 +543,7 @@ func (mg *Graph) GetInEdgeChannel(ctx context.Context, reqChan chan gdbi.Element for cursor.Next(context.TODO()) { if err := cursor.Decode(&result); err == nil { e := UnpackEdge(result) - toID := result["to"].(string) + toID := result[FIELD_TO].(string) r := batchMap[toID] batchMapReturnCount[toID]++ for _, ri := range r { @@ -579,7 +581,7 @@ func (mg *Graph) GetInEdgeChannel(ctx context.Context, reqChan chan gdbi.Element // ListVertexLabels returns a list of vertex types in the graph func (mg *Graph) ListVertexLabels() ([]string, error) { v := mg.ar.VertexCollection(mg.graph) - out, err := v.Distinct(context.TODO(), "label", bson.M{}) + out, err := v.Distinct(context.TODO(), FIELD_LABEL, bson.M{}) if err != nil { return nil, err } @@ -593,7 +595,7 @@ func (mg *Graph) ListVertexLabels() ([]string, error) { // ListEdgeLabels returns a list of edge types in the graph func (mg *Graph) ListEdgeLabels() ([]string, error) { e := mg.ar.EdgeCollection(mg.graph) - out, err := e.Distinct(context.TODO(), "label", bson.M{}) + out, err := e.Distinct(context.TODO(), FIELD_LABEL, bson.M{}) if err != nil { return nil, err } diff --git a/mongo/index.go b/mongo/index.go index bd9a3db0..55e7a9ff 100644 --- a/mongo/index.go +++ b/mongo/index.go @@ -110,11 +110,11 @@ func (mg *Graph) VertexLabelScan(ctx context.Context, label string) chan string go func() { defer close(out) selection := map[string]interface{}{ - "label": label, + FIELD_LABEL: label, } vcol := mg.ar.VertexCollection(mg.graph) opts := options.Find() - opts.SetProjection(map[string]interface{}{"_id": 1, "label": 1}) + opts.SetProjection(map[string]interface{}{FIELD_ID: 1, FIELD_LABEL: 1}) cursor, err := vcol.Find(context.TODO(), selection, opts) if err == nil { @@ -127,7 +127,7 @@ func (mg *Graph) VertexLabelScan(ctx context.Context, label string) chan string default: } if nil == cursor.Decode(&result) { - out <- result["_id"].(string) + out <- result[FIELD_ID].(string) } } if err := cursor.Close(context.TODO()); err != nil { diff --git a/mongo/processor.go b/mongo/processor.go index 4f2b72dd..8b36b38c 100644 --- a/mongo/processor.go +++ b/mongo/processor.go @@ -28,20 +28,23 @@ type Processor struct { func getDataElement(result map[string]interface{}) *gdbi.DataElement { de := &gdbi.DataElement{} - if x, ok := result["_id"]; ok { + if x, ok := result[FIELD_ID]; ok { de.ID = x.(string) } - if x, ok := result["label"]; ok { + if x, ok := result[FIELD_LABEL]; ok { de.Label = x.(string) } - if x, ok := result["data"]; ok { - de.Data = removePrimatives(x).(map[string]interface{}) - de.Loaded = true + de.Data = map[string]any{} + for k, v := range removePrimatives(result).(map[string]any) { + if !IsNodeField(k) { + de.Data[k] = v + } } - if x, ok := result["to"]; ok { + de.Loaded = true + if x, ok := result[FIELD_TO]; ok { de.To = x.(string) } - if x, ok := result["from"]; ok { + if x, ok := result[FIELD_FROM]; ok { de.From = x.(string) } return de @@ -176,6 +179,8 @@ func (proc *Processor) Process(ctx context.Context, man gdbi.Manager, in gdbi.In } default: + //Reconstruct the traveler + //Extract the path if path, ok := result["path"]; ok { if pathA, ok := path.(bson.A); ok { o := make([]gdbi.DataElementID, len(pathA)) @@ -192,6 +197,7 @@ func (proc *Processor) Process(ctx context.Context, man gdbi.Manager, in gdbi.In t = &gdbi.BaseTraveler{Path: o} } } + //Extract marks if marks, ok := result["marks"]; ok { if marks, ok := marks.(map[string]interface{}); ok { for k, v := range marks { @@ -204,20 +210,21 @@ func (proc *Processor) Process(ctx context.Context, man gdbi.Manager, in gdbi.In } de := &gdbi.DataElement{} - if x, ok := result["_id"]; ok { + data := removePrimatives(result["data"]).(map[string]any) + if x, ok := data[FIELD_ID]; ok { de.ID = removePrimatives(x).(string) } - if x, ok := result["label"]; ok { + if x, ok := data[FIELD_LABEL]; ok { de.Label = x.(string) } - if x, ok := result["data"]; ok { - de.Data = removePrimatives(x).(map[string]interface{}) - de.Loaded = true - } - if x, ok := result["to"]; ok { + //if x, ok := result["data"]; ok { + de.Data = RemoveKeyFields(data) //removePrimatives(x).(map[string]interface{}) + de.Loaded = true + //} + if x, ok := data[FIELD_TO]; ok { de.To = x.(string) } - if x, ok := result["from"]; ok { + if x, ok := data[FIELD_FROM]; ok { de.From = x.(string) } out <- t.AddCurrent(de) From e4ba0b1e93e41937eb8677f08587f417730d8174 Mon Sep 17 00:00:00 2001 From: Kyle Ellrott Date: Fri, 9 Feb 2024 09:31:01 -0800 Subject: [PATCH 11/23] Fixing hasLabel bug --- conformance/tests/ot_aggregations.py | 4 ++-- conformance/tests/ot_repeat.py | 8 ++++---- gripql/inspect/haslabel.go | 3 +++ gripql/javascript/gripql.js | 7 +++++++ mongo/compile.go | 11 ++--------- 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/conformance/tests/ot_aggregations.py b/conformance/tests/ot_aggregations.py index d0553c79..97f0b629 100644 --- a/conformance/tests/ot_aggregations.py +++ b/conformance/tests/ot_aggregations.py @@ -122,7 +122,7 @@ def getMinMax(input_data, percent, accuracy=0.15): if count != len(percents): errors.append( "Unexpected number of terms: %d != %d" % - (len(row["buckets"]), len(percents)) + (len(res["buckets"]), len(percents)) ) return errors @@ -194,7 +194,7 @@ def test_field_aggregation(man): G = man.setGraph("swapi") count = 0 - for row in G.query().V().hasLabel("Planet").aggregate(gripql.field("gid-agg", "$._data")): + for row in G.query().V().hasLabel("Planet").aggregate(gripql.field("gid-agg", "$")): if row["key"] not in fields: errors.append("unknown field returned: %s" % (row['key'])) if row["value"] != 3: diff --git a/conformance/tests/ot_repeat.py b/conformance/tests/ot_repeat.py index 91630765..dcc8abe5 100644 --- a/conformance/tests/ot_repeat.py +++ b/conformance/tests/ot_repeat.py @@ -79,20 +79,20 @@ def test_set(man): G = man.setGraph("swapi") q = G.query().V("Character:1").set("count", 0) - q = q.as_("start").render("$start._data") + q = q.as_("start").render("$start") for row in q: if row['count'] != 0: errors.append("Incorrect increment value") q = G.query().V("Character:1").set("count", 0).as_("start").out().increment("$start.count") - q = q.render("$start._data") + q = q.render("$start") for row in q: if row['count'] != 1: errors.append("Incorrect increment value") q = G.query().V("Character:1").set("count", 0).as_("start").out().increment("$start.count") q = q.increment("$start.count").has(gripql.gt("$start.count", 1.0)) - q = q.render("$start._data") + q = q.render("$start") count = 0 for row in q: count += 1 @@ -102,7 +102,7 @@ def test_set(man): errors.append("Incorrect number of rows returned") q = G.query().V("Character:1").set("count", 0).increment("count",2).as_("start").out().increment("$start.count") - q = q.render("$start._data") + q = q.render("$start") for row in q: if row['count'] != 3: errors.append("Incorrect increment value") diff --git a/gripql/inspect/haslabel.go b/gripql/inspect/haslabel.go index fa9abdcc..01723e55 100644 --- a/gripql/inspect/haslabel.go +++ b/gripql/inspect/haslabel.go @@ -5,6 +5,9 @@ import ( "github.com/bmeg/grip/util/protoutil" ) +// Determine if a pipeline starts with 'V().hasLabel(x)' and trim it out +// This can be used to optimize pipelines that start with looking up vertex labels +// using an index func FindVertexHasLabelStart(pipe []*gripql.GraphStatement) ([]string, []*gripql.GraphStatement) { hasLabelLen := 0 labels := []string{} diff --git a/gripql/javascript/gripql.js b/gripql/javascript/gripql.js index f1d1e212..1a4279c5 100644 --- a/gripql/javascript/gripql.js +++ b/gripql/javascript/gripql.js @@ -256,6 +256,13 @@ function histogram(name, field, interval) { } } +function count(name) { + return { + "name": name, + "count": {} + } +} + function V(id) { return query().V(id) } diff --git a/mongo/compile.go b/mongo/compile.go index 206643d4..770770e5 100644 --- a/mongo/compile.go +++ b/mongo/compile.go @@ -515,14 +515,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile return &Pipeline{}, fmt.Errorf(`"hasLabel" statement is only valid for edge or vertex types not: %s`, lastType.String()) } labels := protoutil.AsStringList(stmt.HasLabel) - ilabels := make([]interface{}, len(labels)) - for i, v := range labels { - ilabels[i] = v - } - has := gripql.Within(FIELD_LABEL, ilabels...) - whereExpr := convertHasExpression(has, false) - matchStmt := bson.D{primitive.E{Key: "$match", Value: whereExpr}} - query = append(query, matchStmt) + query = append(query, bson.D{primitive.E{Key: "$match", Value: bson.M{FIELD_CURRENT_LABEL: bson.M{"$in": labels}}}}) case *gripql.GraphStatement_HasId: if lastType != gdbi.VertexData && lastType != gdbi.EdgeData { @@ -533,7 +526,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile for i, v := range ids { iids[i] = v } - has := gripql.Within(FIELD_ID, iids...) + has := gripql.Within(FIELD_CURRENT_ID, iids...) whereExpr := convertHasExpression(has, false) matchStmt := bson.D{primitive.E{Key: "$match", Value: whereExpr}} query = append(query, matchStmt) From d75e125807ac29a72ad6822fb389629dfdb8eb0b Mon Sep 17 00:00:00 2001 From: Kyle Ellrott Date: Fri, 9 Feb 2024 10:04:06 -0800 Subject: [PATCH 12/23] Fixing schema sampling --- mongo/schema.go | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/mongo/schema.go b/mongo/schema.go index 261a9f06..80d77998 100644 --- a/mongo/schema.go +++ b/mongo/schema.go @@ -73,7 +73,7 @@ func (ma *GraphDB) getVertexSchema(ctx context.Context, graph string, n uint32, pipe := []bson.M{ { "$match": bson.M{ - "label": bson.M{"$eq": label}, + FIELD_LABEL: bson.M{"$eq": label}, }, }, } @@ -84,7 +84,10 @@ func (ma *GraphDB) getVertexSchema(ctx context.Context, graph string, n uint32, pipe = append(pipe, bson.M{"$limit": n}) } - cursor, _ := ma.VertexCollection(graph).Aggregate(context.TODO(), pipe) + cursor, err := ma.VertexCollection(graph).Aggregate(context.TODO(), pipe) + if err != nil { + log.Errorf("Vertex schema scan error: %s", err) + } result := make(map[string]interface{}) schema := make(map[string]interface{}) for cursor.Next(context.TODO()) { @@ -94,8 +97,8 @@ func (ma *GraphDB) getVertexSchema(ctx context.Context, graph string, n uint32, default: if err := cursor.Decode(&result); err == nil { - if result["data"] != nil { - ds := gripql.GetDataFieldTypes(result["data"].(map[string]interface{})) + if result != nil { + ds := gripql.GetDataFieldTypes(result) util.MergeMaps(schema, ds) } } else { @@ -153,7 +156,7 @@ func (ma *GraphDB) getEdgeSchema(ctx context.Context, graph string, n uint32, ra pipe := []bson.M{ { "$match": bson.M{ - "label": bson.M{"$eq": label}, + FIELD_LABEL: bson.M{"$eq": label}, }, }, } @@ -177,9 +180,9 @@ func (ma *GraphDB) getEdgeSchema(ctx context.Context, graph string, n uint32, ra default: if err := cursor.Decode(&result); err == nil { - fromToPairs.Add(fromtokey{result["from"].(string), result["to"].(string)}) - if result["data"] != nil { - ds := gripql.GetDataFieldTypes(result["data"].(map[string]interface{})) + fromToPairs.Add(fromtokey{result[FIELD_FROM].(string), result[FIELD_TO].(string)}) + if result != nil { + ds := gripql.GetDataFieldTypes(result) util.MergeMaps(schema, ds) } } else { @@ -277,18 +280,18 @@ func (ma *GraphDB) resolveLabels(graph string, ft fromto) fromto { to := "" result := map[string]string{} opts := options.FindOne() - opts.SetProjection(bson.M{"_id": -1, "label": 1}) + opts.SetProjection(bson.M{"_id": -1, "_label": 1}) cursor := v.FindOne(context.TODO(), bson.M{"_id": fromID}, opts) if cursor.Err() == nil { if nil == cursor.Decode(&result) { - from = result["label"] + from = result["_label"] } } result = map[string]string{} cursor = v.FindOne(context.TODO(), bson.M{"_id": toID}, opts) if cursor.Err() == nil { if nil == cursor.Decode(&result) { - to = result["label"] + to = result["_label"] } } if from != "" && to != "" { From e5bb94cbc8662a44d6b9850c235083d365bcf9d5 Mon Sep 17 00:00:00 2001 From: Kyle Ellrott Date: Fri, 9 Feb 2024 10:08:08 -0800 Subject: [PATCH 13/23] Adding missing file --- mongo/fields.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 mongo/fields.go diff --git a/mongo/fields.go b/mongo/fields.go new file mode 100644 index 00000000..1eacc990 --- /dev/null +++ b/mongo/fields.go @@ -0,0 +1,32 @@ +package mongo + +const FIELD_ID = "_id" +const FIELD_LABEL = "_label" +const FIELD_TO = "_to" +const FIELD_FROM = "_from" + +const FIELD_CURRENT = "data" +const FIELD_CURRENT_ID = "data._id" +const FIELD_CURRENT_TO = "data._to" +const FIELD_CURRENT_FROM = "data._from" +const FIELD_CURRENT_LABEL = "data._label" + +const FIELD_DST = "dst" +const FIELD_DST_ID = "dst._id" +const FIELD_DST_TO = "dst._to" +const FIELD_DST_FROM = "dst._from" +const FIELD_DST_LABEL = "dst._label" + +func IsNodeField(f string) bool { + return f == FIELD_ID || f == FIELD_LABEL || f == FIELD_TO || f == FIELD_FROM +} + +func RemoveKeyFields(x map[string]any) map[string]any { + out := map[string]any{} + for k, v := range x { + if !IsNodeField(k) { + out[k] = v + } + } + return out +} From 0ab3ae177878767cb8d491fe25862ba30a29e617 Mon Sep 17 00:00:00 2001 From: Kyle Ellrott Date: Fri, 9 Feb 2024 11:43:58 -0800 Subject: [PATCH 14/23] Fixing various issues in the engines --- conformance/tests/ot_update.py | 2 +- mongo/convert.go | 27 +++++++++------------------ mongo/graph.go | 6 +++--- 3 files changed, 13 insertions(+), 22 deletions(-) diff --git a/conformance/tests/ot_update.py b/conformance/tests/ot_update.py index 8d0ac997..8b214771 100644 --- a/conformance/tests/ot_update.py +++ b/conformance/tests/ot_update.py @@ -44,7 +44,7 @@ def test_replace(man): errors.append("vertex has unexpected data") if G.getEdge("edge1")["data"] != {"weight": 5}: - errors.append("edge is missing expected data") + errors.append("edge is missing expected data: %s" % (G.getEdge("edge1"))) return errors diff --git a/mongo/convert.go b/mongo/convert.go index 33301b2d..d7c63858 100644 --- a/mongo/convert.go +++ b/mongo/convert.go @@ -3,7 +3,6 @@ package mongo import ( "github.com/bmeg/grip/gdbi" "go.mongodb.org/mongo-driver/bson/primitive" - "google.golang.org/protobuf/types/known/structpb" ) // PackVertex take a GRIP vertex and convert it to a mongo doc @@ -12,13 +11,12 @@ func PackVertex(v *gdbi.Vertex) map[string]interface{} { if v.Data != nil { p = v.Data } - out := map[string]interface{}{ - "_id": v.ID, - "_label": v.Label, - } + out := map[string]interface{}{} for k, v := range p { out[k] = v } + out["_id"] = v.ID + out["_label"] = v.Label return out } @@ -28,24 +26,17 @@ func PackEdge(e *gdbi.Edge) map[string]interface{} { if e.Data != nil { p = e.Data } - out := map[string]interface{}{ - "_id": e.ID, - "_from": e.From, - "_to": e.To, - "_label": e.Label, - } + out := map[string]interface{}{} for k, v := range p { out[k] = v } + out["_id"] = e.ID + out["_from"] = e.From + out["_to"] = e.To + out["_label"] = e.Label return out } -type pair struct { - key string - valueMap interface{} - valueStruct *structpb.Struct -} - // UnpackVertex takes a mongo doc and converts it into an gripql.Vertex func UnpackVertex(i map[string]interface{}) *gdbi.Vertex { o := &gdbi.Vertex{} @@ -73,7 +64,7 @@ func UnpackEdge(i map[string]interface{}) *gdbi.Edge { o.Data = map[string]any{} d := removePrimatives(i).(map[string]any) for k, v := range d { - if k != "_id" && k != "_label" && k != "_to" && k != "from" { + if k != "_id" && k != "_label" && k != "_to" && k != "_from" { o.Data[k] = v } } diff --git a/mongo/graph.go b/mongo/graph.go index eab9957e..1d32cb84 100644 --- a/mongo/graph.go +++ b/mongo/graph.go @@ -310,7 +310,7 @@ func (mg *Graph) GetOutChannel(ctx context.Context, reqChan chan gdbi.ElementLoo query = append(query, bson.M{"$match": bson.M{FIELD_LABEL: bson.M{"$in": edgeLabels}}}) } vertCol := fmt.Sprintf("%s_vertices", mg.graph) - query = append(query, bson.M{"$lookup": bson.M{FIELD_FROM: vertCol, "localField": FIELD_TO, "foreignField": FIELD_ID, "as": "dst"}}) + query = append(query, bson.M{"$lookup": bson.M{"from": vertCol, "localField": FIELD_TO, "foreignField": FIELD_ID, "as": "dst"}}) query = append(query, bson.M{"$unwind": "$dst"}) if load { //query = append(query, bson.M{"$project": bson.M{FIELD_FROM: true, "dst._id": true, "dst._label": true, "dst.data": true}}) @@ -390,11 +390,11 @@ func (mg *Graph) GetInChannel(ctx context.Context, reqChan chan gdbi.ElementLook query = append(query, bson.M{"$match": bson.M{FIELD_LABEL: bson.M{"$in": edgeLabels}}}) } vertCol := fmt.Sprintf("%s_vertices", mg.graph) - query = append(query, bson.M{"$lookup": bson.M{FIELD_FROM: vertCol, "localField": FIELD_FROM, "foreignField": FIELD_ID, "as": "src"}}) + query = append(query, bson.M{"$lookup": bson.M{"from": vertCol, "localField": FIELD_FROM, "foreignField": FIELD_ID, "as": "src"}}) query = append(query, bson.M{"$unwind": "$src"}) if load { //query = append(query, bson.M{"$project": bson.M{FIELD_TO: true, "src._id": true, "src._label": true, "src.data": true}}) //FIX: .data no longer used - query = append(query, bson.M{"$project": bson.M{FIELD_TO: true, "src._id": true, "src": true}}) + query = append(query, bson.M{"$project": bson.M{FIELD_TO: true, "src": true}}) } else { query = append(query, bson.M{"$project": bson.M{FIELD_TO: true, "src._id": true, "src._label": true}}) } From 5cabbd135e751fd365b648a8c767e4aa0e6ae300 Mon Sep 17 00:00:00 2001 From: Kyle Ellrott Date: Thu, 15 Feb 2024 22:38:59 -0800 Subject: [PATCH 15/23] Working on issues conformance test issues --- conformance/tests/ot_aggregations.py | 2 +- conformance/tests/ot_mark.py | 18 +-- engine/core/optimize.go | 8 +- engine/core/processors.go | 24 +-- engine/core/processors_extra.go | 20 +-- engine/core/statement_compiler.go | 6 +- engine/logic/match.go | 3 + gdbi/statement_processor.go | 6 +- .../jsonpath.go => gdbi/tpath/namepath.go | 43 +++-- gdbi/tpath/namepath_test.go | 22 +++ gdbi/tpath/render.go | 37 +++++ gdbi/traveler.go | 12 +- gdbi/{jsonpath.go => traveler_doc.go} | 153 +++++++----------- ...{jsonpath_test.go => traveler_doc_test.go} | 53 +++--- gripql/inspect/inspect.go | 12 +- gripql/javascript/gripql.js | 17 ++ kvgraph/index.go | 3 +- mongo/compile.go | 42 ++--- mongo/compile_test.go | 8 +- mongo/has_evaluator.go | 6 +- mongo/index.go | 10 +- 21 files changed, 280 insertions(+), 225 deletions(-) rename travelerpath/jsonpath.go => gdbi/tpath/namepath.go (68%) create mode 100644 gdbi/tpath/namepath_test.go create mode 100644 gdbi/tpath/render.go rename gdbi/{jsonpath.go => traveler_doc.go} (69%) rename gdbi/{jsonpath_test.go => traveler_doc_test.go} (85%) diff --git a/conformance/tests/ot_aggregations.py b/conformance/tests/ot_aggregations.py index 97f0b629..e5809f53 100644 --- a/conformance/tests/ot_aggregations.py +++ b/conformance/tests/ot_aggregations.py @@ -190,7 +190,7 @@ def test_traversal_gid_aggregation(man): def test_field_aggregation(man): errors = [] - fields = [ "id", 'orbital_period', 'gravity', 'terrain', 'name','climate', 'system', 'diameter', 'rotation_period', 'url', 'population', 'surface_water'] + fields = [ "_gid", "_label", 'orbital_period', 'gravity', 'terrain', 'name','climate', 'system', 'diameter', 'rotation_period', 'url', 'population', 'surface_water'] G = man.setGraph("swapi") count = 0 diff --git a/conformance/tests/ot_mark.py b/conformance/tests/ot_mark.py index 667b53de..e9bddd8b 100644 --- a/conformance/tests/ot_mark.py +++ b/conformance/tests/ot_mark.py @@ -13,9 +13,9 @@ def test_mark_select_label_filter(man): count += 1 if len(row) != 2: errors.append("Incorrect number of marks returned") - if row["a"]["gid"] != "Film:1": + if row["a"]["_gid"] != "Film:1": errors.append("Incorrect vertex returned for 'a': %s" % row["a"]) - if row["b"]["label"] not in ["Vehicle", "Starship", "Species", "Planet", "Character"]: + if row["b"]["_label"] not in ["Vehicle", "Starship", "Species", "Planet", "Character"]: errors.append("Incorrect vertex returned for 'b': %s" % row["b"]) if count != 38: @@ -36,11 +36,11 @@ def test_mark_select(man): count += 1 if len(row) != 3: errors.append("Incorrect number of marks returned") - if row["a"]["gid"] != "Character:1": + if row["a"]["_gid"] != "Character:1": errors.append("Incorrect vertex returned for 'a': %s" % row["a"]) - if row["a"]["data"]["height"] != 172: + if row["a"]["height"] != 172: errors.append("Missing data for 'a'") - if row["b"]["label"] not in ["Starship", "Planet", "Species", "Film"]: + if row["b"]["_label"] not in ["Starship", "Planet", "Species", "Film"]: errors.append("Incorrect vertex returned for 'b': %s" % row["b"]) if count != 64: @@ -61,13 +61,13 @@ def test_mark_edge_select(man): count += 1 if len(row) != 3: errors.append("Incorrect number of marks returned") - if row["a"]["gid"] != "Film:1": + if row["a"]["_gid"] != "Film:1": errors.append("Incorrect as selection") - if row["b"]["label"] != "planets": + if row["b"]["_label"] != "planets": errors.append("Incorrect as edge selection: %s" % row["b"]) - if "scene_count" not in row["b"]["data"]: + if "scene_count" not in row["b"]: errors.append("Data not returned") - if row["c"]["label"] != "Planet": + if row["c"]["_label"] != "Planet": errors.append("Incorrect element returned") if count != 3: diff --git a/engine/core/optimize.go b/engine/core/optimize.go index afac7981..5ff07215 100644 --- a/engine/core/optimize.go +++ b/engine/core/optimize.go @@ -1,8 +1,8 @@ package core import ( + "github.com/bmeg/grip/gdbi/tpath" "github.com/bmeg/grip/gripql" - "github.com/bmeg/grip/travelerpath" "github.com/bmeg/grip/util/protoutil" ) @@ -47,11 +47,11 @@ func IndexStartOptimize(pipe []*gripql.GraphStatement) []*gripql.GraphStatement return IndexStartOptimize(newPipe) } if cond := s.Has.GetCondition(); cond != nil { - path := travelerpath.GetJSONPath(cond.Key) + path := tpath.NormalizePath(cond.Key) switch path { - case "$.gid": + case "$_current._gid": hasIDIdx = append(hasIDIdx, i) - case "$.label": + case "$_current._label": hasLabelIdx = append(hasLabelIdx, i) default: // do nothing diff --git a/engine/core/processors.go b/engine/core/processors.go index 695e99f9..8aead1f2 100644 --- a/engine/core/processors.go +++ b/engine/core/processors.go @@ -1053,19 +1053,21 @@ func (agg *aggregate) Process(ctx context.Context, man gdbi.Manager, in gdbi.InP c++ } } - sort.Float64s(fieldValues) - min := fieldValues[0] - max := fieldValues[len(fieldValues)-1] - - for bucket := math.Floor(min/i) * i; bucket <= max; bucket += i { - var count float64 - for _, v := range fieldValues { - if v >= bucket && v < (bucket+i) { - count++ + if len(fieldValues) > 0 { + sort.Float64s(fieldValues) + min := fieldValues[0] + max := fieldValues[len(fieldValues)-1] + + for bucket := math.Floor(min/i) * i; bucket <= max; bucket += i { + var count float64 + for _, v := range fieldValues { + if v >= bucket && v < (bucket+i) { + count++ + } } + //sBucket, _ := structpb.NewValue(bucket) + out <- &gdbi.BaseTraveler{Aggregation: &gdbi.Aggregate{Name: a.Name, Key: bucket, Value: float64(count)}} } - //sBucket, _ := structpb.NewValue(bucket) - out <- &gdbi.BaseTraveler{Aggregation: &gdbi.Aggregate{Name: a.Name, Key: bucket, Value: float64(count)}} } return outErr }) diff --git a/engine/core/processors_extra.go b/engine/core/processors_extra.go index ac85838a..e78dd549 100644 --- a/engine/core/processors_extra.go +++ b/engine/core/processors_extra.go @@ -6,10 +6,10 @@ import ( "math" "strings" + "github.com/bmeg/grip/gdbi/tpath" "github.com/bmeg/grip/gripql" "github.com/bmeg/grip/kvi" "github.com/bmeg/grip/kvindex" - "github.com/bmeg/grip/travelerpath" "github.com/influxdata/tdigest" "golang.org/x/sync/errgroup" @@ -61,8 +61,8 @@ func (agg *aggregateDisk) Process(ctx context.Context, man gdbi.Manager, in gdbi kv := man.GetTempKV() idx := kvindex.NewIndex(kv) - namespace := travelerpath.GetNamespace(tagg.Field) - field := travelerpath.GetJSONPath(tagg.Field) + namespace := tpath.GetNamespace(tagg.Field) + field := tpath.NormalizePath(tagg.Field) field = strings.TrimPrefix(field, "$.") idx.AddField(field) @@ -70,7 +70,7 @@ func (agg *aggregateDisk) Process(ctx context.Context, man gdbi.Manager, in gdbi for batch := range aChans[a.Name] { err := kv.Update(func(tx kvi.KVTransaction) error { for _, t := range batch { - doc := gdbi.GetDoc(t, namespace) + doc := gdbi.TravelerGetDoc(t, namespace) err := idx.AddDocTx(tx, fmt.Sprintf("%d", tid), doc) tid++ if err != nil { @@ -107,8 +107,8 @@ func (agg *aggregateDisk) Process(ctx context.Context, man gdbi.Manager, in gdbi kv := man.GetTempKV() idx := kvindex.NewIndex(kv) - namespace := travelerpath.GetNamespace(hagg.Field) - field := travelerpath.GetJSONPath(hagg.Field) + namespace := tpath.GetNamespace(hagg.Field) + field := tpath.NormalizePath(hagg.Field) field = strings.TrimPrefix(field, "$.") idx.AddField(field) @@ -116,7 +116,7 @@ func (agg *aggregateDisk) Process(ctx context.Context, man gdbi.Manager, in gdbi for batch := range aChans[a.Name] { err := kv.Update(func(tx kvi.KVTransaction) error { for _, t := range batch { - doc := gdbi.GetDoc(t, namespace) + doc := gdbi.TravelerGetDoc(t, namespace) err := idx.AddDocTx(tx, fmt.Sprintf("%d", tid), doc) tid++ if err != nil { @@ -152,8 +152,8 @@ func (agg *aggregateDisk) Process(ctx context.Context, man gdbi.Manager, in gdbi kv := man.GetTempKV() idx := kvindex.NewIndex(kv) - namespace := travelerpath.GetNamespace(pagg.Field) - field := travelerpath.GetJSONPath(pagg.Field) + namespace := tpath.GetNamespace(pagg.Field) + field := tpath.NormalizePath(pagg.Field) field = strings.TrimPrefix(field, "$.") idx.AddField(field) @@ -161,7 +161,7 @@ func (agg *aggregateDisk) Process(ctx context.Context, man gdbi.Manager, in gdbi for batch := range aChans[a.Name] { err := kv.Update(func(tx kvi.KVTransaction) error { for _, t := range batch { - doc := gdbi.GetDoc(t, namespace) + doc := gdbi.TravelerGetDoc(t, namespace) err := idx.AddDocTx(tx, fmt.Sprintf("%d", tid), doc) tid++ if err != nil { diff --git a/engine/core/statement_compiler.go b/engine/core/statement_compiler.go index 30333d5f..7aab4ce3 100644 --- a/engine/core/statement_compiler.go +++ b/engine/core/statement_compiler.go @@ -5,8 +5,8 @@ import ( "github.com/bmeg/grip/engine/logic" "github.com/bmeg/grip/gdbi" + "github.com/bmeg/grip/gdbi/tpath" "github.com/bmeg/grip/gripql" - "github.com/bmeg/grip/travelerpath" "github.com/bmeg/grip/util/protoutil" ) @@ -166,8 +166,8 @@ func (sc *DefaultStmtCompiler) As(stmt *gripql.GraphStatement_As, ps *gdbi.State if err := gripql.ValidateFieldName(stmt.As); err != nil { return nil, fmt.Errorf(`"mark" statement invalid; %v`, err) } - if stmt.As == travelerpath.Current { - return nil, fmt.Errorf(`"mark" statement invalid; uses reserved name %s`, travelerpath.Current) + if stmt.As == tpath.CURRENT { + return nil, fmt.Errorf(`"mark" statement invalid; uses reserved name %s`, tpath.CURRENT) } ps.MarkTypes[stmt.As] = ps.LastType return &Marker{stmt.As}, nil diff --git a/engine/logic/match.go b/engine/logic/match.go index 88a6be6e..9acd6529 100644 --- a/engine/logic/match.go +++ b/engine/logic/match.go @@ -13,9 +13,12 @@ import ( func MatchesCondition(trav gdbi.Traveler, cond *gripql.HasCondition) bool { var val interface{} var condVal interface{} + val = gdbi.TravelerPathLookup(trav, cond.Key) condVal = cond.Value.AsInterface() + log.Debugf("match: %s %s %s", condVal, val, cond.Key) + switch cond.Condition { case gripql.Condition_EQ: return reflect.DeepEqual(val, condVal) diff --git a/gdbi/statement_processor.go b/gdbi/statement_processor.go index 38730e3e..ba4c024a 100644 --- a/gdbi/statement_processor.go +++ b/gdbi/statement_processor.go @@ -3,8 +3,8 @@ package gdbi import ( "fmt" + "github.com/bmeg/grip/gdbi/tpath" "github.com/bmeg/grip/gripql" - "github.com/bmeg/grip/travelerpath" ) func StatementProcessor( @@ -171,8 +171,8 @@ func StatementProcessor( if err := gripql.ValidateFieldName(stmt.As); err != nil { return nil, fmt.Errorf(`"mark" statement invalid; %v`, err) } - if stmt.As == travelerpath.Current { - return nil, fmt.Errorf(`"mark" statement invalid; uses reserved name %s`, travelerpath.Current) + if stmt.As == tpath.CURRENT { + return nil, fmt.Errorf(`"mark" statement invalid; uses reserved name %s`, tpath.CURRENT) } ps.MarkTypes[stmt.As] = ps.LastType return sc.As(stmt, ps) diff --git a/travelerpath/jsonpath.go b/gdbi/tpath/namepath.go similarity index 68% rename from travelerpath/jsonpath.go rename to gdbi/tpath/namepath.go index 9bce43c2..bb84c834 100644 --- a/travelerpath/jsonpath.go +++ b/gdbi/tpath/namepath.go @@ -1,13 +1,11 @@ -package travelerpath +package tpath import ( "strings" - - "github.com/bmeg/grip/gripql" ) // Current represents the 'current' traveler namespace -var Current = "__current__" +const CURRENT = "_current" // GetNamespace returns the namespace of the provided path // @@ -20,37 +18,36 @@ func GetNamespace(path string) string { namespace = strings.TrimPrefix(parts[0], "$") } if namespace == "" { - namespace = Current + namespace = CURRENT } return namespace } -// GetJSONPath strips the namespace from the path and returns the valid -// Json path within the document referenced by the namespace +// NormalizePath // // Example: -// GetJSONPath("gene.symbol.ensembl") returns "$.data.symbol.ensembl" -func GetJSONPath(path string) string { +// NormalizePath("gene.symbol.ensembl") returns "$_current.symbol.ensembl" + +func NormalizePath(path string) string { + namespace := CURRENT parts := strings.Split(path, ".") + if strings.HasPrefix(parts[0], "$") { - parts = parts[1:] - } - if len(parts) == 0 { - return "" - } - found := false - for _, v := range gripql.ReservedFields { - if parts[0] == v { - found = true - parts[0] = strings.TrimPrefix(parts[0], "_") + if len(parts[0]) > 1 { + namespace = parts[0][1:] } + parts = parts[1:] } - if !found { - parts = append([]string{"data"}, parts...) - } + parts = append([]string{"$" + namespace}, parts...) + return strings.Join(parts, ".") +} - parts = append([]string{"$"}, parts...) +func ToLocalPath(path string) string { + parts := strings.Split(path, ".") + if strings.HasPrefix(parts[0], "$") { + parts[0] = "$" + } return strings.Join(parts, ".") } diff --git a/gdbi/tpath/namepath_test.go b/gdbi/tpath/namepath_test.go new file mode 100644 index 00000000..26cd7bd6 --- /dev/null +++ b/gdbi/tpath/namepath_test.go @@ -0,0 +1,22 @@ +package tpath + +import "testing" + +func TestPathNormalize(t *testing.T) { + + pairs := [][]string{ + {"_label", "$_current._label"}, + {"name", "$_current.name"}, + {"$.name", "$_current.name"}, + {"$name", "$name"}, + {"$a.name", "$a.name"}, + } + + for _, p := range pairs { + o := NormalizePath(p[0]) + if o != p[1] { + t.Errorf("Normalize %s error: %s != %s", p[0], o, p[1]) + } + } + +} diff --git a/gdbi/tpath/render.go b/gdbi/tpath/render.go new file mode 100644 index 00000000..a7d468e2 --- /dev/null +++ b/gdbi/tpath/render.go @@ -0,0 +1,37 @@ +package tpath + +import ( + "github.com/bmeg/jsonpath" +) + +func Render(template any, data map[string]any) (any, error) { + switch elem := template.(type) { + case string: + path := NormalizePath(elem) + return jsonpath.JsonPathLookup(data, path) + case map[string]interface{}: + o := make(map[string]interface{}) + for k, v := range elem { + val, err := Render(v, data) + if err == nil { + o[k] = val + } else { + o[k] = v + } + } + return o, nil + case []any: + o := make([]any, len(elem)) + for i := range elem { + val, err := Render(elem[i], data) + if err == nil { + o[i] = val + } else { + o[i] = elem[i] + } + } + return o, nil + default: + return template, nil + } +} diff --git a/gdbi/traveler.go b/gdbi/traveler.go index 7d923734..af7dfc8c 100644 --- a/gdbi/traveler.go +++ b/gdbi/traveler.go @@ -218,19 +218,21 @@ func (elem *DataElement) ToDict() map[string]interface{} { if elem == nil { return out } + for k, v := range elem.Data { + out[k] = v + } if elem.ID != "" { - out["gid"] = elem.ID + out["_gid"] = elem.ID } if elem.Label != "" { - out["label"] = elem.Label + out["_label"] = elem.Label } if elem.To != "" { - out["to"] = elem.To + out["_to"] = elem.To } if elem.From != "" { - out["from"] = elem.From + out["_from"] = elem.From } - out["data"] = elem.Data return out } diff --git a/gdbi/jsonpath.go b/gdbi/traveler_doc.go similarity index 69% rename from gdbi/jsonpath.go rename to gdbi/traveler_doc.go index 01f9a2fb..f59c7f5a 100644 --- a/gdbi/jsonpath.go +++ b/gdbi/traveler_doc.go @@ -1,66 +1,47 @@ package gdbi import ( - // "fmt" - "strings" + "github.com/bmeg/grip/gdbi/tpath" "github.com/bmeg/grip/log" - "github.com/bmeg/grip/travelerpath" "github.com/bmeg/jsonpath" ) -// GetDoc returns the document referenced by the provided namespace. -// -// Example for a traveler containing: -// -// { -// "current": {...}, -// "marks": { -// "gene": { -// "gid": 1, -// "label": "gene", -// "data": { -// "symbol": { -// "ensembl": "ENSG00000012048", -// "hgnc": 1100, -// "entrez": 672 -// } -// } -// } -// } -// } -// } -// -// GetDoc(traveler, "gene") returns: -// -// { -// "gid": 1, -// "label": "gene", -// "data": { -// "symbol": { -// "ensembl": "ENSG00000012048", -// "hgnc": 1100, -// "entrez": 672 -// } -// } -// } -func GetDoc(traveler Traveler, namespace string) map[string]interface{} { - var tmap map[string]interface{} - if namespace == travelerpath.Current { - dr := traveler.GetCurrent() - if dr == nil { - return nil +// GetDoc returns the document representing the traveler data +func TravelerGetDoc(traveler Traveler, ns ...string) map[string]any { + if len(ns) == 0 { + out := map[string]any{} + out[tpath.CURRENT] = traveler.GetCurrent().Get().ToDict() + for _, k := range traveler.ListMarks() { + out[k] = traveler.GetMark(k).Get().ToDict() } - tmap = dr.Get().ToDict() - } else { - dr := traveler.GetMark(namespace) - if dr == nil { - return nil + return out + } + out := map[string]any{} + for _, n := range ns { + if n == tpath.CURRENT { + out[n] = traveler.GetCurrent().Get().ToDict() + } else { + m := traveler.GetMark(n) + if m != nil { + out[n] = m.Get().ToDict() + } } - tmap = dr.Get().ToDict() } - return tmap + return out +} + +// TravelerGetMarkDoc returns the document representing the traveler data +func TravelerGetMarkDoc(traveler Traveler, ns string) map[string]any { + if ns == tpath.CURRENT { + return traveler.GetCurrent().Get().ToDict() + } + m := traveler.GetMark(ns) + if m != nil { + return m.Get().ToDict() + } + return nil } // TravelerPathLookup gets the value of a field in the given Traveler @@ -68,7 +49,7 @@ func GetDoc(traveler Traveler, namespace string) map[string]interface{} { // Example for a traveler containing: // // { -// "current": {...}, +// "_current": {...}, // "marks": { // "gene": { // "gid": 1, @@ -87,14 +68,19 @@ func GetDoc(traveler Traveler, namespace string) map[string]interface{} { // // TravelerPathLookup(travler, "$gene.symbol.ensembl") returns "ENSG00000012048" func TravelerPathLookup(traveler Traveler, path string) interface{} { - namespace := travelerpath.GetNamespace(path) - field := travelerpath.GetJSONPath(path) - doc := GetDoc(traveler, namespace) + field := tpath.NormalizePath(path) + jpath := tpath.ToLocalPath(field) + namespace := tpath.GetNamespace(field) + var doc map[string]any + if namespace == tpath.CURRENT { + doc = traveler.GetCurrent().Get().ToDict() + } else { + doc = traveler.GetMark(namespace).Get().ToDict() + } if field == "" { - //fmt.Printf("Null field, return %#v\n", doc) return doc } - res, err := jsonpath.JsonPathLookup(doc, field) + res, err := jsonpath.JsonPathLookup(doc, jpath) if err != nil { return nil } @@ -103,49 +89,32 @@ func TravelerPathLookup(traveler Traveler, path string) interface{} { // TravelerSetValue(travler, "$gene.symbol.ensembl", "hi") inserts the value in the location" func TravelerSetValue(traveler Traveler, path string, val interface{}) error { - namespace := travelerpath.GetNamespace(path) - field := travelerpath.GetJSONPath(path) + field := tpath.NormalizePath(path) + namespace := tpath.GetNamespace(field) if field == "" { return nil } - doc := GetDoc(traveler, namespace) + doc := TravelerGetDoc(traveler, namespace) return jsonpath.JsonPathSet(doc, field, val) } // TravelerPathExists returns true if the field exists in the given Traveler func TravelerPathExists(traveler Traveler, path string) bool { - namespace := travelerpath.GetNamespace(path) - field := travelerpath.GetJSONPath(path) + field := tpath.NormalizePath(path) + namespace := tpath.GetNamespace(field) if field == "" { return false } - doc := GetDoc(traveler, namespace) + doc := TravelerGetDoc(traveler, namespace) _, err := jsonpath.JsonPathLookup(doc, field) return err == nil } // RenderTraveler takes a template and fills in the values using the data structure func RenderTraveler(traveler Traveler, template interface{}) interface{} { - switch elem := template.(type) { - case string: - return TravelerPathLookup(traveler, elem) - case map[string]interface{}: - o := make(map[string]interface{}) - for k, v := range elem { - val := RenderTraveler(traveler, v) - o[k] = val - } - return o - case []interface{}: - o := make([]interface{}, len(elem)) - for i := range elem { - val := RenderTraveler(traveler, elem[i]) - o[i] = val - } - return o - default: - return nil - } + doc := TravelerGetDoc(traveler) + out, _ := tpath.Render(template, doc) + return out } // SelectTravelerFields returns a new copy of the traveler with only the selected fields @@ -159,16 +128,16 @@ KeyLoop: exclude = true key = strings.TrimPrefix(key, "-") } - namespace := travelerpath.GetNamespace(key) + namespace := tpath.GetNamespace(key) switch namespace { - case travelerpath.Current: + case tpath.CURRENT: // noop default: log.Errorf("SelectTravelerFields: only can select field from current traveler") continue KeyLoop } - path := travelerpath.GetJSONPath(key) - path = strings.TrimPrefix(path, "$.") + path := tpath.NormalizePath(key) + path = strings.TrimPrefix(path, "$.") //FIXME if exclude { excludePaths = append(excludePaths, path) @@ -215,7 +184,7 @@ func includeFields(new, old *DataElement, paths []string) *DataElement { Include: for _, path := range paths { switch path { - case "gid", "label", "from", "to": + case "_gid", "_label", "_from", "_to": // noop case "data": for k, v := range old.Data { @@ -271,13 +240,13 @@ func excludeFields(elem *DataElement, paths []string) *DataElement { Exclude: for _, path := range paths { switch path { - case "gid": + case "_gid": result.ID = "" - case "label": + case "_label": result.Label = "" - case "from": + case "_from": result.From = "" - case "to": + case "_to": result.To = "" case "data": result.Data = map[string]interface{}{} diff --git a/gdbi/jsonpath_test.go b/gdbi/traveler_doc_test.go similarity index 85% rename from gdbi/jsonpath_test.go rename to gdbi/traveler_doc_test.go index a3e05d9a..6673f6a5 100644 --- a/gdbi/jsonpath_test.go +++ b/gdbi/traveler_doc_test.go @@ -4,7 +4,8 @@ import ( "os" "testing" - "github.com/bmeg/grip/travelerpath" + "github.com/bmeg/grip/gdbi/tpath" + "github.com/stretchr/testify/assert" ) @@ -44,68 +45,68 @@ func TestMain(m *testing.M) { func TestGetNamespace(t *testing.T) { expected := "foo" - result := travelerpath.GetNamespace("$foo.bar[1:3].baz") + result := tpath.GetNamespace("$foo.bar[1:3].baz") assert.Equal(t, expected, result) - result = travelerpath.GetNamespace("foo.bar[1:3].baz") + result = tpath.GetNamespace("foo.bar[1:3].baz") assert.NotEqual(t, expected, result) } func TestGetJSONPath(t *testing.T) { - expected := "$.data.a" - result := travelerpath.GetJSONPath("a") + expected := "$_current.a" + result := tpath.NormalizePath("a") assert.Equal(t, expected, result) - expected = "$.data.a" - result = travelerpath.GetJSONPath("_data.a") + expected = "$_current.a" + result = tpath.NormalizePath("$.a") assert.Equal(t, expected, result) - expected = "$.data.e[1].nested" - result = travelerpath.GetJSONPath("e[1].nested") + expected = "$_current.e[1].nested" + result = tpath.NormalizePath("e[1].nested") assert.Equal(t, expected, result) - expected = "$.data.a" - result = travelerpath.GetJSONPath("$testMark.a") + expected = "$testMark.a" + result = tpath.NormalizePath("$testMark.a") assert.Equal(t, expected, result) - expected = "$.data.a" - result = travelerpath.GetJSONPath("testMark.a") - assert.NotEqual(t, expected, result) + expected = "$_current.testMark.a" + result = tpath.NormalizePath("testMark.a") + assert.Equal(t, expected, result) } -func TestGetDoc(t *testing.T) { +func TestGetMarkDoc(t *testing.T) { expected := traveler.GetMark("testMark").Get().ToDict() - result := GetDoc(traveler, "testMark") + result := TravelerGetMarkDoc(traveler, "testMark") assert.Equal(t, expected, result) expected = traveler.GetMark("i-dont-exist").Get().ToDict() - result = GetDoc(traveler, "i-dont-exist") + result = TravelerGetMarkDoc(traveler, "i-dont-exist") assert.Equal(t, expected, result) expected = traveler.GetCurrent().Get().ToDict() - result = GetDoc(traveler, travelerpath.Current) + result = TravelerGetMarkDoc(traveler, tpath.CURRENT) assert.Equal(t, expected, result) } func TestTravelerPathExists(t *testing.T) { assert.True(t, TravelerPathExists(traveler, "_gid")) + assert.True(t, TravelerPathExists(traveler, "$_gid")) assert.True(t, TravelerPathExists(traveler, "_label")) assert.True(t, TravelerPathExists(traveler, "a")) - assert.True(t, TravelerPathExists(traveler, "_data.a")) + assert.True(t, TravelerPathExists(traveler, "$a")) + assert.True(t, TravelerPathExists(traveler, "$_current.a")) assert.False(t, TravelerPathExists(traveler, "non-existent")) - assert.False(t, TravelerPathExists(traveler, "_data.non-existent")) + assert.False(t, TravelerPathExists(traveler, "$_current.non-existent")) assert.True(t, TravelerPathExists(traveler, "$testMark._gid")) assert.True(t, TravelerPathExists(traveler, "$testMark._label")) assert.True(t, TravelerPathExists(traveler, "$testMark.a")) - assert.True(t, TravelerPathExists(traveler, "$testMark._data.a")) assert.False(t, TravelerPathExists(traveler, "$testMark.non-existent")) - assert.False(t, TravelerPathExists(traveler, "$testMark._data.non-existent")) } func TestRender(t *testing.T) { expected := traveler.GetCurrent().Get().Data["a"] - result := RenderTraveler(traveler, "a") + result := RenderTraveler(traveler, "$.a") assert.Equal(t, expected, result) expected = []interface{}{ @@ -141,15 +142,15 @@ func TestRender(t *testing.T) { "current.a": "a", "current.b": "b", "current.c": "c", - "current.d": "_data.d", + "current.d": "d", "mark.gid": "$testMark._gid", "mark.label": "$testMark._label", "mark.a": "$testMark.a", "mark.b": "$testMark.b", - "mark.c": "$testMark._data.c", + "mark.c": "$testMark.c", "mark.d": "$testMark.d", "mark.d[0]": "$testMark.d[0]", - "current.e[0].nested": "_data.e[0].nested", + "current.e[0].nested": "e[0].nested", "current.e.nested": "e.nested", "current.f": "f", }) diff --git a/gripql/inspect/inspect.go b/gripql/inspect/inspect.go index 64ebda44..a2212a30 100644 --- a/gripql/inspect/inspect.go +++ b/gripql/inspect/inspect.go @@ -3,9 +3,10 @@ package inspect import ( "fmt" + "github.com/bmeg/grip/gdbi/tpath" "github.com/bmeg/grip/gripql" "github.com/bmeg/grip/log" - "github.com/bmeg/grip/travelerpath" + "github.com/bmeg/grip/util/protoutil" ) @@ -99,8 +100,11 @@ func PipelineStepOutputs(stmts []*gripql.GraphStatement) map[string][]string { case *gripql.GraphStatement_Render: val := gs.GetRender().AsInterface() - names := travelerpath.GetAllNamespaces(val) + names := tpath.GetAllNamespaces(val) for _, n := range names { + if n == tpath.CURRENT { + out[steps[i]] = []string{"*"} + } if a, ok := asMap[n]; ok { out[a] = []string{"*"} } @@ -111,8 +115,8 @@ func PipelineStepOutputs(stmts []*gripql.GraphStatement) map[string][]string { //if there is a distinct step, we need to load data, but only for requested fields fields := protoutil.AsStringList(gs.GetDistinct()) for _, f := range fields { - n := travelerpath.GetNamespace(f) - if n == travelerpath.Current { + n := tpath.GetNamespace(f) + if n == tpath.CURRENT { out[steps[i]] = []string{"*"} } if a, ok := asMap[n]; ok { diff --git a/gripql/javascript/gripql.js b/gripql/javascript/gripql.js index 1a4279c5..0fe9789b 100644 --- a/gripql/javascript/gripql.js +++ b/gripql/javascript/gripql.js @@ -263,6 +263,23 @@ function count(name) { } } +function field(name, field){ + return { + "name": name, + "field": { + "field": field + } + } +} + +gripql = { + "lt" : lt, + "gt" : gt, + "lte" : lte, + "gte" : gte, + "eq" : eq, +} + function V(id) { return query().V(id) } diff --git a/kvgraph/index.go b/kvgraph/index.go index 5023da89..6707ffca 100644 --- a/kvgraph/index.go +++ b/kvgraph/index.go @@ -7,7 +7,6 @@ import ( "github.com/bmeg/grip/gripql" "github.com/bmeg/grip/log" - "github.com/bmeg/grip/travelerpath" ) func (kgraph *KVGraph) setupGraphIndex(graph string) error { @@ -33,7 +32,7 @@ func (kgraph *KVGraph) deleteGraphIndex(graph string) { } func normalizePath(path string) string { - path = travelerpath.GetJSONPath(path) + //path = travelerpath.GetJSONPath(path) path = strings.TrimPrefix(path, "$.") path = strings.TrimPrefix(path, "data.") return path diff --git a/mongo/compile.go b/mongo/compile.go index 770770e5..2fe95585 100644 --- a/mongo/compile.go +++ b/mongo/compile.go @@ -6,9 +6,9 @@ import ( "github.com/bmeg/grip/engine/core" "github.com/bmeg/grip/gdbi" + "github.com/bmeg/grip/gdbi/tpath" "github.com/bmeg/grip/gripql" "github.com/bmeg/grip/log" - "github.com/bmeg/grip/travelerpath" "github.com/bmeg/grip/util/protoutil" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" @@ -538,7 +538,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile hasKeys := bson.M{} keys := protoutil.AsStringList(stmt.HasKey) for _, key := range keys { - key = travelerpath.GetJSONPath(key) + key = tpath.NormalizePath(key) key = strings.TrimPrefix(key, "$.") hasKeys[key] = bson.M{"$exists": true} } @@ -576,13 +576,13 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile keys := bson.M{} match := bson.M{} for _, f := range fields { - namespace := travelerpath.GetNamespace(f) - f = travelerpath.GetJSONPath(f) - f = strings.TrimPrefix(f, "$.") + namespace := tpath.GetNamespace(f) + f = tpath.NormalizePath(f) + f = strings.TrimPrefix(f, "$.") //FIXME if f == "gid" { f = "_id" } - if namespace != travelerpath.Current { + if namespace != tpath.CURRENT { f = fmt.Sprintf("marks.%s.%s", namespace, f) } match[f] = bson.M{"$exists": true} @@ -630,8 +630,8 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile if err := gripql.ValidateFieldName(stmt.As); err != nil { return &Pipeline{}, fmt.Errorf(`"as" statement invalid; %v`, err) } - if stmt.As == travelerpath.Current { - return &Pipeline{}, fmt.Errorf(`"as" statement invalid; uses reserved name %s`, travelerpath.Current) + if stmt.As == tpath.CURRENT { + return &Pipeline{}, fmt.Errorf(`"as" statement invalid; uses reserved name %s`, tpath.CURRENT) } markTypes[stmt.As] = lastType query = append(query, bson.D{primitive.E{Key: "$addFields", Value: bson.M{"marks": bson.M{stmt.As: "$$ROOT"}}}}) @@ -698,13 +698,13 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile exclude = true f = strings.TrimPrefix(f, "-") } - namespace := travelerpath.GetNamespace(f) - if namespace != travelerpath.Current { + namespace := tpath.GetNamespace(f) + if namespace != tpath.CURRENT { log.Errorf("FieldsProcessor: only can select field from current traveler") continue SelectLoop } - f = travelerpath.GetJSONPath(f) - f = strings.TrimPrefix(f, "$.") + f = tpath.NormalizePath(f) + f = strings.TrimPrefix(f, "$.") //FIXME if exclude { excludeFields = append(excludeFields, f) } else { @@ -753,8 +753,8 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile switch a.Aggregation.(type) { case *gripql.Aggregate_Term: agg := a.GetTerm() - field := travelerpath.GetJSONPath(agg.Field) - field = strings.TrimPrefix(field, "$.") + field := tpath.NormalizePath(agg.Field) + field = strings.TrimPrefix(field, "$.") //FIXME if field == "gid" { field = "_id" } @@ -776,8 +776,8 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile case *gripql.Aggregate_Histogram: agg := a.GetHistogram() - field := travelerpath.GetJSONPath(agg.Field) - field = strings.TrimPrefix(field, "$.") + field := tpath.NormalizePath(agg.Field) + field = strings.TrimPrefix(field, "$.") //FIXME stmt := []bson.M{ { "$match": bson.M{ @@ -801,7 +801,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile case *gripql.Aggregate_Percentile: agg := a.GetPercentile() - field := travelerpath.GetJSONPath(agg.Field) + field := tpath.NormalizePath(agg.Field) field = strings.TrimPrefix(field, "$.") stmt := []bson.M{ { @@ -835,8 +835,8 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile case *gripql.Aggregate_Type: agg := a.GetType() - field := travelerpath.GetJSONPath(agg.Field) - field = strings.TrimPrefix(field, "$.") + field := tpath.NormalizePath(agg.Field) + field = strings.TrimPrefix(field, "$.") //FIXME stmt := []bson.M{ { "$match": bson.M{ @@ -861,8 +861,8 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile case *gripql.Aggregate_Field: agg := a.GetField() - field := travelerpath.GetJSONPath(agg.Field) - field = strings.TrimPrefix(field, "$.") + field := tpath.NormalizePath(agg.Field) + field = strings.TrimPrefix(field, "$.") //FIXME stmt := []bson.M{ { "$match": bson.M{ diff --git a/mongo/compile_test.go b/mongo/compile_test.go index b3bf2c6f..486fab93 100644 --- a/mongo/compile_test.go +++ b/mongo/compile_test.go @@ -5,8 +5,8 @@ import ( "strings" "testing" + "github.com/bmeg/grip/gdbi/tpath" "github.com/bmeg/grip/gripql" - "github.com/bmeg/grip/travelerpath" "github.com/bmeg/grip/util" "go.mongodb.org/mongo-driver/bson" ) @@ -37,14 +37,14 @@ func TestDistinctPathing(t *testing.T) { keys := bson.M{} for _, f := range fields { - namespace := travelerpath.GetNamespace(f) + namespace := tpath.GetNamespace(f) fmt.Printf("Namespace: %s\n", namespace) - f = travelerpath.GetJSONPath(f) + f = tpath.NormalizePath(f) f = strings.TrimPrefix(f, "$.") if f == "gid" { f = FIELD_ID } - if namespace != travelerpath.Current { + if namespace != tpath.CURRENT { f = fmt.Sprintf("marks.%s.%s", namespace, f) } match[f] = bson.M{"$exists": true} diff --git a/mongo/has_evaluator.go b/mongo/has_evaluator.go index 5e6dbc22..0e804eff 100644 --- a/mongo/has_evaluator.go +++ b/mongo/has_evaluator.go @@ -1,11 +1,12 @@ package mongo import ( + "fmt" "strings" + "github.com/bmeg/grip/gdbi/tpath" "github.com/bmeg/grip/gripql" "github.com/bmeg/grip/log" - "github.com/bmeg/grip/travelerpath" "go.mongodb.org/mongo-driver/bson" ) @@ -80,11 +81,12 @@ func convertHasExpression(stmt *gripql.HasExpression, not bool) bson.M { } func convertPath(key string) string { - key = travelerpath.GetJSONPath(key) + key = tpath.NormalizePath(key) key = strings.TrimPrefix(key, "$.") if key == "gid" { key = "_id" } + fmt.Printf("Key: %s\n", key) return key } diff --git a/mongo/index.go b/mongo/index.go index 55e7a9ff..91eddd61 100644 --- a/mongo/index.go +++ b/mongo/index.go @@ -5,9 +5,9 @@ import ( "fmt" "strings" + "github.com/bmeg/grip/gdbi/tpath" "github.com/bmeg/grip/gripql" "github.com/bmeg/grip/log" - "github.com/bmeg/grip/travelerpath" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" @@ -16,8 +16,8 @@ import ( // AddVertexIndex add index to vertices func (mg *Graph) AddVertexIndex(label string, field string) error { log.WithFields(log.Fields{"label": label, "field": field}).Info("Adding vertex index") - field = travelerpath.GetJSONPath(field) - field = strings.TrimPrefix(field, "$.") + field = tpath.NormalizePath(field) + field = strings.TrimPrefix(field, "$.") //FIXME idx := mg.ar.VertexCollection(mg.graph).Indexes() @@ -36,8 +36,8 @@ func (mg *Graph) AddVertexIndex(label string, field string) error { // DeleteVertexIndex delete index from vertices func (mg *Graph) DeleteVertexIndex(label string, field string) error { log.WithFields(log.Fields{"label": label, "field": field}).Info("Deleting vertex index") - field = travelerpath.GetJSONPath(field) - field = strings.TrimPrefix(field, "$.") + field = tpath.NormalizePath(field) + field = strings.TrimPrefix(field, "$.") //FIXME idx := mg.ar.VertexCollection(mg.graph).Indexes() cursor, err := idx.List(context.TODO()) From 610803b7d868eab4384d4affdc5c2cfd46f7749f Mon Sep 17 00:00:00 2001 From: Kyle Ellrott Date: Thu, 15 Feb 2024 23:05:03 -0800 Subject: [PATCH 16/23] Fixing more conformance testing issues --- conformance/tests/ot_fields.py | 2 +- gdbi/traveler_doc.go | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/conformance/tests/ot_fields.py b/conformance/tests/ot_fields.py index 8ad06aa0..134e5ebd 100644 --- a/conformance/tests/ot_fields.py +++ b/conformance/tests/ot_fields.py @@ -11,7 +11,7 @@ def test_fields(man): } resp = G.query().V("Character:1").fields(["name"]).execute() if resp[0] != expected: - errors.append("vertex contains incorrect fields: \nexpected:%s\nresponse:%s" % (expected, resp)) + errors.append("""Query 'V("Character:1").fields(["name"])' vertex contains incorrect fields: \nexpected:%s\nresponse:%s""" % (expected, resp)) expected = { u"gid": u"Character:1", diff --git a/gdbi/traveler_doc.go b/gdbi/traveler_doc.go index f59c7f5a..2a6c5f3c 100644 --- a/gdbi/traveler_doc.go +++ b/gdbi/traveler_doc.go @@ -137,12 +137,12 @@ KeyLoop: continue KeyLoop } path := tpath.NormalizePath(key) - path = strings.TrimPrefix(path, "$.") //FIXME - + jpath := tpath.ToLocalPath(path) + spath := strings.TrimPrefix(jpath, "$.") if exclude { - excludePaths = append(excludePaths, path) + excludePaths = append(excludePaths, spath) } else { - includePaths = append(includePaths, path) + includePaths = append(includePaths, spath) } } @@ -186,10 +186,6 @@ Include: switch path { case "_gid", "_label", "_from", "_to": // noop - case "data": - for k, v := range old.Data { - newData[k] = v - } default: parts := strings.Split(path, ".") var data map[string]interface{} From eaef88e412262c2f7dafa0f41191aa890eb8f0f6 Mon Sep 17 00:00:00 2001 From: Kyle Ellrott Date: Fri, 16 Feb 2024 20:52:35 -0800 Subject: [PATCH 17/23] Fixing various issues to get the key/value graph store to work --- engine/core/processors.go | 5 +- gdbi/data_element.go | 144 ++++++++++++++++++++++++++++++++++++++ gdbi/interface.go | 3 + gdbi/tpath/fields.go | 5 ++ gdbi/traveler.go | 120 +++---------------------------- gdbi/traveler_doc.go | 36 ++++++++-- 6 files changed, 196 insertions(+), 117 deletions(-) create mode 100644 gdbi/data_element.go create mode 100644 gdbi/tpath/fields.go diff --git a/engine/core/processors.go b/engine/core/processors.go index 8aead1f2..c9c851c8 100644 --- a/engine/core/processors.go +++ b/engine/core/processors.go @@ -10,6 +10,7 @@ import ( "github.com/bmeg/grip/engine/logic" "github.com/bmeg/grip/gdbi" + "github.com/bmeg/grip/gdbi/tpath" "github.com/bmeg/grip/gripql" "github.com/bmeg/grip/log" "github.com/bmeg/grip/util/copy" @@ -1106,7 +1107,9 @@ func (agg *aggregate) Process(ctx context.Context, man gdbi.Manager, in gdbi.InP val := gdbi.TravelerPathLookup(t, fa.Field) if m, ok := val.(map[string]interface{}); ok { for k := range m { - fieldCounts[k]++ + if !tpath.IsGraphField(k) { + fieldCounts[k]++ + } } } } diff --git a/gdbi/data_element.go b/gdbi/data_element.go new file mode 100644 index 00000000..b3fca12f --- /dev/null +++ b/gdbi/data_element.go @@ -0,0 +1,144 @@ +package gdbi + +import ( + "errors" + "fmt" + + "github.com/bmeg/grip/gripql" + "google.golang.org/protobuf/types/known/structpb" +) + +// ToVertex converts data element to vertex +func (elem *DataElement) ToVertex() *gripql.Vertex { + sValue, err := structpb.NewStruct(elem.Data) + if err != nil { + fmt.Printf("Error: %s %#v\n", err, elem.Data) + } + return &gripql.Vertex{ + Gid: elem.ID, + Label: elem.Label, + Data: sValue, + } +} + +// ToEdge converts data element to edge +func (elem *DataElement) ToEdge() *gripql.Edge { + sValue, _ := structpb.NewStruct(elem.Data) + return &gripql.Edge{ + Gid: elem.ID, + From: elem.From, + To: elem.To, + Label: elem.Label, + Data: sValue, + } +} + +// ToDict converts data element to generic map +func (elem *DataElement) ToDict() map[string]interface{} { + /* + out := map[string]interface{}{ + "gid": "", + "label": "", + "to": "", + "from": "", + "data": map[string]interface{}{}, + } + */ + out := map[string]interface{}{} + if elem == nil { + return out + } + for k, v := range elem.Data { + out[k] = v + } + if elem.ID != "" { + out["_gid"] = elem.ID + } + if elem.Label != "" { + out["_label"] = elem.Label + } + if elem.To != "" { + out["_to"] = elem.To + } + if elem.From != "" { + out["_from"] = elem.From + } + return out +} + +func (elem *DataElement) FromDict(d map[string]any) { + if elem.Data == nil { + elem.Data = map[string]any{} + } + for k, v := range d { + switch k { + case "_to": + if vStr, ok := v.(string); ok { + elem.To = vStr + } + case "_from": + if vStr, ok := v.(string); ok { + elem.From = vStr + } + case "_gid": + if vStr, ok := v.(string); ok { + elem.ID = vStr + } + case "_label": + if vStr, ok := v.(string); ok { + elem.Label = vStr + } + default: + elem.Data[k] = v + } + } + elem.Loaded = true +} + +// Validate returns an error if the vertex is invalid +func (vertex *Vertex) Validate() error { + if vertex.ID == "" { + return errors.New("'gid' cannot be blank") + } + if vertex.Label == "" { + return errors.New("'label' cannot be blank") + } + for k := range vertex.Data { + err := gripql.ValidateFieldName(k) + if err != nil { + return err + } + } + return nil +} + +func NewGraphElement(g *gripql.GraphElement) *GraphElement { + o := GraphElement{Graph: g.Graph} + if g.Vertex != nil { + o.Vertex = NewElementFromVertex(g.Vertex) + } + if g.Edge != nil { + o.Edge = NewElementFromEdge(g.Edge) + } + return &o +} + +func NewElementFromVertex(v *gripql.Vertex) *Vertex { + return &Vertex{ + ID: v.Gid, + Label: v.Label, + Data: v.Data.AsMap(), + Loaded: true, + } +} + +func NewElementFromEdge(e *gripql.Edge) *Edge { + return &Edge{ + ID: e.Gid, + Label: e.Label, + To: e.To, + From: e.From, + Data: e.Data.AsMap(), + Loaded: true, + } +} diff --git a/gdbi/interface.go b/gdbi/interface.go index 331392d5..08384fbc 100644 --- a/gdbi/interface.go +++ b/gdbi/interface.go @@ -98,7 +98,10 @@ type Traveler interface { Copy() Traveler HasMark(label string) bool GetMark(label string) DataRef + // AddMark adds a new mark to the data and return a duplicated Traveler AddMark(label string, r DataRef) Traveler + // UpdateMark changes the data of a mark in the original traveler (vs AddMark which changes a copy of the traveler) + UpdateMark(label string, r DataRef) ListMarks() []string GetSelections() map[string]DataRef GetRender() interface{} diff --git a/gdbi/tpath/fields.go b/gdbi/tpath/fields.go new file mode 100644 index 00000000..f6cd6c4e --- /dev/null +++ b/gdbi/tpath/fields.go @@ -0,0 +1,5 @@ +package tpath + +func IsGraphField(f string) bool { + return f == "_gid" || f == "_label" || f == "_to" || f == "_from" +} diff --git a/gdbi/traveler.go b/gdbi/traveler.go index af7dfc8c..b5162e13 100644 --- a/gdbi/traveler.go +++ b/gdbi/traveler.go @@ -1,12 +1,8 @@ package gdbi import ( - "errors" - "fmt" - - "github.com/bmeg/grip/gripql" + "github.com/bmeg/grip/gdbi/tpath" "github.com/bmeg/grip/util/copy" - "google.golang.org/protobuf/types/known/structpb" ) // These consts mark the type of a Pipeline traveler chan @@ -120,6 +116,14 @@ func (t *BaseTraveler) AddMark(label string, r DataRef) Traveler { return &o } +func (t *BaseTraveler) UpdateMark(label string, r DataRef) { + if label == tpath.CURRENT { + t.Current = r.Get() + return + } + t.Marks[label] = r.Get() +} + // GetMark gets stored result in travels state using its label func (t *BaseTraveler) GetMark(label string) DataRef { return t.Marks[label] @@ -157,109 +161,3 @@ func (t *BaseTraveler) GetPath() []DataElementID { func (t BaseTraveler) GetAggregation() *Aggregate { return t.Aggregation } - -func NewElementFromVertex(v *gripql.Vertex) *Vertex { - return &Vertex{ - ID: v.Gid, - Label: v.Label, - Data: v.Data.AsMap(), - Loaded: true, - } -} - -func NewElementFromEdge(e *gripql.Edge) *Edge { - return &Edge{ - ID: e.Gid, - Label: e.Label, - To: e.To, - From: e.From, - Data: e.Data.AsMap(), - Loaded: true, - } -} - -// ToVertex converts data element to vertex -func (elem *DataElement) ToVertex() *gripql.Vertex { - sValue, err := structpb.NewStruct(elem.Data) - if err != nil { - fmt.Printf("Error: %s %#v\n", err, elem.Data) - } - return &gripql.Vertex{ - Gid: elem.ID, - Label: elem.Label, - Data: sValue, - } -} - -// ToEdge converts data element to edge -func (elem *DataElement) ToEdge() *gripql.Edge { - sValue, _ := structpb.NewStruct(elem.Data) - return &gripql.Edge{ - Gid: elem.ID, - From: elem.From, - To: elem.To, - Label: elem.Label, - Data: sValue, - } -} - -// ToDict converts data element to generic map -func (elem *DataElement) ToDict() map[string]interface{} { - /* - out := map[string]interface{}{ - "gid": "", - "label": "", - "to": "", - "from": "", - "data": map[string]interface{}{}, - } - */ - out := map[string]interface{}{} - if elem == nil { - return out - } - for k, v := range elem.Data { - out[k] = v - } - if elem.ID != "" { - out["_gid"] = elem.ID - } - if elem.Label != "" { - out["_label"] = elem.Label - } - if elem.To != "" { - out["_to"] = elem.To - } - if elem.From != "" { - out["_from"] = elem.From - } - return out -} - -// Validate returns an error if the vertex is invalid -func (vertex *Vertex) Validate() error { - if vertex.ID == "" { - return errors.New("'gid' cannot be blank") - } - if vertex.Label == "" { - return errors.New("'label' cannot be blank") - } - for k := range vertex.Data { - err := gripql.ValidateFieldName(k) - if err != nil { - return err - } - } - return nil -} - -func NewGraphElement(g *gripql.GraphElement) *GraphElement { - o := GraphElement{Graph: g.Graph} - if g.Vertex != nil { - o.Vertex = NewElementFromVertex(g.Vertex) - } - if g.Edge != nil { - o.Edge = NewElementFromEdge(g.Edge) - } - return &o -} diff --git a/gdbi/traveler_doc.go b/gdbi/traveler_doc.go index 2a6c5f3c..9e414934 100644 --- a/gdbi/traveler_doc.go +++ b/gdbi/traveler_doc.go @@ -91,22 +91,48 @@ func TravelerPathLookup(traveler Traveler, path string) interface{} { func TravelerSetValue(traveler Traveler, path string, val interface{}) error { field := tpath.NormalizePath(path) namespace := tpath.GetNamespace(field) + jpath := tpath.ToLocalPath(field) if field == "" { return nil } - doc := TravelerGetDoc(traveler, namespace) - return jsonpath.JsonPathSet(doc, field, val) + doc := TravelerGetMarkDoc(traveler, namespace) + err := jsonpath.JsonPathSet(doc, jpath, val) + if err != nil { + return err + } + r := DataElement{} + r.FromDict(doc) + traveler.UpdateMark(namespace, &r) + return nil } +/* +func TravelerSetMarkDoc(traveler Traveler, ns string, doc map[string]any ) error { + + d = DataElement{} + + + if ns == tpath.CURRENT { + return traveler.GetCurrent().Get().ToDict() + } + m := traveler.GetMark(ns) + if m != nil { + return m.Get().ToDict() + } + return nil +} +*/ + // TravelerPathExists returns true if the field exists in the given Traveler func TravelerPathExists(traveler Traveler, path string) bool { field := tpath.NormalizePath(path) + jpath := tpath.ToLocalPath(field) namespace := tpath.GetNamespace(field) - if field == "" { + if jpath == "" { return false } - doc := TravelerGetDoc(traveler, namespace) - _, err := jsonpath.JsonPathLookup(doc, field) + doc := TravelerGetMarkDoc(traveler, namespace) + _, err := jsonpath.JsonPathLookup(doc, jpath) return err == nil } From f52dce8f86194bdb91c716dc4f16a2db2fcecafe Mon Sep 17 00:00:00 2001 From: Kyle Ellrott Date: Fri, 16 Feb 2024 21:25:53 -0800 Subject: [PATCH 18/23] Fixing small issues around gripper driver testing --- conformance/tests/ot_aggregations.py | 3 ++- gripper/test-graph/test_gripper.py | 2 +- server/server.go | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/conformance/tests/ot_aggregations.py b/conformance/tests/ot_aggregations.py index e5809f53..2b9b42c5 100644 --- a/conformance/tests/ot_aggregations.py +++ b/conformance/tests/ot_aggregations.py @@ -190,7 +190,8 @@ def test_traversal_gid_aggregation(man): def test_field_aggregation(man): errors = [] - fields = [ "_gid", "_label", 'orbital_period', 'gravity', 'terrain', 'name','climate', 'system', 'diameter', 'rotation_period', 'url', 'population', 'surface_water'] + # TODO: find way to get gripper driver to drop id field + fields = [ "id", "_gid", "_label", 'orbital_period', 'gravity', 'terrain', 'name','climate', 'system', 'diameter', 'rotation_period', 'url', 'population', 'surface_water'] G = man.setGraph("swapi") count = 0 diff --git a/gripper/test-graph/test_gripper.py b/gripper/test-graph/test_gripper.py index 6ee4e464..c6c29b7c 100644 --- a/gripper/test-graph/test_gripper.py +++ b/gripper/test-graph/test_gripper.py @@ -39,7 +39,7 @@ def test_plugin_start(self): self.assertTrue(found) with open(os.path.join(BASE, "test-graph/swapi.yaml")) as handle: - mappingGraph = yaml.load(handle.read()) + mappingGraph = yaml.load(handle.read(), Loader=yaml.BaseLoader) conn = gripql.Connection(SERVER) graphName = "posted_tabledata_%s" % (''.join(random.choices(string.ascii_uppercase + string.digits, k=4))) conn.postMapping(graphName, mappingGraph['vertices'], mappingGraph['edges']) diff --git a/server/server.go b/server/server.go index a693efa7..dede2cd3 100644 --- a/server/server.go +++ b/server/server.go @@ -86,6 +86,8 @@ func NewGripServer(conf *config.Config, baseDir string, drivers map[string]gdbi. g, err := StartDriver(dConfig, sources) if err == nil { gdbs[name] = g + } else { + log.Errorf("Driver start error: %s", err) } } } From 5357f73dc4342611358dca66275b9369c8304f9b Mon Sep 17 00:00:00 2001 From: Kyle Ellrott Date: Sat, 17 Feb 2024 09:51:32 -0800 Subject: [PATCH 19/23] Fixing issues around mongo engine --- conformance/tests/ot_basic.py | 4 +- gripql/javascript/gripql.js | 2 + mongo/compile.go | 95 ++++++++++++----------------------- mongo/fields.go | 20 ++++++++ mongo/has_evaluator.go | 25 +++------ mongo/index.go | 4 +- mongo/processor.go | 23 ++------- 7 files changed, 68 insertions(+), 105 deletions(-) diff --git a/conformance/tests/ot_basic.py b/conformance/tests/ot_basic.py index 80b4a897..4af8b4b2 100644 --- a/conformance/tests/ot_basic.py +++ b/conformance/tests/ot_basic.py @@ -330,9 +330,9 @@ def test_out_edge_out_all(man): G = man.setGraph("swapi") for i in G.query().V().as_("a").outE().as_("b").out().as_("c").render(["$a._gid", "$b._from", "$b._to", "$c._gid"]): if i[0] != i[1]: - errors.append("outE-out _gid/from missmatch %s != %s" % (i[0], i[1])) + errors.append("outE-out _gid/from missmatch '%s' != '%s'" % (i[0], i[1])) if i[2] != i[3]: - errors.append("outE-out to/_gid missmatch %s != %s" % (i[0], i[1])) + errors.append("outE-out to/_gid missmatch '%s' != '%s'" % (i[2], i[3])) return errors diff --git a/gripql/javascript/gripql.js b/gripql/javascript/gripql.js index 0fe9789b..5ed50be3 100644 --- a/gripql/javascript/gripql.js +++ b/gripql/javascript/gripql.js @@ -278,6 +278,8 @@ gripql = { "lte" : lte, "gte" : gte, "eq" : eq, + "without": without, + "within" : within, } function V(id) { diff --git a/mongo/compile.go b/mongo/compile.go index 2fe95585..f5beb50a 100644 --- a/mongo/compile.go +++ b/mongo/compile.go @@ -396,13 +396,9 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile query = append(query, bson.D{primitive.E{Key: "$unwind", Value: "$dst"}}) } query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - FIELD_ID: "$dst._id", - FIELD_LABEL: "$dst._label", - FIELD_TO: "$dst._to", - FIELD_FROM: "$dst._from", - "data": "$dst", - "marks": "$marks", - "path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"edge": "$dst._id"}}}}, + FIELD_CURRENT: "$dst", + "marks": "$marks", + "path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"edge": "$dst._id"}}}}, }}}) lastType = gdbi.EdgeData @@ -448,13 +444,9 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile query = append(query, bson.D{primitive.E{Key: "$unwind", Value: "$dst"}}) } query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - FIELD_ID: "$dst._id", - FIELD_LABEL: "$dst._label", - FIELD_TO: "$dst._to", - FIELD_FROM: "$dst._from", - "data": "$dst", - "marks": "$marks", - "path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"edge": "$dst._id"}}}}, + FIELD_CURRENT: "$dst", + "marks": "$marks", + "path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"edge": "$dst._id"}}}}, }}}) lastType = gdbi.EdgeData @@ -488,13 +480,9 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile ) query = append(query, bson.D{primitive.E{Key: "$unwind", Value: "$dst"}}) query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - FIELD_ID: "$dst._id", - FIELD_LABEL: "$dst._label", - FIELD_TO: "$dst._to", - FIELD_FROM: "$dst._from", - "data": "$dst.data", - "marks": "$marks", - "path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"edge": "$dst._id"}}}}, + FIELD_CURRENT: "$dst", + "marks": "$marks", + "path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"edge": "$dst._id"}}}}, }}}) labels := protoutil.AsStringList(stmt.BothE) if len(labels) > 0 { @@ -538,10 +526,11 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile hasKeys := bson.M{} keys := protoutil.AsStringList(stmt.HasKey) for _, key := range keys { - key = tpath.NormalizePath(key) - key = strings.TrimPrefix(key, "$.") - hasKeys[key] = bson.M{"$exists": true} + lKey := ToPipelinePath(key) + fmt.Printf("Key: %s -> %s\n", key, lKey) + hasKeys[lKey] = bson.M{"$exists": true} } + fmt.Printf("hasKey: %#v\n", hasKeys) query = append(query, bson.D{primitive.E{Key: "$match", Value: hasKeys}}) case *gripql.GraphStatement_Limit: @@ -576,18 +565,10 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile keys := bson.M{} match := bson.M{} for _, f := range fields { - namespace := tpath.GetNamespace(f) - f = tpath.NormalizePath(f) - f = strings.TrimPrefix(f, "$.") //FIXME - if f == "gid" { - f = "_id" - } - if namespace != tpath.CURRENT { - f = fmt.Sprintf("marks.%s.%s", namespace, f) - } - match[f] = bson.M{"$exists": true} - k := strings.Replace(f, ".", "_", -1) - keys[k] = "$" + f + p := ToPipelinePath(f) + match[p] = bson.M{"$exists": true} + k := strings.Replace(f, ".", "_", -1) // FIXME + keys[k] = f } query = append(query, bson.D{primitive.E{ Key: "$match", Value: match, @@ -634,7 +615,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile return &Pipeline{}, fmt.Errorf(`"as" statement invalid; uses reserved name %s`, tpath.CURRENT) } markTypes[stmt.As] = lastType - query = append(query, bson.D{primitive.E{Key: "$addFields", Value: bson.M{"marks": bson.M{stmt.As: "$$ROOT"}}}}) + query = append(query, bson.D{primitive.E{Key: "$addFields", Value: bson.M{"marks": bson.M{stmt.As: "$" + FIELD_CURRENT}}}}) case *gripql.GraphStatement_Select: if lastType != gdbi.VertexData && lastType != gdbi.EdgeData { @@ -644,23 +625,17 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile switch markTypes[stmt.Select] { case gdbi.VertexData: query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - "_id": mark + "._id", - "_label": mark + "._label", - "data": mark + ".data", - "marks": 1, - "path": "$path", + FIELD_CURRENT: mark, + "marks": 1, + "path": "$path", //"path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"vertex": mark + "._id"}}}}, }}}) lastType = gdbi.VertexData case gdbi.EdgeData: query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - "_id": mark + "._id", - "_label": mark + "._label", - "_from": mark + "._from", - "_to": mark + "._to", - "data": mark + ".data", - "marks": 1, - "path": "$path", + FIELD_CURRENT: mark, + "marks": 1, + "path": "$path", //"path": bson.M{"$concatArrays": []interface{}{"$path", []bson.M{{"edge": mark + "._id"}}}}, }}}) lastType = gdbi.EdgeData @@ -698,13 +673,13 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile exclude = true f = strings.TrimPrefix(f, "-") } + f = tpath.NormalizePath(f) namespace := tpath.GetNamespace(f) if namespace != tpath.CURRENT { log.Errorf("FieldsProcessor: only can select field from current traveler") continue SelectLoop } - f = tpath.NormalizePath(f) - f = strings.TrimPrefix(f, "$.") //FIXME + f = tpath.ToLocalPath(f) if exclude { excludeFields = append(excludeFields, f) } else { @@ -753,11 +728,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile switch a.Aggregation.(type) { case *gripql.Aggregate_Term: agg := a.GetTerm() - field := tpath.NormalizePath(agg.Field) - field = strings.TrimPrefix(field, "$.") //FIXME - if field == "gid" { - field = "_id" - } + field := ToPipelinePath(agg.Field) stmt := []bson.M{ { "$match": bson.M{ @@ -776,8 +747,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile case *gripql.Aggregate_Histogram: agg := a.GetHistogram() - field := tpath.NormalizePath(agg.Field) - field = strings.TrimPrefix(field, "$.") //FIXME + field := ToPipelinePath(agg.Field) stmt := []bson.M{ { "$match": bson.M{ @@ -801,8 +771,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile case *gripql.Aggregate_Percentile: agg := a.GetPercentile() - field := tpath.NormalizePath(agg.Field) - field = strings.TrimPrefix(field, "$.") + field := ToPipelinePath(agg.Field) stmt := []bson.M{ { "$match": bson.M{ @@ -835,8 +804,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile case *gripql.Aggregate_Type: agg := a.GetType() - field := tpath.NormalizePath(agg.Field) - field = strings.TrimPrefix(field, "$.") //FIXME + field := ToPipelinePath(agg.Field) stmt := []bson.M{ { "$match": bson.M{ @@ -861,8 +829,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile case *gripql.Aggregate_Field: agg := a.GetField() - field := tpath.NormalizePath(agg.Field) - field = strings.TrimPrefix(field, "$.") //FIXME + field := ToPipelinePath(agg.Field) stmt := []bson.M{ { "$match": bson.M{ diff --git a/mongo/fields.go b/mongo/fields.go index 1eacc990..dd6f49a9 100644 --- a/mongo/fields.go +++ b/mongo/fields.go @@ -1,10 +1,18 @@ package mongo +import ( + "strings" + + "github.com/bmeg/grip/gdbi/tpath" +) + const FIELD_ID = "_id" const FIELD_LABEL = "_label" const FIELD_TO = "_to" const FIELD_FROM = "_from" +const FIELD_MARKS = "marks" + const FIELD_CURRENT = "data" const FIELD_CURRENT_ID = "data._id" const FIELD_CURRENT_TO = "data._to" @@ -30,3 +38,15 @@ func RemoveKeyFields(x map[string]any) map[string]any { } return out } + +func ToPipelinePath(p string) string { + n := tpath.NormalizePath(p) + ns := tpath.GetNamespace(n) + path := tpath.ToLocalPath(n) + path = strings.TrimPrefix(path, "$.") + + if ns == tpath.CURRENT { + return FIELD_CURRENT + "." + path + } + return FIELD_MARKS + "." + ns + "." + path +} diff --git a/mongo/has_evaluator.go b/mongo/has_evaluator.go index 0e804eff..9838a08a 100644 --- a/mongo/has_evaluator.go +++ b/mongo/has_evaluator.go @@ -1,10 +1,6 @@ package mongo import ( - "fmt" - "strings" - - "github.com/bmeg/grip/gdbi/tpath" "github.com/bmeg/grip/gripql" "github.com/bmeg/grip/log" "go.mongodb.org/mongo-driver/bson" @@ -22,7 +18,8 @@ func convertHasExpression(stmt *gripql.HasExpression, not bool) bson.M { if !ok { log.Error("unable to cast values from INSIDE statement") } else { - output = convertHasExpression(gripql.And(gripql.Gt(cond.Key, lims[0]), gripql.Lt(cond.Key, lims[1])), not) + key := ToPipelinePath(cond.Key) + output = convertHasExpression(gripql.And(gripql.Gt(key, lims[0]), gripql.Lt(key, lims[1])), not) } case gripql.Condition_OUTSIDE: @@ -31,7 +28,8 @@ func convertHasExpression(stmt *gripql.HasExpression, not bool) bson.M { if !ok { log.Error("unable to cast values from OUTSIDE statement") } else { - output = convertHasExpression(gripql.Or(gripql.Lt(cond.Key, lims[0]), gripql.Gt(cond.Key, lims[1])), not) + key := ToPipelinePath(cond.Key) + output = convertHasExpression(gripql.Or(gripql.Lt(key, lims[0]), gripql.Gt(key, lims[1])), not) } case gripql.Condition_BETWEEN: @@ -40,7 +38,8 @@ func convertHasExpression(stmt *gripql.HasExpression, not bool) bson.M { if !ok { log.Error("unable to cast values from BETWEEN statement") } else { - output = convertHasExpression(gripql.And(gripql.Gte(cond.Key, lims[0]), gripql.Lt(cond.Key, lims[1])), not) + key := ToPipelinePath(cond.Key) + output = convertHasExpression(gripql.And(gripql.Gte(key, lims[0]), gripql.Lt(key, lims[1])), not) } default: @@ -80,20 +79,10 @@ func convertHasExpression(stmt *gripql.HasExpression, not bool) bson.M { return output } -func convertPath(key string) string { - key = tpath.NormalizePath(key) - key = strings.TrimPrefix(key, "$.") - if key == "gid" { - key = "_id" - } - fmt.Printf("Key: %s\n", key) - return key -} - func convertCondition(cond *gripql.HasCondition, not bool) bson.M { var key string var val interface{} - key = convertPath(cond.Key) + key = ToPipelinePath(cond.Key) val = cond.Value.AsInterface() expr := bson.M{} switch cond.Condition { diff --git a/mongo/index.go b/mongo/index.go index 91eddd61..3077d255 100644 --- a/mongo/index.go +++ b/mongo/index.go @@ -17,7 +17,8 @@ import ( func (mg *Graph) AddVertexIndex(label string, field string) error { log.WithFields(log.Fields{"label": label, "field": field}).Info("Adding vertex index") field = tpath.NormalizePath(field) - field = strings.TrimPrefix(field, "$.") //FIXME + field = tpath.ToLocalPath(field) + field = strings.TrimPrefix(field, "$.") idx := mg.ar.VertexCollection(mg.graph).Indexes() @@ -37,6 +38,7 @@ func (mg *Graph) AddVertexIndex(label string, field string) error { func (mg *Graph) DeleteVertexIndex(label string, field string) error { log.WithFields(log.Fields{"label": label, "field": field}).Info("Deleting vertex index") field = tpath.NormalizePath(field) + field = tpath.ToLocalPath(field) field = strings.TrimPrefix(field, "$.") //FIXME idx := mg.ar.VertexCollection(mg.graph).Indexes() diff --git a/mongo/processor.go b/mongo/processor.go index 8b36b38c..de7630b5 100644 --- a/mongo/processor.go +++ b/mongo/processor.go @@ -199,8 +199,8 @@ func (proc *Processor) Process(ctx context.Context, man gdbi.Manager, in gdbi.In } //Extract marks if marks, ok := result["marks"]; ok { - if marks, ok := marks.(map[string]interface{}); ok { - for k, v := range marks { + if markDict, ok := marks.(map[string]interface{}); ok { + for k, v := range markDict { if v, ok := v.(map[string]interface{}); ok { de := getDataElement(v) t = t.AddMark(k, de) @@ -209,24 +209,7 @@ func (proc *Processor) Process(ctx context.Context, man gdbi.Manager, in gdbi.In } } - de := &gdbi.DataElement{} - data := removePrimatives(result["data"]).(map[string]any) - if x, ok := data[FIELD_ID]; ok { - de.ID = removePrimatives(x).(string) - } - if x, ok := data[FIELD_LABEL]; ok { - de.Label = x.(string) - } - //if x, ok := result["data"]; ok { - de.Data = RemoveKeyFields(data) //removePrimatives(x).(map[string]interface{}) - de.Loaded = true - //} - if x, ok := data[FIELD_TO]; ok { - de.To = x.(string) - } - if x, ok := data[FIELD_FROM]; ok { - de.From = x.(string) - } + de := getDataElement(result[FIELD_CURRENT].(map[string]any)) out <- t.AddCurrent(de) } } From 69c4867e14e4e5f96925d00f66b1d1f61b580a27 Mon Sep 17 00:00:00 2001 From: Kyle Ellrott Date: Sat, 17 Feb 2024 21:37:25 -0800 Subject: [PATCH 20/23] Fixing additional issues to clear errors in mongo engine --- conformance/tests/ot_aggregations.py | 6 ++-- conformance/tests/ot_basic.py | 2 +- conformance/tests/ot_distinct.py | 12 +++---- conformance/tests/ot_has.py | 2 +- conformance/tests/ot_path_optimize.py | 4 +-- gripql/javascript/gripql.js | 5 +++ mongo/compile.go | 47 ++++++++++++--------------- mongo/fields.go | 10 ++++++ mongo/has_evaluator.go | 15 +++++---- 9 files changed, 58 insertions(+), 45 deletions(-) diff --git a/conformance/tests/ot_aggregations.py b/conformance/tests/ot_aggregations.py index 2b9b42c5..92040cef 100644 --- a/conformance/tests/ot_aggregations.py +++ b/conformance/tests/ot_aggregations.py @@ -191,7 +191,7 @@ def test_field_aggregation(man): errors = [] # TODO: find way to get gripper driver to drop id field - fields = [ "id", "_gid", "_label", 'orbital_period', 'gravity', 'terrain', 'name','climate', 'system', 'diameter', 'rotation_period', 'url', 'population', 'surface_water'] + fields = [ "_id", "id", "_gid", "_label", 'orbital_period', 'gravity', 'terrain', 'name','climate', 'system', 'diameter', 'rotation_period', 'url', 'population', 'surface_water'] G = man.setGraph("swapi") count = 0 @@ -201,8 +201,8 @@ def test_field_aggregation(man): if row["value"] != 3: errors.append("incorrect count returned: %s" % (row['value'])) count += 1 - if count not in [11, 12]: # gripper returns an id field as well, others dont.... - errors.append("Incorrect number of results returned") + if count not in [11, 12, 13]: # gripper returns an id field as well, others dont.... + errors.append("""V().hasLabel("Planet").aggregate(gripql.field("gid-agg", "$")) : Incorrect number of results returned %d""" % (count)) return errors diff --git a/conformance/tests/ot_basic.py b/conformance/tests/ot_basic.py index 4af8b4b2..e6db22ac 100644 --- a/conformance/tests/ot_basic.py +++ b/conformance/tests/ot_basic.py @@ -435,7 +435,7 @@ def test_both_edge(man): c = G.query().V("Character:1").bothE(["homeworld", "residents"]).count().execute()[0]["count"] if c != 2: - errors.append("Fail: G.query().V(\"Character:1\").inE([\"homeworld\", \"residents\"]).count() - %s != %s" % (c, 2)) + errors.append("Fail: G.query().V(\"Character:1\").bothE([\"homeworld\", \"residents\"]).count() - %s != %s" % (c, 2)) return errors diff --git a/conformance/tests/ot_distinct.py b/conformance/tests/ot_distinct.py index 4084c009..1ec497ab 100644 --- a/conformance/tests/ot_distinct.py +++ b/conformance/tests/ot_distinct.py @@ -7,25 +7,25 @@ def test_distinct(man): for i in G.query().V().distinct(): count += 1 if count != 39: - errors.append("Distinct %s != %s" % (count, 39)) + errors.append("V().distinct() distinct count %s != %s" % (count, 39)) count = 0 for i in G.query().V().distinct("_gid"): count += 1 if count != 39: - errors.append("Distinct %s != %s" % (count, 39)) + errors.append("""V().distinct("_gid") distinct count %s != %s""" % (count, 39)) count = 0 for i in G.query().V().distinct("eye_color"): count += 1 if count != 8: - errors.append("Distinct %s != %s" % (count, 8)) + errors.append("""V().distinct("eye_color") distinct count %s != %s""" % (count, 8)) count = 0 for i in G.query().V().distinct("gender"): count += 1 if count != 4: - errors.append("Distinct %s != %s" % (count, 4)) + errors.append("""V().distinct("gender") distinct count %s != %s""" % (count, 4)) count = 0 for i in G.query().V().distinct("non-existent-field"): @@ -37,13 +37,13 @@ def test_distinct(man): for i in G.query().V().hasLabel("Character").as_("person").out().distinct("$person.name"): count += 1 if count != 18: - errors.append("Distinct G.query().V().hasLabel(\"Person\").as_(\"person\").out().distinct(\"$person.name\") %s != %s" % (count, 18)) + errors.append("Distinct G.query().V().hasLabel(\"Character\").as_(\"person\").out().distinct(\"$person.name\") %s != %s" % (count, 18)) count = 0 for i in G.query().V().hasLabel("Character").as_("person").out().distinct("$person.eye_color"): count += 1 if count != 8: - errors.append("Distinct G.query().V().hasLabel(\"Person\").as_(\"person\").out().distinct(\"$person.eye_color\") %s != %s" % (count, 8)) + errors.append("Distinct G.query().V().hasLabel(\"Character\").as_(\"person\").out().distinct(\"$person.eye_color\") %s != %s" % (count, 8)) return errors diff --git a/conformance/tests/ot_has.py b/conformance/tests/ot_has.py index 89ea7723..1cde1628 100644 --- a/conformance/tests/ot_has.py +++ b/conformance/tests/ot_has.py @@ -75,7 +75,7 @@ def test_hasId(man): errors.append("Wrong vertex returned %s" % (i)) if count != 1: errors.append( - "Fail: G.query().V().hasId(\"01\") %s != %s" % + "Fail: G.query().V().hasId(\"Character:1\") %s != %s" % (count, 1)) count = 0 diff --git a/conformance/tests/ot_path_optimize.py b/conformance/tests/ot_path_optimize.py index fcabd352..bac68e9c 100644 --- a/conformance/tests/ot_path_optimize.py +++ b/conformance/tests/ot_path_optimize.py @@ -30,13 +30,13 @@ def test_path_1(man): errors.append("Wrong label found at end of path: %s" % (res["label"])) count += 1 if count != 1814: - errors.append("out-out-outE Incorrect vertex count returned: %d != %d" % (count, 1814)) + errors.append("""V("Film:1").out().out().outE() Incorrect vertex count returned: %d != %d""" % (count, 1814)) count = 0 for res in G.query().V("Film:1").out().out().outE().out(): count += 1 if count != 1814: - errors.append("out-out-outE-out Incorrect vertex count returned: %d != %d" % (count, 1814)) + errors.append(""".V("Film:1").out().out().outE().out() Incorrect vertex count returned: %d != %d""" % (count, 1814)) return errors diff --git a/gripql/javascript/gripql.js b/gripql/javascript/gripql.js index 5ed50be3..800ffb5e 100644 --- a/gripql/javascript/gripql.js +++ b/gripql/javascript/gripql.js @@ -280,6 +280,11 @@ gripql = { "eq" : eq, "without": without, "within" : within, + "inside" : inside, + "field" : field, + "count" : count, + "histogram": histogram, + "percentile": percentile, } function V(id) { diff --git a/mongo/compile.go b/mongo/compile.go index f5beb50a..fc968a0e 100644 --- a/mongo/compile.go +++ b/mongo/compile.go @@ -369,7 +369,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile bson.D{primitive.E{ Key: "$lookup", Value: bson.M{ "from": edgeCol, - "localField": FIELD_ID, + "localField": FIELD_CURRENT_ID, "foreignField": FIELD_TO, "as": "dst", }, @@ -417,7 +417,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile bson.D{primitive.E{ Key: "$lookup", Value: bson.M{ "from": edgeCol, - "localField": FIELD_ID, + "localField": FIELD_CURRENT_ID, "foreignField": FIELD_FROM, "as": "dst", }, @@ -458,7 +458,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile bson.D{primitive.E{ Key: "$lookup", Value: bson.M{ "from": edgeCol, - "let": bson.M{"vid": "$_id", "marks": "$marks"}, + "let": bson.M{"vid": "$data._id", "marks": "$marks"}, "pipeline": []bson.M{ { "$match": bson.M{ @@ -486,7 +486,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile }}}) labels := protoutil.AsStringList(stmt.BothE) if len(labels) > 0 { - query = append(query, bson.D{primitive.E{Key: "$match", Value: bson.M{FIELD_LABEL: bson.M{"$in": labels}}}}) + query = append(query, bson.D{primitive.E{Key: "$match", Value: bson.M{"data._label": bson.M{"$in": labels}}}}) } lastType = gdbi.EdgeData @@ -514,7 +514,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile for i, v := range ids { iids[i] = v } - has := gripql.Within(FIELD_CURRENT_ID, iids...) + has := gripql.Within("_gid", iids...) whereExpr := convertHasExpression(has, false) matchStmt := bson.D{primitive.E{Key: "$match", Value: whereExpr}} query = append(query, matchStmt) @@ -560,15 +560,15 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile } fields := protoutil.AsStringList(stmt.Distinct) if len(fields) == 0 { - fields = append(fields, FIELD_ID) + fields = append(fields, "_id") } keys := bson.M{} match := bson.M{} for _, f := range fields { p := ToPipelinePath(f) match[p] = bson.M{"$exists": true} - k := strings.Replace(f, ".", "_", -1) // FIXME - keys[k] = f + k := strings.Replace(f[1:], ".", "_", -1) // FIXME + keys[k] = "$" + p } query = append(query, bson.D{primitive.E{ Key: "$match", Value: match, @@ -580,24 +580,19 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile }, }, }) + fmt.Printf("Distinct: %s\n", query) switch lastType { case gdbi.VertexData: query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - FIELD_ID: "$dst._id", - FIELD_LABEL: "$dst._label", - "data": "$dst.data", - "marks": "$dst.marks", - "path": "$dst.path", + "data": "$dst.data", + "marks": "$dst.marks", + "path": "$dst.path", }}}) case gdbi.EdgeData: query = append(query, bson.D{primitive.E{Key: "$project", Value: bson.M{ - FIELD_ID: "$dst._id", - FIELD_LABEL: "$dst.label", - FIELD_TO: "$dst.to", - FIELD_FROM: "$dst.from", - "data": "$dst.data", - "marks": "$dst.marks", - "path": "$dst.path", + "data": "$dst.data", + "marks": "$dst.marks", + "path": "$dst.path", }}}) } @@ -679,7 +674,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile log.Errorf("FieldsProcessor: only can select field from current traveler") continue SelectLoop } - f = tpath.ToLocalPath(f) + f = ToPipelinePath(f) if exclude { excludeFields = append(excludeFields, f) } else { @@ -693,16 +688,16 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile } if len(includeFields) > 0 || len(excludeFields) == 0 { - fieldSelect = bson.M{"_id": 1, "_label": 1, "_from": 1, "_to": 1, "marks": 1} + fieldSelect = bson.M{"data._id": 1, "data._label": 1, "data._from": 1, "data._to": 1, "marks": 1} for _, v := range excludeFields { switch v { - case "gid": + case "_gid": fieldSelect["_id"] = 0 - case "label": + case "_label": delete(fieldSelect, "label") - case "from": + case "_from": delete(fieldSelect, "from") - case "to": + case "_to": delete(fieldSelect, "to") } } diff --git a/mongo/fields.go b/mongo/fields.go index dd6f49a9..d82e7fc5 100644 --- a/mongo/fields.go +++ b/mongo/fields.go @@ -45,8 +45,18 @@ func ToPipelinePath(p string) string { path := tpath.ToLocalPath(n) path = strings.TrimPrefix(path, "$.") + if path == "_gid" { + path = "_id" + } + if ns == tpath.CURRENT { + if path == "$" { + return FIELD_CURRENT + } return FIELD_CURRENT + "." + path } + if path == "$" { + return FIELD_MARKS + "." + ns + } return FIELD_MARKS + "." + ns + "." + path } diff --git a/mongo/has_evaluator.go b/mongo/has_evaluator.go index 9838a08a..df3462a1 100644 --- a/mongo/has_evaluator.go +++ b/mongo/has_evaluator.go @@ -1,6 +1,8 @@ package mongo import ( + "fmt" + "github.com/bmeg/grip/gripql" "github.com/bmeg/grip/log" "go.mongodb.org/mongo-driver/bson" @@ -15,30 +17,31 @@ func convertHasExpression(stmt *gripql.HasExpression, not bool) bson.M { case gripql.Condition_INSIDE: val := cond.Value.AsInterface() lims, ok := val.([]interface{}) - if !ok { + if !ok || len(lims) < 2 { log.Error("unable to cast values from INSIDE statement") } else { - key := ToPipelinePath(cond.Key) + key := cond.Key output = convertHasExpression(gripql.And(gripql.Gt(key, lims[0]), gripql.Lt(key, lims[1])), not) + fmt.Printf("inside: %#v\n", output) } case gripql.Condition_OUTSIDE: val := cond.Value.AsInterface() lims, ok := val.([]interface{}) - if !ok { + if !ok || len(lims) < 2 { log.Error("unable to cast values from OUTSIDE statement") } else { - key := ToPipelinePath(cond.Key) + key := cond.Key output = convertHasExpression(gripql.Or(gripql.Lt(key, lims[0]), gripql.Gt(key, lims[1])), not) } case gripql.Condition_BETWEEN: val := cond.Value.AsInterface() lims, ok := val.([]interface{}) - if !ok { + if !ok || len(lims) < 2 { log.Error("unable to cast values from BETWEEN statement") } else { - key := ToPipelinePath(cond.Key) + key := cond.Key output = convertHasExpression(gripql.And(gripql.Gte(key, lims[0]), gripql.Lt(key, lims[1])), not) } From 942105bbc2cf8b7bff79766374cbf92fabb402fb Mon Sep 17 00:00:00 2001 From: Kyle Ellrott Date: Sat, 17 Feb 2024 21:39:19 -0800 Subject: [PATCH 21/23] Adding path conversion unit tests --- mongo/field_test.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 mongo/field_test.go diff --git a/mongo/field_test.go b/mongo/field_test.go new file mode 100644 index 00000000..ac6f62df --- /dev/null +++ b/mongo/field_test.go @@ -0,0 +1,18 @@ +package mongo + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestFields(t *testing.T) { + + assert.Equal(t, ToPipelinePath("name"), "data.name") + assert.Equal(t, ToPipelinePath("_gid"), "data._id") + assert.Equal(t, ToPipelinePath("$a.name"), "marks.a.name") + + assert.Equal(t, ToPipelinePath("$.name"), "data.name") + assert.Equal(t, ToPipelinePath("$"), "data") + +} From 0f84a35461a66acf91dd904a4ac51b4a1b3c73a0 Mon Sep 17 00:00:00 2001 From: Kyle Ellrott Date: Sun, 18 Feb 2024 23:07:31 -0800 Subject: [PATCH 22/23] Improving command line job submission utilities and fixing mongo core driver. - To make this work, the 'load' variable is being ignored, because it's not correctly predicited and optimized against. Only mongo-core takes advantage of it and fails. The query interogation and optimizer needs to be refined before the load method can be reenabled --- cmd/job/main.go | 101 ++++++++++++++++++++++++------------ cmd/query/main.go | 39 ++------------ conformance/tests/ot_has.py | 2 +- engine/pipeline/pipes.go | 14 ++--- gripql/client.go | 86 ++++++++++++++++++++++++++++-- gripql/javascript/gripql.js | 4 ++ gripql/javascript/parse.go | 47 +++++++++++++++++ mongo/graph.go | 68 ++++++++++++------------ 8 files changed, 249 insertions(+), 112 deletions(-) create mode 100644 gripql/javascript/parse.go diff --git a/cmd/job/main.go b/cmd/job/main.go index e70a2835..b3783e05 100644 --- a/cmd/job/main.go +++ b/cmd/job/main.go @@ -1,17 +1,14 @@ package job - import ( "fmt" - "encoding/json" + "github.com/bmeg/grip/gripql" + gripqljs "github.com/bmeg/grip/gripql/javascript" + _ "github.com/bmeg/grip/jsengine/goja" // import goja so it registers with the driver map "github.com/bmeg/grip/util/rpc" "github.com/spf13/cobra" - _ "github.com/bmeg/grip/jsengine/goja" // import goja so it registers with the driver map "google.golang.org/protobuf/encoding/protojson" - "github.com/dop251/goja" - gripqljs "github.com/bmeg/grip/gripql/javascript" - "github.com/bmeg/grip/jsengine/underscore" ) var host = "localhost:8202" @@ -28,7 +25,7 @@ var listJobsCmd = &cobra.Command{ Long: ``, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - graph := args[0] + graph := args[0] conn, err := gripql.Connect(rpc.ConfigWithDefaults(host), true) if err != nil { @@ -48,13 +45,13 @@ var listJobsCmd = &cobra.Command{ } var dropCmd = &cobra.Command{ - Use: "drop", - Short: "List graphs", + Use: "drop ", + Short: "Drop job", Long: ``, Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { - graph := args[0] - jobID := args[1] + graph := args[0] + jobID := args[1] conn, err := gripql.Connect(rpc.ConfigWithDefaults(host), true) if err != nil { @@ -65,19 +62,19 @@ var dropCmd = &cobra.Command{ if err != nil { return err } - fmt.Printf("%s\n", resp) + fmt.Printf("%s\n", resp) return nil }, } var getCmd = &cobra.Command{ - Use: "get job", + Use: "get ", Short: "Get job info", Long: ``, Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { - graph := args[0] - jobID := args[1] + graph := args[0] + jobID := args[1] conn, err := gripql.Connect(rpc.ConfigWithDefaults(host), true) if err != nil { @@ -103,60 +100,94 @@ var getCmd = &cobra.Command{ }, } - var submitCmd = &cobra.Command{ Use: "submit ", Short: "Submit query job", Long: ``, Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { - graph := args[0] + graph := args[0] queryString := args[1] - vm := goja.New() - us, err := underscore.Asset("underscore.js") + query, err := gripqljs.ParseQuery(queryString) if err != nil { - return fmt.Errorf("failed to load underscore.js") - } - if _, err := vm.RunString(string(us)); err != nil { return err } - gripqlString, err := gripqljs.Asset("gripql.js") + query.Graph = graph + + conn, err := gripql.Connect(rpc.ConfigWithDefaults(host), true) if err != nil { - return fmt.Errorf("failed to load gripql.js") + return err } - if _, err := vm.RunString(string(gripqlString)); err != nil { + + res, err := conn.Submit(query) + if err != nil { return err } - val, err := vm.RunString(queryString) + fmt.Printf("%s\n", res) + return nil + }, +} + +var resumeCmd = &cobra.Command{ + Use: "resume ", + Short: "Resume query job", + Long: ``, + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + graph := args[0] + jobID := args[1] + queryString := args[2] + + query, err := gripqljs.ParseQuery(queryString) if err != nil { return err } + query.Graph = graph - queryJSON, err := json.Marshal(val) + conn, err := gripql.Connect(rpc.ConfigWithDefaults(host), true) if err != nil { return err } - query := gripql.GraphQuery{} - err = protojson.Unmarshal(queryJSON, &query) + res, err := conn.ResumeJob(graph, jobID, query) if err != nil { return err } - query.Graph = graph + + for row := range res { + rowString, _ := protojson.Marshal(row) + fmt.Printf("%s\n", rowString) + } + return nil + + }, +} + +var viewCmd = &cobra.Command{ + Use: "view ", + Short: "Resume query job", + Long: ``, + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + graph := args[0] + jobID := args[1] conn, err := gripql.Connect(rpc.ConfigWithDefaults(host), true) if err != nil { return err } - res, err := conn.Submit(&query) + res, err := conn.ViewJob(graph, jobID) if err != nil { return err } - fmt.Printf("%s\n", res) + for row := range res { + rowString, _ := protojson.Marshal(row) + fmt.Printf("%s\n", rowString) + } return nil }, } @@ -164,9 +195,15 @@ var submitCmd = &cobra.Command{ func init() { listJobsCmd.Flags().StringVar(&host, "host", host, "grip server url") getCmd.Flags().StringVar(&host, "host", host, "grip server url") + viewCmd.Flags().StringVar(&host, "host", host, "grip server url") dropCmd.Flags().StringVar(&host, "host", host, "grip server url") + submitCmd.Flags().StringVar(&host, "host", host, "grip server url") + resumeCmd.Flags().StringVar(&host, "host", host, "grip server url") Cmd.AddCommand(listJobsCmd) Cmd.AddCommand(getCmd) + Cmd.AddCommand(viewCmd) Cmd.AddCommand(dropCmd) + Cmd.AddCommand(submitCmd) + Cmd.AddCommand(resumeCmd) } diff --git a/cmd/query/main.go b/cmd/query/main.go index f2474d7d..0dffd565 100644 --- a/cmd/query/main.go +++ b/cmd/query/main.go @@ -1,16 +1,13 @@ package query import ( - "encoding/json" "fmt" "github.com/bmeg/grip/gripql" gripqljs "github.com/bmeg/grip/gripql/javascript" _ "github.com/bmeg/grip/jsengine/goja" // import goja so it registers with the driver map _ "github.com/bmeg/grip/jsengine/otto" // import otto so it registers with the driver map - "github.com/bmeg/grip/jsengine/underscore" "github.com/bmeg/grip/util/rpc" - "github.com/dop251/goja" "github.com/spf13/cobra" "google.golang.org/protobuf/encoding/protojson" ) @@ -26,48 +23,20 @@ Example: grip query example-graph 'V().hasLabel("Variant").out().limit(5)'`, Args: cobra.ExactArgs(2), RunE: func(cmd *cobra.Command, args []string) error { - vm := goja.New() - - us, err := underscore.Asset("underscore.js") - if err != nil { - return fmt.Errorf("failed to load underscore.js") - } - if _, err := vm.RunString(string(us)); err != nil { - return err - } - - gripqlString, err := gripqljs.Asset("gripql.js") - if err != nil { - return fmt.Errorf("failed to load gripql.js") - } - if _, err := vm.RunString(string(gripqlString)); err != nil { - return err - } - + graph := args[0] queryString := args[1] - val, err := vm.RunString(queryString) - if err != nil { - return err - } - queryJSON, err := json.Marshal(val) + query, err := gripqljs.ParseQuery(queryString) if err != nil { return err } - - query := gripql.GraphQuery{} - err = protojson.Unmarshal(queryJSON, &query) - if err != nil { - return err - } - query.Graph = args[0] - + query.Graph = graph conn, err := gripql.Connect(rpc.ConfigWithDefaults(host), true) if err != nil { return err } - res, err := conn.Traversal(&query) + res, err := conn.Traversal(query) if err != nil { return err } diff --git a/conformance/tests/ot_has.py b/conformance/tests/ot_has.py index 1cde1628..0efbb969 100644 --- a/conformance/tests/ot_has.py +++ b/conformance/tests/ot_has.py @@ -314,7 +314,7 @@ def test_has_without(man): errors.append("Wrong vertex returned %s" % (i)) if count != 35: errors.append( - "Fail: G.query().V().has(gripql.without(\"occupation\", [\"jedi\", \"sith\"])) %s != %s" % + """Fail: V().has(gripql.without("eye_color", ["brown"])) %s != %s""" % (count, 35)) count = 0 diff --git a/engine/pipeline/pipes.go b/engine/pipeline/pipes.go index e965190e..b8104198 100644 --- a/engine/pipeline/pipes.go +++ b/engine/pipeline/pipes.go @@ -129,13 +129,15 @@ func Resume(ctx context.Context, pipe gdbi.Pipeline, workdir string, input gdbi. man := engine.NewManager(workdir) log.Debugf("resuming: out %s", dataType) rPipe := Start(ctx, pipe, man, bufsize, input, cancel) - for t := range rPipe.Outputs { - if !t.IsSignal() { - resch <- Convert(graph, dataType, markTypes, t) + if rPipe != nil { + for t := range rPipe.Outputs { + if !t.IsSignal() { + resch <- Convert(graph, dataType, markTypes, t) + } + } + if debug { + rPipe.Logger.Log() } - } - if debug { - rPipe.Logger.Log() } man.Cleanup() }() diff --git a/gripql/client.go b/gripql/client.go index 7fd6c880..5837d202 100644 --- a/gripql/client.go +++ b/gripql/client.go @@ -32,10 +32,13 @@ func Connect(conf rpc.Config, write bool) (Client, error) { } queryOut := NewQueryClient(conn) var editOut EditClient + var jobOut JobClient if write { editOut = NewEditClient(conn) + jobOut = NewJobClient(conn) + } - return Client{queryOut, editOut, nil, nil, conn}, nil + return Client{queryOut, editOut, jobOut, nil, conn}, nil } func (client Client) WithConfigureAPI() Client { @@ -259,11 +262,86 @@ func (client Client) GetJob(graph string, jobID string) (*JobStatus, error) { return client.JobC.GetJob(context.Background(), &QueryJob{Graph: graph, Id: jobID}) } -/* -func (client Client) ViewJob(in *QueryJob, opts ...grpc.CallOption) (Job_ViewJobClient, error) { +func (client Client) ResumeJob(graph string, jobID string, q *GraphQuery) (chan *QueryResult, error) { + tclient, err := client.JobC.ResumeJob(context.Background(), + &ExtendQuery{Graph: graph, + SrcId: jobID, + Query: q.Query, + }) + out := make(chan *QueryResult, 100) + + if err != nil { + return nil, err + } + + t, err := tclient.Recv() + if err == io.EOF { + close(out) + return out, nil + } + if err != nil { + close(out) + return out, err + } + out <- t + + go func() { + defer close(out) + for { + t, err := tclient.Recv() + if err == io.EOF { + return + } + if err != nil { + log.WithFields(log.Fields{"error": err}).Error("Receiving traversal result") + return + } + out <- t + } + }() + return out, nil +} + +func (client Client) ViewJob(graph string, jobID string, opts ...grpc.CallOption) (chan *QueryResult, error) { + tclient, err := client.JobC.ViewJob(context.Background(), + &QueryJob{Graph: graph, + Id: jobID, + }) + + out := make(chan *QueryResult, 100) + + if err != nil { + return nil, err + } + + t, err := tclient.Recv() + if err == io.EOF { + close(out) + return out, nil + } + if err != nil { + close(out) + return out, err + } + out <- t + + go func() { + defer close(out) + for { + t, err := tclient.Recv() + if err == io.EOF { + return + } + if err != nil { + log.WithFields(log.Fields{"error": err}).Error("Receiving traversal result") + return + } + out <- t + } + }() + return out, nil } -*/ // ListDrivers lists avalible drivers func (client Client) ListDrivers() (*ListDriversResponse, error) { diff --git a/gripql/javascript/gripql.js b/gripql/javascript/gripql.js index 800ffb5e..9d5bdaf7 100644 --- a/gripql/javascript/gripql.js +++ b/gripql/javascript/gripql.js @@ -9,6 +9,10 @@ function process(val) { return val } +function resume() { + return query() +} + function query() { return { query: [], diff --git a/gripql/javascript/parse.go b/gripql/javascript/parse.go new file mode 100644 index 00000000..09f81ef7 --- /dev/null +++ b/gripql/javascript/parse.go @@ -0,0 +1,47 @@ +package gripqljs + +import ( + "encoding/json" + "fmt" + + "github.com/bmeg/grip/gripql" + "github.com/bmeg/grip/jsengine/underscore" + "github.com/dop251/goja" + "google.golang.org/protobuf/encoding/protojson" +) + +func ParseQuery(queryString string) (*gripql.GraphQuery, error) { + vm := goja.New() + us, err := underscore.Asset("underscore.js") + if err != nil { + return nil, fmt.Errorf("failed to load underscore.js") + } + if _, err := vm.RunString(string(us)); err != nil { + return nil, err + } + gripqlString, err := Asset("gripql.js") + if err != nil { + return nil, fmt.Errorf("failed to load gripql.js") + } + if _, err := vm.RunString(string(gripqlString)); err != nil { + return nil, err + } + + val, err := vm.RunString(queryString) + if err != nil { + return nil, err + } + + queryJSON, err := json.Marshal(val) + if err != nil { + return nil, err + } + + query := gripql.GraphQuery{} + err = protojson.Unmarshal(queryJSON, &query) + if err != nil { + return nil, err + } + + return &query, nil +} diff --git a/mongo/graph.go b/mongo/graph.go index 1d32cb84..820dbc41 100644 --- a/mongo/graph.go +++ b/mongo/graph.go @@ -44,9 +44,9 @@ func (mg *Graph) GetTimestamp() string { // GetVertex loads a vertex given an id. It returns a nil if not found func (mg *Graph) GetVertex(id string, load bool) *gdbi.Vertex { opts := options.FindOne() - if !load { - opts.SetProjection(map[string]interface{}{FIELD_ID: 1, FIELD_LABEL: 1}) - } + //if !load { + // opts.SetProjection(map[string]interface{}{FIELD_ID: 1, FIELD_LABEL: 1}) + //} result := mg.ar.VertexCollection(mg.graph).FindOne(context.Background(), bson.M{FIELD_ID: id}, opts) if result.Err() != nil { return nil @@ -62,9 +62,9 @@ func (mg *Graph) GetVertex(id string, load bool) *gdbi.Vertex { // GetEdge loads an edge given an id. It returns nil if not found func (mg *Graph) GetEdge(id string, load bool) *gdbi.Edge { opts := options.FindOne() - if !load { - opts.SetProjection(map[string]interface{}{FIELD_ID: 1, FIELD_LABEL: 1, FIELD_FROM: 1, FIELD_TO: 1}) - } + //if !load { + // opts.SetProjection(map[string]interface{}{FIELD_ID: 1, FIELD_LABEL: 1, FIELD_FROM: 1, FIELD_TO: 1}) + //} result := mg.ar.EdgeCollection(mg.graph).FindOne(context.TODO(), bson.M{FIELD_ID: id}, opts) if result.Err() != nil { return nil @@ -165,21 +165,21 @@ func (mg *Graph) GetVertexList(ctx context.Context, load bool) <-chan *gdbi.Vert defer close(o) vCol := mg.ar.VertexCollection(mg.graph) opts := options.Find() - if !load { - opts.SetProjection(bson.M{FIELD_ID: 1, FIELD_LABEL: 1}) - } + //if !load { + // opts.SetProjection(bson.M{FIELD_ID: 1, FIELD_LABEL: 1}) + //} query, err := vCol.Find(ctx, bson.M{}, opts) if err != nil { return } defer query.Close(ctx) - result := map[string]interface{}{} for query.Next(ctx) { select { case <-ctx.Done(): return default: } + result := map[string]interface{}{} if err := query.Decode(&result); err == nil { v := UnpackVertex(result) o <- v @@ -200,21 +200,21 @@ func (mg *Graph) GetEdgeList(ctx context.Context, loadProp bool) <-chan *gdbi.Ed defer close(o) eCol := mg.ar.EdgeCollection(mg.graph) opts := options.Find() - if !loadProp { - opts.SetProjection(bson.M{FIELD_ID: 1, FIELD_TO: 1, FIELD_FROM: 1, FIELD_LABEL: 1}) - } + //if !loadProp { + // opts.SetProjection(bson.M{FIELD_ID: 1, FIELD_TO: 1, FIELD_FROM: 1, FIELD_LABEL: 1}) + //} query, err := eCol.Find(ctx, bson.M{}, opts) if err != nil { return } defer query.Close(ctx) - result := map[string]interface{}{} for query.Next(ctx) { select { case <-ctx.Done(): return default: } + result := map[string]interface{}{} if err := query.Decode(&result); err == nil { if _, ok := result[FIELD_TO]; ok { e := UnpackEdge(result) @@ -250,16 +250,16 @@ func (mg *Graph) GetVertexChannel(ctx context.Context, ids chan gdbi.ElementLook } query := bson.M{FIELD_ID: bson.M{"$in": idBatch}} opts := options.Find() - if !load { - opts.SetProjection(bson.M{FIELD_ID: 1, FIELD_LABEL: 1}) - } + //if !load { + // opts.SetProjection(bson.M{FIELD_ID: 1, FIELD_LABEL: 1}) + //} cursor, err := vCol.Find(context.TODO(), query, opts) if err != nil { return } chunk := map[string]*gdbi.Vertex{} - result := map[string]interface{}{} for cursor.Next(context.TODO()) { + result := map[string]interface{}{} if err := cursor.Decode(&result); err == nil { v := UnpackVertex(result) chunk[v.ID] = v @@ -312,18 +312,18 @@ func (mg *Graph) GetOutChannel(ctx context.Context, reqChan chan gdbi.ElementLoo vertCol := fmt.Sprintf("%s_vertices", mg.graph) query = append(query, bson.M{"$lookup": bson.M{"from": vertCol, "localField": FIELD_TO, "foreignField": FIELD_ID, "as": "dst"}}) query = append(query, bson.M{"$unwind": "$dst"}) - if load { - //query = append(query, bson.M{"$project": bson.M{FIELD_FROM: true, "dst._id": true, "dst._label": true, "dst.data": true}}) - query = append(query, bson.M{"$project": bson.M{FIELD_FROM: true, "dst": true}}) - } else { - query = append(query, bson.M{"$project": bson.M{FIELD_FROM: true, "dst._id": true, "dst._label": true}}) - } + //if load { + //query = append(query, bson.M{"$project": bson.M{FIELD_FROM: true, "dst._id": true, "dst._label": true, "dst.data": true}}) + query = append(query, bson.M{"$project": bson.M{FIELD_FROM: true, "dst": true}}) + //} else { + // query = append(query, bson.M{"$project": bson.M{FIELD_FROM: true, "dst._id": true, "dst._label": true}}) + //} eCol := mg.ar.EdgeCollection(mg.graph) cursor, err := eCol.Aggregate(context.TODO(), query) if err == nil { - result := map[string]interface{}{} for cursor.Next(context.TODO()) { + result := map[string]interface{}{} if err := cursor.Decode(&result); err == nil { if dst, ok := result["dst"].(map[string]interface{}); ok { v := UnpackVertex(dst) @@ -392,18 +392,18 @@ func (mg *Graph) GetInChannel(ctx context.Context, reqChan chan gdbi.ElementLook vertCol := fmt.Sprintf("%s_vertices", mg.graph) query = append(query, bson.M{"$lookup": bson.M{"from": vertCol, "localField": FIELD_FROM, "foreignField": FIELD_ID, "as": "src"}}) query = append(query, bson.M{"$unwind": "$src"}) - if load { - //query = append(query, bson.M{"$project": bson.M{FIELD_TO: true, "src._id": true, "src._label": true, "src.data": true}}) //FIX: .data no longer used - query = append(query, bson.M{"$project": bson.M{FIELD_TO: true, "src": true}}) - } else { - query = append(query, bson.M{"$project": bson.M{FIELD_TO: true, "src._id": true, "src._label": true}}) - } + //if load { + //query = append(query, bson.M{"$project": bson.M{FIELD_TO: true, "src._id": true, "src._label": true, "src.data": true}}) //FIX: .data no longer used + query = append(query, bson.M{"$project": bson.M{FIELD_TO: true, "src": true}}) + //} else { + // query = append(query, bson.M{"$project": bson.M{FIELD_TO: true, "src._id": true, "src._label": true}}) + //} eCol := mg.ar.EdgeCollection(mg.graph) cursor, err := eCol.Aggregate(context.TODO(), query) if err == nil { - result := map[string]interface{}{} for cursor.Next(context.TODO()) { + result := map[string]interface{}{} if err := cursor.Decode(&result); err == nil { if src, ok := result["src"].(map[string]interface{}); ok { v := UnpackVertex(src) @@ -472,8 +472,8 @@ func (mg *Graph) GetOutEdgeChannel(ctx context.Context, reqChan chan gdbi.Elemen eCol := mg.ar.EdgeCollection(mg.graph) cursor, err := eCol.Aggregate(context.TODO(), query) if err == nil { - result := map[string]interface{}{} for cursor.Next(context.TODO()) { + result := map[string]interface{}{} if err := cursor.Decode(&result); err == nil { e := UnpackEdge(result) fromID := result[FIELD_FROM].(string) @@ -539,8 +539,8 @@ func (mg *Graph) GetInEdgeChannel(ctx context.Context, reqChan chan gdbi.Element eCol := mg.ar.EdgeCollection(mg.graph) cursor, err := eCol.Aggregate(context.TODO(), query) if err == nil { - result := map[string]interface{}{} for cursor.Next(context.TODO()) { + result := map[string]interface{}{} if err := cursor.Decode(&result); err == nil { e := UnpackEdge(result) toID := result[FIELD_TO].(string) From 166f1f7caca1b5a58a95e395f6e6365121847e35 Mon Sep 17 00:00:00 2001 From: Kyle Ellrott Date: Mon, 19 Feb 2024 10:45:49 -0800 Subject: [PATCH 23/23] Fixing compiler options so job system can override data loading optimizations --- engine/core/compile.go | 15 ++++++++--- gdbi/pipeline.go | 9 +++++-- gdbi/state.go | 4 +-- gripql/inspect/inspect.go | 18 +++++++++++++- mongo/compile.go | 2 +- mongo/graph.go | 52 +++++++++++++++++++-------------------- server/job_manager.go | 6 +++-- test/inspect_test.go | 28 +++++++++++---------- 8 files changed, 82 insertions(+), 52 deletions(-) diff --git a/engine/core/compile.go b/engine/core/compile.go index 54bf1204..810fe1c7 100644 --- a/engine/core/compile.go +++ b/engine/core/compile.go @@ -66,10 +66,17 @@ func (comp DefaultCompiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.C stmts = o(stmts) } - ps := gdbi.NewPipelineState(stmts) + storeMarks := false if opts != nil { - ps.LastType = opts.PipelineExtension - ps.MarkTypes = opts.ExtensionMarkTypes + storeMarks = opts.StoreMarks + } + + ps := gdbi.NewPipelineState(stmts, storeMarks) + if opts != nil { + if opts.Extends != nil { + ps.LastType = opts.Extends.StartType + ps.MarkTypes = opts.Extends.MarksTypes + } } procs := make([]gdbi.Processor, 0, len(stmts)) @@ -96,7 +103,7 @@ func Validate(stmts []*gripql.GraphStatement, opts *gdbi.CompileOptions) error { switch gs.GetStatement().(type) { case *gripql.GraphStatement_V, *gripql.GraphStatement_E: default: - if opts == nil || opts.PipelineExtension == gdbi.NoData { + if opts == nil || opts.Extends.StartType == gdbi.NoData { return fmt.Errorf("first statement is not V() or E(): %s", gs) } } diff --git a/gdbi/pipeline.go b/gdbi/pipeline.go index 6ca0c7f7..7a29bbe5 100644 --- a/gdbi/pipeline.go +++ b/gdbi/pipeline.go @@ -16,10 +16,15 @@ type CustomProcGen interface { GetProcessor(db GraphInterface, ps PipelineState) (Processor, error) } +type PipelineExtension struct { + StartType DataType + MarksTypes map[string]DataType +} + type CompileOptions struct { //Compile pipeline extension - PipelineExtension DataType - ExtensionMarkTypes map[string]DataType + Extends *PipelineExtension + StoreMarks bool } // Compiler takes a gripql query and turns it into an executable pipeline diff --git a/gdbi/state.go b/gdbi/state.go index e485595e..c8824ff7 100644 --- a/gdbi/state.go +++ b/gdbi/state.go @@ -36,9 +36,9 @@ func (ps *State) SetLastType(a DataType) { ps.LastType = a } -func NewPipelineState(stmts []*gripql.GraphStatement) *State { +func NewPipelineState(stmts []*gripql.GraphStatement, storeMarks bool) *State { steps := inspect.PipelineSteps(stmts) - stepOut := inspect.PipelineStepOutputs(stmts) + stepOut := inspect.PipelineStepOutputs(stmts, storeMarks) return &State{ LastType: NoData, diff --git a/gripql/inspect/inspect.go b/gripql/inspect/inspect.go index a2212a30..bc487ea8 100644 --- a/gripql/inspect/inspect.go +++ b/gripql/inspect/inspect.go @@ -78,18 +78,23 @@ func PipelineAsSteps(stmts []*gripql.GraphStatement) map[string]string { } // PipelineStepOutputs identify the required outputs for each step in the traversal -func PipelineStepOutputs(stmts []*gripql.GraphStatement) map[string][]string { +func PipelineStepOutputs(stmts []*gripql.GraphStatement, storeMarks bool) map[string][]string { + // mapping of what steps of the traversal as used at each stage of the pipeline steps := PipelineSteps(stmts) + asMap := PipelineAsSteps(stmts) + // we're inpecting the pipeline backwards, the last step is emitted onLast := true out := map[string][]string{} for i := len(stmts) - 1; i >= 0; i-- { gs := stmts[i] switch gs.GetStatement().(type) { case *gripql.GraphStatement_Count: + //if the pipeline ends with counting, we don't need to load data onLast = false case *gripql.GraphStatement_Select: + //if the last step is jumping back to a previous mark if onLast { sel := gs.GetSelect() if a, ok := asMap[sel]; ok { @@ -99,6 +104,7 @@ func PipelineStepOutputs(stmts []*gripql.GraphStatement) map[string][]string { } case *gripql.GraphStatement_Render: + // determine every step output that is needed for the render val := gs.GetRender().AsInterface() names := tpath.GetAllNamespaces(val) for _, n := range names { @@ -147,12 +153,21 @@ func PipelineStepOutputs(stmts []*gripql.GraphStatement) map[string][]string { out[steps[i]] = []string{"*"} } } + //if the job is a fragment, the elements marked with as_, they may be needed + //in followup runs + if storeMarks { + for _, v := range asMap { + out[v] = []string{"*"} + } + } return out } +// DEPRECATED : Was used for older version of GRIDS engine // PipelineNoLoadPath identifies 'paths' which are groups of statements that move // travelers across multiple steps, and don't require data (other then the label) // to be loaded +/* func PipelineNoLoadPath(stmts []*gripql.GraphStatement, minLen int) [][]int { out := [][]int{} @@ -183,3 +198,4 @@ func PipelineNoLoadPath(stmts []*gripql.GraphStatement, minLen int) [][]int { } return out } +*/ diff --git a/mongo/compile.go b/mongo/compile.go index fc968a0e..2eb21351 100644 --- a/mongo/compile.go +++ b/mongo/compile.go @@ -76,7 +76,7 @@ func (comp *Compiler) Compile(stmts []*gripql.GraphStatement, opts *gdbi.Compile //in the case of a pipeline extension, switch over the the //core based engine. Until the mongo aggregation pipeline engine //is updated to support - if opts != nil && opts.PipelineExtension != gdbi.NoData { + if opts != nil && opts.Extends != nil { cmpl := core.NewCompiler(comp.db) return cmpl.Compile(stmts, opts) } diff --git a/mongo/graph.go b/mongo/graph.go index 820dbc41..a9917850 100644 --- a/mongo/graph.go +++ b/mongo/graph.go @@ -44,9 +44,9 @@ func (mg *Graph) GetTimestamp() string { // GetVertex loads a vertex given an id. It returns a nil if not found func (mg *Graph) GetVertex(id string, load bool) *gdbi.Vertex { opts := options.FindOne() - //if !load { - // opts.SetProjection(map[string]interface{}{FIELD_ID: 1, FIELD_LABEL: 1}) - //} + if !load { + opts.SetProjection(map[string]interface{}{FIELD_ID: 1, FIELD_LABEL: 1}) + } result := mg.ar.VertexCollection(mg.graph).FindOne(context.Background(), bson.M{FIELD_ID: id}, opts) if result.Err() != nil { return nil @@ -62,9 +62,9 @@ func (mg *Graph) GetVertex(id string, load bool) *gdbi.Vertex { // GetEdge loads an edge given an id. It returns nil if not found func (mg *Graph) GetEdge(id string, load bool) *gdbi.Edge { opts := options.FindOne() - //if !load { - // opts.SetProjection(map[string]interface{}{FIELD_ID: 1, FIELD_LABEL: 1, FIELD_FROM: 1, FIELD_TO: 1}) - //} + if !load { + opts.SetProjection(map[string]interface{}{FIELD_ID: 1, FIELD_LABEL: 1, FIELD_FROM: 1, FIELD_TO: 1}) + } result := mg.ar.EdgeCollection(mg.graph).FindOne(context.TODO(), bson.M{FIELD_ID: id}, opts) if result.Err() != nil { return nil @@ -165,9 +165,9 @@ func (mg *Graph) GetVertexList(ctx context.Context, load bool) <-chan *gdbi.Vert defer close(o) vCol := mg.ar.VertexCollection(mg.graph) opts := options.Find() - //if !load { - // opts.SetProjection(bson.M{FIELD_ID: 1, FIELD_LABEL: 1}) - //} + if !load { + opts.SetProjection(bson.M{FIELD_ID: 1, FIELD_LABEL: 1}) + } query, err := vCol.Find(ctx, bson.M{}, opts) if err != nil { return @@ -200,9 +200,9 @@ func (mg *Graph) GetEdgeList(ctx context.Context, loadProp bool) <-chan *gdbi.Ed defer close(o) eCol := mg.ar.EdgeCollection(mg.graph) opts := options.Find() - //if !loadProp { - // opts.SetProjection(bson.M{FIELD_ID: 1, FIELD_TO: 1, FIELD_FROM: 1, FIELD_LABEL: 1}) - //} + if !loadProp { + opts.SetProjection(bson.M{FIELD_ID: 1, FIELD_TO: 1, FIELD_FROM: 1, FIELD_LABEL: 1}) + } query, err := eCol.Find(ctx, bson.M{}, opts) if err != nil { return @@ -250,9 +250,9 @@ func (mg *Graph) GetVertexChannel(ctx context.Context, ids chan gdbi.ElementLook } query := bson.M{FIELD_ID: bson.M{"$in": idBatch}} opts := options.Find() - //if !load { - // opts.SetProjection(bson.M{FIELD_ID: 1, FIELD_LABEL: 1}) - //} + if !load { + opts.SetProjection(bson.M{FIELD_ID: 1, FIELD_LABEL: 1}) + } cursor, err := vCol.Find(context.TODO(), query, opts) if err != nil { return @@ -312,12 +312,11 @@ func (mg *Graph) GetOutChannel(ctx context.Context, reqChan chan gdbi.ElementLoo vertCol := fmt.Sprintf("%s_vertices", mg.graph) query = append(query, bson.M{"$lookup": bson.M{"from": vertCol, "localField": FIELD_TO, "foreignField": FIELD_ID, "as": "dst"}}) query = append(query, bson.M{"$unwind": "$dst"}) - //if load { - //query = append(query, bson.M{"$project": bson.M{FIELD_FROM: true, "dst._id": true, "dst._label": true, "dst.data": true}}) - query = append(query, bson.M{"$project": bson.M{FIELD_FROM: true, "dst": true}}) - //} else { - // query = append(query, bson.M{"$project": bson.M{FIELD_FROM: true, "dst._id": true, "dst._label": true}}) - //} + if load { + query = append(query, bson.M{"$project": bson.M{FIELD_FROM: true, "dst": true}}) + } else { + query = append(query, bson.M{"$project": bson.M{FIELD_FROM: true, "dst._id": true, "dst._label": true}}) + } eCol := mg.ar.EdgeCollection(mg.graph) cursor, err := eCol.Aggregate(context.TODO(), query) @@ -392,12 +391,11 @@ func (mg *Graph) GetInChannel(ctx context.Context, reqChan chan gdbi.ElementLook vertCol := fmt.Sprintf("%s_vertices", mg.graph) query = append(query, bson.M{"$lookup": bson.M{"from": vertCol, "localField": FIELD_FROM, "foreignField": FIELD_ID, "as": "src"}}) query = append(query, bson.M{"$unwind": "$src"}) - //if load { - //query = append(query, bson.M{"$project": bson.M{FIELD_TO: true, "src._id": true, "src._label": true, "src.data": true}}) //FIX: .data no longer used - query = append(query, bson.M{"$project": bson.M{FIELD_TO: true, "src": true}}) - //} else { - // query = append(query, bson.M{"$project": bson.M{FIELD_TO: true, "src._id": true, "src._label": true}}) - //} + if load { + query = append(query, bson.M{"$project": bson.M{FIELD_TO: true, "src": true}}) + } else { + query = append(query, bson.M{"$project": bson.M{FIELD_TO: true, "src._id": true, "src._label": true}}) + } eCol := mg.ar.EdgeCollection(mg.graph) cursor, err := eCol.Aggregate(context.TODO(), query) diff --git a/server/job_manager.go b/server/job_manager.go index 1e80cadc..a2339c50 100644 --- a/server/job_manager.go +++ b/server/job_manager.go @@ -22,7 +22,7 @@ func (server *GripServer) Submit(ctx context.Context, query *gripql.GraphQuery) return nil, err } compiler := graph.Compiler() - pipe, err := compiler.Compile(query.Query, nil) + pipe, err := compiler.Compile(query.Query, &gdbi.CompileOptions{StoreMarks: true}) if err != nil { return nil, err } @@ -126,7 +126,9 @@ func (server *GripServer) ResumeJob(query *gripql.ExtendQuery, srv gripql.Job_Re } compiler := graph.Compiler() log.Debugf("Compiling resume pipeline: %s -> %s", stream.DataType, query.String()) - pipe, err := compiler.Compile(query.Query, &gdbi.CompileOptions{PipelineExtension: stream.DataType, ExtensionMarkTypes: stream.MarkTypes}) + pipe, err := compiler.Compile(query.Query, + &gdbi.CompileOptions{Extends: &gdbi.PipelineExtension{StartType: stream.DataType, MarksTypes: stream.MarkTypes}}, + ) if err != nil { log.Debugf("User query compile error: %s", err) cancel() diff --git a/test/inspect_test.go b/test/inspect_test.go index bd7d2bfd..7ac9fbba 100644 --- a/test/inspect_test.go +++ b/test/inspect_test.go @@ -36,7 +36,7 @@ func TestAsMapping(t *testing.T) { func TestOutputMasking(t *testing.T) { q := gripql.NewQuery() q = q.V().Out().In().Has(gripql.Eq("$.test", "value")) - out := inspect.PipelineStepOutputs(q.Statements) + out := inspect.PipelineStepOutputs(q.Statements, false) fmt.Printf("vars: %s\n", out) if len(out) != 1 { t.Errorf("Wrong number of step outputs %d", len(out)) @@ -47,7 +47,7 @@ func TestOutputMasking(t *testing.T) { q = gripql.NewQuery() q = q.V().Out().In().Has(gripql.Eq("$.test", "value")).Out() - out = inspect.PipelineStepOutputs(q.Statements) + out = inspect.PipelineStepOutputs(q.Statements, false) fmt.Printf("vars: %s\n", out) if len(out) != 2 { t.Errorf("Wrong number of step outputs %d", len(out)) @@ -61,7 +61,7 @@ func TestOutputMasking(t *testing.T) { q = gripql.NewQuery() q = q.E() - out = inspect.PipelineStepOutputs(q.Statements) + out = inspect.PipelineStepOutputs(q.Statements, false) fmt.Printf("EdgeList vars: %s\n", out) if len(out) != 1 { t.Errorf("Wrong number of step outputs %d", len(out)) @@ -69,7 +69,7 @@ func TestOutputMasking(t *testing.T) { q = gripql.NewQuery() q = q.V().Out().In().Count() - out = inspect.PipelineStepOutputs(q.Statements) + out = inspect.PipelineStepOutputs(q.Statements, false) fmt.Printf("vars: %s\n", out) if len(out) != 0 { t.Errorf("Incorrect output count") @@ -77,7 +77,7 @@ func TestOutputMasking(t *testing.T) { q = gripql.NewQuery() q = q.V().Out().In().Has(gripql.Eq("$.test", "value")).Count() - out = inspect.PipelineStepOutputs(q.Statements) + out = inspect.PipelineStepOutputs(q.Statements, false) fmt.Printf("vars: %s\n", out) if len(out) != 1 { t.Errorf("Incorrect output count") @@ -85,7 +85,7 @@ func TestOutputMasking(t *testing.T) { q = gripql.NewQuery() q = q.V().HasLabel("test").Out().In().Has(gripql.Eq("$.test", "value")).Count() - out = inspect.PipelineStepOutputs(q.Statements) + out = inspect.PipelineStepOutputs(q.Statements, false) if len(out) != 2 { t.Errorf("Wrong number of step outputs %d", len(out)) } @@ -93,17 +93,17 @@ func TestOutputMasking(t *testing.T) { q = gripql.NewQuery() q = q.V().HasLabel("test").Out().As("a").Out().Out().Select("a") - out = inspect.PipelineStepOutputs(q.Statements) + out = inspect.PipelineStepOutputs(q.Statements, false) fmt.Printf("vars: %s\n", out) q = gripql.NewQuery() q = q.V().HasLabel("robot", "person") - out = inspect.PipelineStepOutputs(q.Statements) + out = inspect.PipelineStepOutputs(q.Statements, false) fmt.Printf("vars: %s\n", out) q = gripql.NewQuery() q = q.V().HasLabel("Person").As("person").Out().Distinct("$person.name") - out = inspect.PipelineStepOutputs(q.Statements) + out = inspect.PipelineStepOutputs(q.Statements, false) fmt.Printf("vars: %s -> %s\n", inspect.PipelineSteps(q.Statements), out) if len(out) != 2 { t.Errorf("Incorrect output count") @@ -123,7 +123,7 @@ func TestOutputIndexMasking(t *testing.T) { q = q.V().HasLabel("robot", "person") smts := core.IndexStartOptimize(q.Statements) - out := inspect.PipelineStepOutputs(smts) + out := inspect.PipelineStepOutputs(smts, false) fmt.Printf("%#v\n", smts) if len(out) == 0 { t.Errorf("No outputs found") @@ -131,6 +131,7 @@ func TestOutputIndexMasking(t *testing.T) { fmt.Printf("vars: %s\n", out) } +/* func TestPathFind(t *testing.T) { q := gripql.NewQuery() o := q.V().HasLabel("test").Out().As("a").Out().Out().Select("a") @@ -156,11 +157,12 @@ func TestPathFind(t *testing.T) { } } } +*/ func TestDistinct(t *testing.T) { q := gripql.NewQuery() o := q.V().HasLabel("Person").As("person").Out("friend").Distinct("$person.name", "$.name").Count() - out := inspect.PipelineStepOutputs(o.Statements) + out := inspect.PipelineStepOutputs(o.Statements, false) fmt.Printf("%#v\n", out) if x, ok := out["2"]; ok { @@ -172,7 +174,7 @@ func TestDistinct(t *testing.T) { } o = q.V().HasLabel("Person").As("person").Out("friend").Distinct("$.name").Count() - out = inspect.PipelineStepOutputs(o.Statements) + out = inspect.PipelineStepOutputs(o.Statements, false) fmt.Printf("%#v\n", out) if x, ok := out["2"]; ok { if !setcmp.ContainsString(x, "*") { @@ -183,7 +185,7 @@ func TestDistinct(t *testing.T) { } o = q.V().HasLabel("Person").As("person").Out("friend").Distinct("$person.name").Out("friend").Distinct("$.name").Count() - out = inspect.PipelineStepOutputs(o.Statements) + out = inspect.PipelineStepOutputs(o.Statements, false) fmt.Printf("%#v\n", out) if x, ok := out["3"]; ok { if !setcmp.ContainsString(x, "*") {