From c9eb5c8039eab5ecfbcd714e73b32d20de11e6e4 Mon Sep 17 00:00:00 2001 From: Pawan Rawal <pawan0201@gmail.com> Date: Wed, 13 Apr 2016 07:51:03 +0530 Subject: [PATCH] Added support for marshalling subgraph to protocol buffers 1. Added subgraph.proto file which has the message structure. 2. Added ToProtocolBuffer method which converts a subgraph to protocol buffer. --- query/protocolbuffer/subgraph.pb.go | 104 ++++++++++++++++++++++++++++ query/protocolbuffer/subgraph.proto | 17 +++++ query/query.go | 66 ++++++++++++++++++ query/query_test.go | 78 +++++++++++++++++++++ 4 files changed, 265 insertions(+) create mode 100644 query/protocolbuffer/subgraph.pb.go create mode 100644 query/protocolbuffer/subgraph.proto diff --git a/query/protocolbuffer/subgraph.pb.go b/query/protocolbuffer/subgraph.pb.go new file mode 100644 index 00000000..56032779 --- /dev/null +++ b/query/protocolbuffer/subgraph.pb.go @@ -0,0 +1,104 @@ +// Code generated by protoc-gen-go. +// source: subgraph.proto +// DO NOT EDIT! + +/* +Package protocolbuffer is a generated protocol buffer package. + +It is generated from these files: + subgraph.proto + +It has these top-level messages: + UidList + Result + SubGraph +*/ +package protocolbuffer + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +const _ = proto.ProtoPackageIsVersion1 + +type UidList struct { + Uids []uint64 `protobuf:"fixed64,1,rep,packed,name=uids" json:"uids,omitempty"` +} + +func (m *UidList) Reset() { *m = UidList{} } +func (m *UidList) String() string { return proto.CompactTextString(m) } +func (*UidList) ProtoMessage() {} +func (*UidList) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +type Result struct { + Values [][]byte `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` + Uidmatrix []*UidList `protobuf:"bytes,2,rep,name=uidmatrix" json:"uidmatrix,omitempty"` +} + +func (m *Result) Reset() { *m = Result{} } +func (m *Result) String() string { return proto.CompactTextString(m) } +func (*Result) ProtoMessage() {} +func (*Result) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +func (m *Result) GetUidmatrix() []*UidList { + if m != nil { + return m.Uidmatrix + } + return nil +} + +type SubGraph struct { + Attr string `protobuf:"bytes,1,opt,name=attr" json:"attr,omitempty"` + Children []*SubGraph `protobuf:"bytes,2,rep,name=children" json:"children,omitempty"` + Result *Result `protobuf:"bytes,3,opt,name=result" json:"result,omitempty"` +} + +func (m *SubGraph) Reset() { *m = SubGraph{} } +func (m *SubGraph) String() string { return proto.CompactTextString(m) } +func (*SubGraph) ProtoMessage() {} +func (*SubGraph) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +func (m *SubGraph) GetChildren() []*SubGraph { + if m != nil { + return m.Children + } + return nil +} + +func (m *SubGraph) GetResult() *Result { + if m != nil { + return m.Result + } + return nil +} + +func init() { + proto.RegisterType((*UidList)(nil), "protocolbuffer.UidList") + proto.RegisterType((*Result)(nil), "protocolbuffer.Result") + proto.RegisterType((*SubGraph)(nil), "protocolbuffer.SubGraph") +} + +var fileDescriptor0 = []byte{ + // 212 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x2b, 0x2e, 0x4d, 0x4a, + 0x2f, 0x4a, 0x2c, 0xc8, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x03, 0x53, 0xc9, 0xf9, + 0x39, 0x49, 0xa5, 0x69, 0x69, 0xa9, 0x45, 0x4a, 0x8a, 0x5c, 0xec, 0xa1, 0x99, 0x29, 0x3e, 0x99, + 0xc5, 0x25, 0x42, 0x62, 0x5c, 0x2c, 0xa5, 0x99, 0x29, 0xc5, 0x12, 0x8c, 0x0a, 0xcc, 0x1a, 0x6c, + 0x4e, 0x4c, 0x02, 0x8c, 0x41, 0x60, 0xbe, 0x52, 0x38, 0x17, 0x5b, 0x50, 0x6a, 0x71, 0x69, 0x0e, + 0x48, 0x05, 0x5b, 0x59, 0x62, 0x4e, 0x69, 0x2a, 0x44, 0x0d, 0x4f, 0x10, 0x94, 0x27, 0x64, 0xca, + 0xc5, 0x09, 0x54, 0x99, 0x9b, 0x58, 0x52, 0x94, 0x59, 0x21, 0xc1, 0x04, 0x94, 0xe2, 0x36, 0x12, + 0xd7, 0x43, 0xb5, 0x48, 0x0f, 0x6a, 0x4b, 0x10, 0x42, 0xa5, 0x52, 0x0b, 0x23, 0x17, 0x47, 0x70, + 0x69, 0x92, 0x3b, 0xc8, 0x79, 0x42, 0x42, 0x5c, 0x2c, 0x89, 0x25, 0x25, 0x45, 0x40, 0x93, 0x19, + 0x35, 0x38, 0x83, 0xc0, 0x6c, 0x21, 0x13, 0x2e, 0x8e, 0xe4, 0x8c, 0xcc, 0x9c, 0x94, 0xa2, 0xd4, + 0x3c, 0xa8, 0xb1, 0x12, 0xe8, 0xc6, 0xc2, 0xf4, 0x07, 0xc1, 0x55, 0x0a, 0xe9, 0x71, 0xb1, 0x15, + 0x81, 0xdd, 0x2b, 0xc1, 0x0c, 0x34, 0x8b, 0xdb, 0x48, 0x0c, 0x5d, 0x0f, 0xc4, 0x37, 0x41, 0x50, + 0x55, 0x49, 0x6c, 0x60, 0x69, 0x63, 0x40, 0x00, 0x00, 0x00, 0xff, 0xff, 0xfd, 0x1f, 0xc8, 0xb1, + 0x2b, 0x01, 0x00, 0x00, +} diff --git a/query/protocolbuffer/subgraph.proto b/query/protocolbuffer/subgraph.proto new file mode 100644 index 00000000..d5b713b2 --- /dev/null +++ b/query/protocolbuffer/subgraph.proto @@ -0,0 +1,17 @@ +syntax="proto3"; +package protocolbuffer; + +message UidList { + repeated fixed64 uids = 1 [packed=true];; +} + +message Result { + repeated bytes values = 1; + repeated UidList uidmatrix = 2; +} + +message SubGraph { + string attr = 1; + repeated SubGraph children = 2; //Each node can have multiple children + Result result = 3; +} \ No newline at end of file diff --git a/query/query.go b/query/query.go index 67a9ec4c..d8e99f51 100644 --- a/query/query.go +++ b/query/query.go @@ -26,9 +26,11 @@ import ( "github.com/Sirupsen/logrus" "github.com/dgraph-io/dgraph/gql" "github.com/dgraph-io/dgraph/posting" + "github.com/dgraph-io/dgraph/query/protocolbuffer" "github.com/dgraph-io/dgraph/task" "github.com/dgraph-io/dgraph/worker" "github.com/dgraph-io/dgraph/x" + "github.com/golang/protobuf/proto" "github.com/google/flatbuffers/go" ) @@ -251,6 +253,70 @@ func (g *SubGraph) ToJson(l *Latency) (js []byte, rerr error) { return json.Marshal(r) } +func preTraverse(g *SubGraph) (sg *protocolbuffer.SubGraph, rerr error) { + sg = &protocolbuffer.SubGraph{} + sg.Attr = g.Attr + + ro := flatbuffers.GetUOffsetT(g.result) + r := new(task.Result) + r.Init(g.result, ro) + + var ul task.UidList + result := &protocolbuffer.Result{} + for i := 0; i < r.UidmatrixLength(); i++ { + if ok := r.Uidmatrix(&ul, i); !ok { + return sg, fmt.Errorf("While parsing UidList") + } + uidList := &protocolbuffer.UidList{} + for j := 0; j < ul.UidsLength(); j++ { + uid := ul.Uids(j) + uidList.Uids = append(uidList.Uids, uid) + } + result.Uidmatrix = append(result.Uidmatrix, uidList) + } + + var tv task.Value + for i := 0; i < r.ValuesLength(); i++ { + if ok := r.Values(&tv, i); !ok { + return sg, fmt.Errorf("While parsing value") + } + var ival interface{} + if err := posting.ParseValue(&ival, tv.ValBytes()); err != nil { + return sg, err + } + if ival == nil { + continue + } + result.Values = append(result.Values, []byte(ival.(string))) + } + + sg.Result = result + + for _, child := range g.Children { + childSg, err := preTraverse(child) + if err != nil { + x.Err(glog, err).Error("Error while traversal") + return sg, err + } + sg.Children = append(sg.Children, childSg) + } + return sg, nil +} + +func (g *SubGraph) ToProtocolBuffer() (pb []byte, rerr error) { + sg, err := preTraverse(g) + if err != nil { + x.Err(glog, err).Error("Error while traversal") + return pb, err + } + pb, err = proto.Marshal(sg) + if err != nil { + x.Err(glog, err).Error("Error while marshalling to protocol buffer") + return pb, err + } + return pb, nil +} + func treeCopy(gq *gql.GraphQuery, sg *SubGraph) { for _, gchild := range gq.Children { dst := new(SubGraph) diff --git a/query/query_test.go b/query/query_test.go index 1f3da1ae..ed68c251 100644 --- a/query/query_test.go +++ b/query/query_test.go @@ -26,10 +26,12 @@ import ( "github.com/dgraph-io/dgraph/commit" "github.com/dgraph-io/dgraph/gql" "github.com/dgraph-io/dgraph/posting" + "github.com/dgraph-io/dgraph/query/protocolbuffer" "github.com/dgraph-io/dgraph/store" "github.com/dgraph-io/dgraph/task" "github.com/dgraph-io/dgraph/worker" "github.com/dgraph-io/dgraph/x" + "github.com/golang/protobuf/proto" "github.com/google/flatbuffers/go" ) @@ -319,3 +321,79 @@ func TestToJson(t *testing.T) { } fmt.Printf(string(js)) } + +func TestToProtocolBuffer(t *testing.T) { + dir, _ := populateGraph(t) + defer os.RemoveAll(dir) + + query := ` + { + me(_uid_:0x01) { + name + gender + status + friend { + name + } + } + } + ` + + gq, _, err := gql.Parse(query) + if err != nil { + t.Error(err) + } + sg, err := ToSubGraph(gq) + if err != nil { + t.Error(err) + } + + ch := make(chan error) + go ProcessGraph(sg, ch) + err = <-ch + if err != nil { + t.Error(err) + } + + pb, err := sg.ToProtocolBuffer() + if err != nil { + t.Error(err) + } + + // Unmarshalling to a protocol buffer subgraph for testing + usg := &protocolbuffer.SubGraph{} + err = proto.Unmarshal(pb, usg) + if err != nil { + t.Error(err) + } + + if len(usg.Children) != 4 { + t.Errorf("Expected len 4. Got: %v", usg.Children) + } + child := usg.Children[0] + if child.Attr != "name" { + t.Errorf("Expected attr name. Got: %v", child.Attr) + } + if string(child.Result.Values[0]) != "Michonne" { + t.Errorf("Expected value Michonne. Got %v", string(child.Result.Values[0])) + } + child = usg.Children[3] + if child.Attr != "friend" { + t.Errorf("Expected attr friend. Got: %v", child.Attr) + } + uids := child.Result.Uidmatrix[0].Uids + if uids[0] != 23 || uids[1] != 24 || uids[2] != 25 || uids[3] != 31 || uids[4] != 101 { + t.Errorf("Friend ids don't match") + } + // To check for name of friends + child = child.Children[0] + if child.Attr != "name" { + t.Errorf("Expected attr friend. Got: %v", child.Attr) + } + + names := child.Result.Values + + if string(names[0]) != "Rick Grimes" || string(names[1]) != "Glenn Rhee" || string(names[2]) != "Daryl Dixon" || string(names[3]) != "Andrea" { + t.Errorf("Names don't match") + } +} -- GitLab