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

Merge pull request #27 from dgraph-io/gql

Remove gql module's dependency on query. Make it the other way round.…
parents ef545b5b 7d6cb52d
No related branches found
No related tags found
No related merge requests found
...@@ -22,12 +22,20 @@ import ( ...@@ -22,12 +22,20 @@ import (
"strconv" "strconv"
"github.com/dgraph-io/dgraph/lex" "github.com/dgraph-io/dgraph/lex"
"github.com/dgraph-io/dgraph/query"
"github.com/dgraph-io/dgraph/x" "github.com/dgraph-io/dgraph/x"
) )
var glog = x.Log("gql") 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) { func run(l *lex.Lexer) {
for state := lexText; state != nil; { for state := lexText; state != nil; {
state = state(l) state = state(l)
...@@ -35,11 +43,11 @@ func run(l *lex.Lexer) { ...@@ -35,11 +43,11 @@ func run(l *lex.Lexer) {
close(l.Items) // No more tokens. 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) l := lex.NewLexer(input)
go run(l) go run(l)
sg = nil gq = nil
for item := range l.Items { for item := range l.Items {
if item.Typ == itemText { if item.Typ == itemText {
continue continue
...@@ -50,23 +58,23 @@ func Parse(input string) (sg *query.SubGraph, rerr error) { ...@@ -50,23 +58,23 @@ func Parse(input string) (sg *query.SubGraph, rerr error) {
} }
} }
if item.Typ == itemLeftCurl { if item.Typ == itemLeftCurl {
if sg == nil { if gq == nil {
sg, rerr = getRoot(l) gq, rerr = getRoot(l)
if rerr != nil { if rerr != nil {
x.Err(glog, rerr).Error("While retrieving subgraph root") x.Err(glog, rerr).Error("While retrieving subgraph root")
return nil, rerr return nil, rerr
} }
} else { } else {
if err := godeep(l, sg); err != nil { if err := godeep(l, gq); err != nil {
return sg, err 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 item := <-l.Items
if item.Typ != itemName { if item.Typ != itemName {
return nil, fmt.Errorf("Expected some name. Got: %v", item) return nil, fmt.Errorf("Expected some name. Got: %v", item)
...@@ -113,11 +121,14 @@ func getRoot(l *lex.Lexer) (sg *query.SubGraph, rerr error) { ...@@ -113,11 +121,14 @@ func getRoot(l *lex.Lexer) (sg *query.SubGraph, rerr error) {
if item.Typ != itemRightRound { if item.Typ != itemRightRound {
return nil, fmt.Errorf("Unexpected token. Got: %v", item) 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 { func godeep(l *lex.Lexer, gq *GraphQuery) error {
curp := sg // Used to track current node, for nesting. curp := gq // Used to track current node, for nesting.
for item := range l.Items { for item := range l.Items {
if item.Typ == lex.ItemError { if item.Typ == lex.ItemError {
return errors.New(item.Val) return errors.New(item.Val)
...@@ -126,9 +137,9 @@ func godeep(l *lex.Lexer, sg *query.SubGraph) error { ...@@ -126,9 +137,9 @@ func godeep(l *lex.Lexer, sg *query.SubGraph) error {
return nil return nil
} else if item.Typ == itemName { } else if item.Typ == itemName {
child := new(query.SubGraph) child := new(GraphQuery)
child.Attr = item.Val child.Attr = item.Val
sg.Children = append(sg.Children, child) gq.Children = append(gq.Children, child)
curp = child curp = child
} else if item.Typ == itemLeftCurl { } else if item.Typ == itemLeftCurl {
......
...@@ -19,11 +19,9 @@ package gql ...@@ -19,11 +19,9 @@ package gql
import ( import (
"fmt" "fmt"
"testing" "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 { if g.Attr != attr {
return fmt.Errorf("Expected: %v. Got: %v", attr, g.Attr) return fmt.Errorf("Expected: %v. Got: %v", attr, g.Attr)
} }
...@@ -43,31 +41,31 @@ func TestParse(t *testing.T) { ...@@ -43,31 +41,31 @@ func TestParse(t *testing.T) {
} }
` `
sg, err := Parse(query) gq, err := Parse(query)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
if sg == nil { if gq == nil {
t.Error("subgraph is nil") t.Error("subgraph is nil")
return return
} }
if len(sg.Children) != 4 { if len(gq.Children) != 4 {
t.Errorf("Expected 4 children. Got: %v", len(sg.Children)) t.Errorf("Expected 4 children. Got: %v", len(gq.Children))
return return
} }
if err := checkAttr(sg.Children[0], "friends"); err != nil { if err := checkAttr(gq.Children[0], "friends"); err != nil {
t.Error(err) t.Error(err)
} }
if err := checkAttr(sg.Children[1], "gender"); err != nil { if err := checkAttr(gq.Children[1], "gender"); err != nil {
t.Error(err) t.Error(err)
} }
if err := checkAttr(sg.Children[2], "age"); err != nil { if err := checkAttr(gq.Children[2], "age"); err != nil {
t.Error(err) t.Error(err)
} }
if err := checkAttr(sg.Children[3], "hometown"); err != nil { if err := checkAttr(gq.Children[3], "hometown"); err != nil {
t.Error(err) t.Error(err)
} }
child := sg.Children[0] child := gq.Children[0]
if len(child.Children) != 1 { if len(child.Children) != 1 {
t.Errorf("Expected 1 child of friends. Got: %v", len(child.Children)) t.Errorf("Expected 1 child of friends. Got: %v", len(child.Children))
} }
...@@ -84,19 +82,19 @@ func TestParseXid(t *testing.T) { ...@@ -84,19 +82,19 @@ func TestParseXid(t *testing.T) {
type.object.name type.object.name
} }
}` }`
sg, err := Parse(query) gq, err := Parse(query)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
} }
if sg == nil { if gq == nil {
t.Error("subgraph is nil") t.Error("subgraph is nil")
return return
} }
if len(sg.Children) != 1 { if len(gq.Children) != 1 {
t.Errorf("Expected 1 children. Got: %v", len(sg.Children)) 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) t.Error(err)
} }
} }
...@@ -143,22 +141,22 @@ func TestParse_pass1(t *testing.T) { ...@@ -143,22 +141,22 @@ func TestParse_pass1(t *testing.T) {
} }
} }
` `
sg, err := Parse(query) gq, err := Parse(query)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
if len(sg.Children) != 2 { if len(gq.Children) != 2 {
t.Errorf("Expected 2. Got: %v", len(sg.Children)) 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) t.Error(err)
} }
if err := checkAttr(sg.Children[1], "friends"); err != nil { if err := checkAttr(gq.Children[1], "friends"); err != nil {
t.Error(err) t.Error(err)
} }
f := sg.Children[1] f := gq.Children[1]
if len(f.Children) != 0 { 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) { ...@@ -170,14 +168,14 @@ func TestParse_block(t *testing.T) {
} }
} }
` `
sg, err := Parse(query) gq, err := Parse(query)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
if len(sg.Children) != 1 { if len(gq.Children) != 1 {
t.Errorf("Expected 1. Got: %v", len(sg.Children)) 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) t.Error(err)
} }
} }
...@@ -24,6 +24,7 @@ import ( ...@@ -24,6 +24,7 @@ import (
"time" "time"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
"github.com/dgraph-io/dgraph/gql"
"github.com/dgraph-io/dgraph/posting" "github.com/dgraph-io/dgraph/posting"
"github.com/dgraph-io/dgraph/task" "github.com/dgraph-io/dgraph/task"
"github.com/dgraph-io/dgraph/uid" "github.com/dgraph-io/dgraph/uid"
...@@ -251,7 +252,25 @@ func (g *SubGraph) ToJson(l *Latency) (js []byte, rerr error) { ...@@ -251,7 +252,25 @@ func (g *SubGraph) ToJson(l *Latency) (js []byte, rerr error) {
return json.Marshal(r) 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, // This would set the Result field in SubGraph,
// and populate the children for attributes. // and populate the children for attributes.
if len(exid) > 0 { if len(exid) > 0 {
......
...@@ -24,6 +24,7 @@ import ( ...@@ -24,6 +24,7 @@ import (
"time" "time"
"github.com/dgraph-io/dgraph/commit" "github.com/dgraph-io/dgraph/commit"
"github.com/dgraph-io/dgraph/gql"
"github.com/dgraph-io/dgraph/posting" "github.com/dgraph-io/dgraph/posting"
"github.com/dgraph-io/dgraph/store" "github.com/dgraph-io/dgraph/store"
"github.com/dgraph-io/dgraph/task" "github.com/dgraph-io/dgraph/task"
...@@ -38,85 +39,6 @@ func setErr(err *error, nerr error) { ...@@ -38,85 +39,6 @@ func setErr(err *error, nerr error) {
*err = nerr *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) { func addEdge(t *testing.T, edge x.DirectedEdge, l *posting.List) {
if err := l.AddMutation(edge, posting.Set); err != nil { if err := l.AddMutation(edge, posting.Set); err != nil {
t.Error(err) t.Error(err)
...@@ -166,7 +88,7 @@ func checkSingleValue(t *testing.T, child *SubGraph, ...@@ -166,7 +88,7 @@ func checkSingleValue(t *testing.T, child *SubGraph,
func TestNewGraph(t *testing.T) { func TestNewGraph(t *testing.T) {
var ex uint64 var ex uint64
ex = 101 ex = 101
sg, err := NewGraph(ex, "") sg, err := newGraph(ex, "")
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
...@@ -256,29 +178,26 @@ func TestProcessGraph(t *testing.T) { ...@@ -256,29 +178,26 @@ func TestProcessGraph(t *testing.T) {
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
// Alright. Now we have everything set up. Let's create the query. // 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 { if err != nil {
t.Error(err) 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) ch := make(chan error)
go ProcessGraph(sg, ch) go ProcessGraph(sg, ch)
...@@ -350,28 +269,27 @@ func TestToJson(t *testing.T) { ...@@ -350,28 +269,27 @@ func TestToJson(t *testing.T) {
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
// Alright. Now we have everything set up. Let's create the query. // 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 { if err != nil {
t.Error(err) 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) ch := make(chan error)
go ProcessGraph(sg, ch) go ProcessGraph(sg, ch)
......
...@@ -70,15 +70,23 @@ func queryHandler(w http.ResponseWriter, r *http.Request) { ...@@ -70,15 +70,23 @@ func queryHandler(w http.ResponseWriter, r *http.Request) {
x.SetStatus(w, x.E_INVALID_REQUEST, "Invalid request encountered.") x.SetStatus(w, x.E_INVALID_REQUEST, "Invalid request encountered.")
return return
} }
glog.WithField("q", string(q)).Debug("Query received.") glog.WithField("q", string(q)).Debug("Query received.")
sg, err := gql.Parse(string(q)) gq, err := gql.Parse(string(q))
if err != nil { if err != nil {
x.Err(glog, err).Error("While parsing query") x.Err(glog, err).Error("While parsing query")
x.SetStatus(w, x.E_INVALID_REQUEST, err.Error()) x.SetStatus(w, x.E_INVALID_REQUEST, err.Error())
return 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) l.Parsing = time.Since(l.Start)
glog.WithField("q", string(q)).Debug("Query parsed.") glog.WithField("q", string(q)).Debug("Query parsed.")
rch := make(chan error) rch := make(chan error)
go query.ProcessGraph(sg, rch) go query.ProcessGraph(sg, rch)
err = <-rch err = <-rch
......
...@@ -88,11 +88,17 @@ func TestQuery(t *testing.T) { ...@@ -88,11 +88,17 @@ func TestQuery(t *testing.T) {
defer closeAll(dir1, dir2, clog) defer closeAll(dir1, dir2, clog)
// Parse GQL into internal query representation. // Parse GQL into internal query representation.
g, err := gql.Parse(q0) gq, err := gql.Parse(q0)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
} }
g, err := query.ToSubGraph(gq)
if err != nil {
t.Error(err)
return
}
// Test internal query representation. // Test internal query representation.
if len(g.Children) != 3 { if len(g.Children) != 3 {
t.Errorf("Expected 3 children. Got: %v", len(g.Children)) t.Errorf("Expected 3 children. Got: %v", len(g.Children))
...@@ -178,11 +184,17 @@ func BenchmarkQuery(b *testing.B) { ...@@ -178,11 +184,17 @@ func BenchmarkQuery(b *testing.B) {
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
g, err := gql.Parse(q1) gq, err := gql.Parse(q1)
if err != nil { if err != nil {
b.Error(err) b.Error(err)
return return
} }
g, err := query.ToSubGraph(gq)
if err != nil {
b.Error(err)
return
}
ch := make(chan error) ch := make(chan error)
go query.ProcessGraph(g, ch) go query.ProcessGraph(g, ch)
if err := <-ch; err != nil { if err := <-ch; err != nil {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment