Skip to content
Snippets Groups Projects
Commit 7d6cb52d authored by Manish R Jain's avatar Manish R Jain
Browse files

Remove gql module's dependency on query. Make it the other way round. GraphQL...

Remove gql module's dependency on query. Make it the other way round. GraphQL query string, now gets converted into query.SubGraph as an additional step run via query.ToSubGraph.
parent 1b7bf16c
No related branches found
No related tags found
No related merge requests found
......@@ -22,12 +22,20 @@ import (
"strconv"
"github.com/dgraph-io/dgraph/lex"
"github.com/dgraph-io/dgraph/query"
"github.com/dgraph-io/dgraph/x"
)
var glog = x.Log("gql")
// GraphQuery stores the parsed Query in a tree format. This gets
// converted to internally used query.SubGraph before processing the query.
type GraphQuery struct {
UID uint64
XID string
Attr string
Children []*GraphQuery
}
func run(l *lex.Lexer) {
for state := lexText; state != nil; {
state = state(l)
......@@ -35,11 +43,11 @@ func run(l *lex.Lexer) {
close(l.Items) // No more tokens.
}
func Parse(input string) (sg *query.SubGraph, rerr error) {
func Parse(input string) (gq *GraphQuery, rerr error) {
l := lex.NewLexer(input)
go run(l)
sg = nil
gq = nil
for item := range l.Items {
if item.Typ == itemText {
continue
......@@ -50,23 +58,23 @@ func Parse(input string) (sg *query.SubGraph, rerr error) {
}
}
if item.Typ == itemLeftCurl {
if sg == nil {
sg, rerr = getRoot(l)
if gq == nil {
gq, rerr = getRoot(l)
if rerr != nil {
x.Err(glog, rerr).Error("While retrieving subgraph root")
return nil, rerr
}
} else {
if err := godeep(l, sg); err != nil {
return sg, err
if err := godeep(l, gq); err != nil {
return gq, err
}
}
}
}
return sg, nil
return gq, nil
}
func getRoot(l *lex.Lexer) (sg *query.SubGraph, rerr error) {
func getRoot(l *lex.Lexer) (gq *GraphQuery, rerr error) {
item := <-l.Items
if item.Typ != itemName {
return nil, fmt.Errorf("Expected some name. Got: %v", item)
......@@ -113,11 +121,14 @@ func getRoot(l *lex.Lexer) (sg *query.SubGraph, rerr error) {
if item.Typ != itemRightRound {
return nil, fmt.Errorf("Unexpected token. Got: %v", item)
}
return query.NewGraph(uid, xid)
gq = new(GraphQuery)
gq.UID = uid
gq.XID = xid
return gq, nil
}
func godeep(l *lex.Lexer, sg *query.SubGraph) error {
curp := sg // Used to track current node, for nesting.
func godeep(l *lex.Lexer, gq *GraphQuery) error {
curp := gq // Used to track current node, for nesting.
for item := range l.Items {
if item.Typ == lex.ItemError {
return errors.New(item.Val)
......@@ -126,9 +137,9 @@ func godeep(l *lex.Lexer, sg *query.SubGraph) error {
return nil
} else if item.Typ == itemName {
child := new(query.SubGraph)
child := new(GraphQuery)
child.Attr = item.Val
sg.Children = append(sg.Children, child)
gq.Children = append(gq.Children, child)
curp = child
} else if item.Typ == itemLeftCurl {
......
......@@ -19,11 +19,9 @@ package gql
import (
"fmt"
"testing"
"github.com/dgraph-io/dgraph/query"
)
func checkAttr(g *query.SubGraph, attr string) error {
func checkAttr(g *GraphQuery, attr string) error {
if g.Attr != attr {
return fmt.Errorf("Expected: %v. Got: %v", attr, g.Attr)
}
......@@ -43,31 +41,31 @@ func TestParse(t *testing.T) {
}
`
sg, err := Parse(query)
gq, err := Parse(query)
if err != nil {
t.Error(err)
}
if sg == nil {
if gq == nil {
t.Error("subgraph is nil")
return
}
if len(sg.Children) != 4 {
t.Errorf("Expected 4 children. Got: %v", len(sg.Children))
if len(gq.Children) != 4 {
t.Errorf("Expected 4 children. Got: %v", len(gq.Children))
return
}
if err := checkAttr(sg.Children[0], "friends"); err != nil {
if err := checkAttr(gq.Children[0], "friends"); err != nil {
t.Error(err)
}
if err := checkAttr(sg.Children[1], "gender"); err != nil {
if err := checkAttr(gq.Children[1], "gender"); err != nil {
t.Error(err)
}
if err := checkAttr(sg.Children[2], "age"); err != nil {
if err := checkAttr(gq.Children[2], "age"); err != nil {
t.Error(err)
}
if err := checkAttr(sg.Children[3], "hometown"); err != nil {
if err := checkAttr(gq.Children[3], "hometown"); err != nil {
t.Error(err)
}
child := sg.Children[0]
child := gq.Children[0]
if len(child.Children) != 1 {
t.Errorf("Expected 1 child of friends. Got: %v", len(child.Children))
}
......@@ -84,19 +82,19 @@ func TestParseXid(t *testing.T) {
type.object.name
}
}`
sg, err := Parse(query)
gq, err := Parse(query)
if err != nil {
t.Error(err)
return
}
if sg == nil {
if gq == nil {
t.Error("subgraph is nil")
return
}
if len(sg.Children) != 1 {
t.Errorf("Expected 1 children. Got: %v", len(sg.Children))
if len(gq.Children) != 1 {
t.Errorf("Expected 1 children. Got: %v", len(gq.Children))
}
if err := checkAttr(sg.Children[0], "type.object.name"); err != nil {
if err := checkAttr(gq.Children[0], "type.object.name"); err != nil {
t.Error(err)
}
}
......@@ -143,22 +141,22 @@ func TestParse_pass1(t *testing.T) {
}
}
`
sg, err := Parse(query)
gq, err := Parse(query)
if err != nil {
t.Error(err)
}
if len(sg.Children) != 2 {
t.Errorf("Expected 2. Got: %v", len(sg.Children))
if len(gq.Children) != 2 {
t.Errorf("Expected 2. Got: %v", len(gq.Children))
}
if err := checkAttr(sg.Children[0], "name"); err != nil {
if err := checkAttr(gq.Children[0], "name"); err != nil {
t.Error(err)
}
if err := checkAttr(sg.Children[1], "friends"); err != nil {
if err := checkAttr(gq.Children[1], "friends"); err != nil {
t.Error(err)
}
f := sg.Children[1]
f := gq.Children[1]
if len(f.Children) != 0 {
t.Errorf("Expected 0. Got: %v", len(sg.Children))
t.Errorf("Expected 0. Got: %v", len(gq.Children))
}
}
......@@ -170,14 +168,14 @@ func TestParse_block(t *testing.T) {
}
}
`
sg, err := Parse(query)
gq, err := Parse(query)
if err != nil {
t.Error(err)
}
if len(sg.Children) != 1 {
t.Errorf("Expected 1. Got: %v", len(sg.Children))
if len(gq.Children) != 1 {
t.Errorf("Expected 1. Got: %v", len(gq.Children))
}
if err := checkAttr(sg.Children[0], "type.object.name.es-419"); err != nil {
if err := checkAttr(gq.Children[0], "type.object.name.es-419"); err != nil {
t.Error(err)
}
}
......@@ -24,6 +24,7 @@ import (
"time"
"github.com/Sirupsen/logrus"
"github.com/dgraph-io/dgraph/gql"
"github.com/dgraph-io/dgraph/posting"
"github.com/dgraph-io/dgraph/task"
"github.com/dgraph-io/dgraph/uid"
......@@ -251,7 +252,25 @@ func (g *SubGraph) ToJson(l *Latency) (js []byte, rerr error) {
return json.Marshal(r)
}
func NewGraph(euid uint64, exid string) (*SubGraph, error) {
func treeCopy(gq *gql.GraphQuery, sg *SubGraph) {
for _, gchild := range gq.Children {
dst := new(SubGraph)
dst.Attr = gchild.Attr
sg.Children = append(sg.Children, dst)
treeCopy(gchild, dst)
}
}
func ToSubGraph(gq *gql.GraphQuery) (*SubGraph, error) {
sg, err := newGraph(gq.UID, gq.XID)
if err != nil {
return nil, err
}
treeCopy(gq, sg)
return sg, nil
}
func newGraph(euid uint64, exid string) (*SubGraph, error) {
// This would set the Result field in SubGraph,
// and populate the children for attributes.
if len(exid) > 0 {
......
......@@ -24,6 +24,7 @@ import (
"time"
"github.com/dgraph-io/dgraph/commit"
"github.com/dgraph-io/dgraph/gql"
"github.com/dgraph-io/dgraph/posting"
"github.com/dgraph-io/dgraph/store"
"github.com/dgraph-io/dgraph/task"
......@@ -38,85 +39,6 @@ func setErr(err *error, nerr error) {
*err = nerr
}
/*
func populateList(key []byte) error {
pl := posting.Get(key)
t := x.DirectedEdge{
ValueId: 9,
Source: "query_test",
Timestamp: time.Now(),
}
var err error
setErr(&err, pl.AddMutation(t, posting.Set))
t.ValueId = 19
setErr(&err, pl.AddMutation(t, posting.Set))
t.ValueId = 29
setErr(&err, pl.AddMutation(t, posting.Set))
t.Value = "abracadabra"
setErr(&err, pl.AddMutation(t, posting.Set))
return err
}
func TestRun(t *testing.T) {
logrus.SetLevel(logrus.DebugLevel)
pdir := NewStore(t)
defer os.RemoveAll(pdir)
ps := new(store.Store)
ps.Init(pdir)
mdir := NewStore(t)
defer os.RemoveAll(mdir)
ms := new(store.Store)
ms.Init(mdir)
posting.Init(ps, ms)
key := posting.Key(11, "testing")
if err := populateList(key); err != nil {
t.Error(err)
}
key = posting.Key(9, "name")
m := Message{Id: 11}
ma := Mattr{Attr: "testing"}
m.Attrs = append(m.Attrs, ma)
if err := Run(&m); err != nil {
t.Error(err)
}
ma = m.Attrs[0]
uids := result.GetRootAsUids(ma.ResultUids, 0)
if uids.UidLength() != 3 {
t.Errorf("Expected 3. Got: %v", uids.UidLength())
}
var v uint64
v = 9
for i := 0; i < uids.UidLength(); i++ {
if uids.Uid(i) == math.MaxUint64 {
t.Error("Value posting encountered at index:", i)
}
if v != uids.Uid(i) {
t.Errorf("Expected: %v. Got: %v", v, uids.Uid(i))
}
v += 10
}
log.Debugf("ResultUid buffer size: %v", len(ma.ResultUids))
var val string
if err := posting.ParseValue(&val, ma.ResultValue); err != nil {
t.Error(err)
}
if val != "abracadabra" {
t.Errorf("Expected abracadabra. Got: [%q]", val)
}
}
*/
func addEdge(t *testing.T, edge x.DirectedEdge, l *posting.List) {
if err := l.AddMutation(edge, posting.Set); err != nil {
t.Error(err)
......@@ -166,7 +88,7 @@ func checkSingleValue(t *testing.T, child *SubGraph,
func TestNewGraph(t *testing.T) {
var ex uint64
ex = 101
sg, err := NewGraph(ex, "")
sg, err := newGraph(ex, "")
if err != nil {
t.Error(err)
}
......@@ -256,29 +178,26 @@ func TestProcessGraph(t *testing.T) {
defer os.RemoveAll(dir)
// Alright. Now we have everything set up. Let's create the query.
sg, err := NewGraph(1, "")
query := `
{
me(_uid_: 0x01) {
friend {
name
}
name
gender
status
}
}
`
gq, err := gql.Parse(query)
if err != nil {
t.Error(err)
}
sg, err := ToSubGraph(gq)
if err != nil {
t.Error(err)
}
// Retrieve friends, and their names.
csg := new(SubGraph)
csg.Attr = "friend"
gsg := new(SubGraph)
gsg.Attr = "name"
csg.Children = append(csg.Children, gsg)
sg.Children = append(sg.Children, csg)
// Retireve profile information for uid:1.
csg = new(SubGraph)
csg.Attr = "name"
sg.Children = append(sg.Children, csg)
csg = new(SubGraph)
csg.Attr = "gender"
sg.Children = append(sg.Children, csg)
csg = new(SubGraph)
csg.Attr = "status"
sg.Children = append(sg.Children, csg)
ch := make(chan error)
go ProcessGraph(sg, ch)
......@@ -350,28 +269,27 @@ func TestToJson(t *testing.T) {
defer os.RemoveAll(dir)
// Alright. Now we have everything set up. Let's create the query.
sg, err := NewGraph(1, "")
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)
}
// Retireve profile information for uid:1.
csg := new(SubGraph)
csg.Attr = "name"
sg.Children = append(sg.Children, csg)
csg = new(SubGraph)
csg.Attr = "gender"
sg.Children = append(sg.Children, csg)
csg = new(SubGraph)
csg.Attr = "status"
sg.Children = append(sg.Children, csg)
gsg := new(SubGraph)
gsg.Attr = "name"
csg = new(SubGraph)
csg.Attr = "friend"
csg.Children = append(csg.Children, gsg)
sg.Children = append(sg.Children, csg)
ch := make(chan error)
go ProcessGraph(sg, ch)
......
......@@ -70,15 +70,23 @@ func queryHandler(w http.ResponseWriter, r *http.Request) {
x.SetStatus(w, x.E_INVALID_REQUEST, "Invalid request encountered.")
return
}
glog.WithField("q", string(q)).Debug("Query received.")
sg, err := gql.Parse(string(q))
gq, err := gql.Parse(string(q))
if err != nil {
x.Err(glog, err).Error("While parsing query")
x.SetStatus(w, x.E_INVALID_REQUEST, err.Error())
return
}
sg, err := query.ToSubGraph(gq)
if err != nil {
x.Err(glog, err).Error("While conversion to internal format")
x.SetStatus(w, x.E_INVALID_REQUEST, err.Error())
return
}
l.Parsing = time.Since(l.Start)
glog.WithField("q", string(q)).Debug("Query parsed.")
rch := make(chan error)
go query.ProcessGraph(sg, rch)
err = <-rch
......
......@@ -88,11 +88,17 @@ func TestQuery(t *testing.T) {
defer closeAll(dir1, dir2, clog)
// Parse GQL into internal query representation.
g, err := gql.Parse(q0)
gq, err := gql.Parse(q0)
if err != nil {
t.Error(err)
return
}
g, err := query.ToSubGraph(gq)
if err != nil {
t.Error(err)
return
}
// Test internal query representation.
if len(g.Children) != 3 {
t.Errorf("Expected 3 children. Got: %v", len(g.Children))
......@@ -178,11 +184,17 @@ func BenchmarkQuery(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
g, err := gql.Parse(q1)
gq, err := gql.Parse(q1)
if err != nil {
b.Error(err)
return
}
g, err := query.ToSubGraph(gq)
if err != nil {
b.Error(err)
return
}
ch := make(chan error)
go query.ProcessGraph(g, ch)
if err := <-ch; err != nil {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment