diff --git a/gql/lexer.go b/gql/lexer.go index 4b1be18555c28000766a4a573485812058e22596..3a30e4a7eba10f58d3cae04b3ffa07b4098de834 100644 --- a/gql/lexer.go +++ b/gql/lexer.go @@ -1,3 +1,19 @@ +/* + * Copyright 2015 Manish R Jain <manishrjain@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package gql import ( diff --git a/gql/lexer_test.go b/gql/lexer_test.go index 91ea5be51e566952d4181cf76ab4c3d450520a95..0564b0c7ae188bfae65532c5d0e2bc41ea02a828 100644 --- a/gql/lexer_test.go +++ b/gql/lexer_test.go @@ -1,3 +1,19 @@ +/* + * Copyright 2015 Manish R Jain <manishrjain@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package gql import ( diff --git a/gql/parser.go b/gql/parser.go new file mode 100644 index 0000000000000000000000000000000000000000..5b3f2753071948a739a6116289ebc50dee2f46b0 --- /dev/null +++ b/gql/parser.go @@ -0,0 +1,131 @@ +/* + * Copyright 2015 Manish R Jain <manishrjain@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gql + +import ( + "errors" + "fmt" + "strconv" + + "github.com/manishrjain/dgraph/query" + "github.com/manishrjain/dgraph/x" +) + +func Parse(input string) (sg *query.SubGraph, rerr error) { + l := newLexer(input) + sg = nil + for item := range l.items { + if item.typ == itemText { + continue + } + if item.typ == itemOpType { + if item.val == "mutation" { + return nil, errors.New("Mutations not supported") + } + } + if item.typ == itemLeftCurl { + if sg == nil { + sg, rerr = getRoot(l) + if rerr != nil { + x.Err(glog, rerr).Error("While retrieving subgraph root") + return nil, rerr + } + } else { + godeep(l, sg) + } + } + } + return sg, nil +} + +func getRoot(l *lexer) (sg *query.SubGraph, rerr error) { + item := <-l.items + if item.typ != itemName { + return nil, fmt.Errorf("Expected some name. Got: %v", item) + } + // ignore itemName for now. + item = <-l.items + if item.typ != itemLeftRound { + return nil, fmt.Errorf("Expected variable start. Got: %v", item) + } + + var uid uint64 + var xid string + for { + var key, val string + // Get key or close bracket + item = <-l.items + if item.typ == itemArgName { + key = item.val + } else if item.typ == itemRightRound { + break + } else { + return nil, fmt.Errorf("Expecting argument name. Got: %v", item) + } + + // Get corresponding value. + item = <-l.items + if item.typ == itemArgVal { + val = item.val + } else { + return nil, fmt.Errorf("Expecting argument val. Got: %v", item) + } + + if key == "uid" { + uid, rerr = strconv.ParseUint(val, 0, 64) + if rerr != nil { + return nil, rerr + } + } else if key == "xid" { + xid = val + } else { + return nil, fmt.Errorf("Expecting uid or xid. Got: %v", item) + } + } + if item.typ != itemRightRound { + return nil, fmt.Errorf("Unexpected token. Got: %v", item) + } + return query.NewGraph(uid, xid) +} + +func godeep(l *lexer, sg *query.SubGraph) { + curp := sg // stores current pointer. + for { + switch item := <-l.items; { + case item.typ == itemName: + child := new(query.SubGraph) + child.Attr = item.val + sg.Children = append(sg.Children, child) + curp = child + case item.typ == itemLeftCurl: + godeep(l, curp) // recursive iteration + case item.typ == itemRightCurl: + return + case item.typ == itemLeftRound: + // absorb all these, we don't care right now. + for { + item = <-l.items + if item.typ == itemRightRound || item.typ == itemEOF { + break + } + } + default: + // continue + } + } + +} diff --git a/gql/parser_test.go b/gql/parser_test.go new file mode 100644 index 0000000000000000000000000000000000000000..e4dab4ee25524640f43c8548fb685efc5eaeb504 --- /dev/null +++ b/gql/parser_test.go @@ -0,0 +1,134 @@ +/* + * Copyright 2015 Manish R Jain <manishrjain@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package gql + +import ( + "fmt" + "testing" + + "github.com/manishrjain/dgraph/query" +) + +func checkAttr(g *query.SubGraph, attr string) error { + if g.Attr != attr { + return fmt.Errorf("Expected: %v. Got: %v", attr, g.Attr) + } + return nil +} + +func TestParse(t *testing.T) { + query := ` + query { + me(uid:0x0a) { + friends { + name + } + gender + age + hometown + } + } +` + + sg, err := Parse(query) + if err != nil { + t.Error(err) + } + if len(sg.Children) != 4 { + t.Errorf("Expected 4 children. Got: %v", len(sg.Children)) + } + if err := checkAttr(sg.Children[0], "friends"); err != nil { + t.Error(err) + } + if err := checkAttr(sg.Children[1], "gender"); err != nil { + t.Error(err) + } + if err := checkAttr(sg.Children[2], "age"); err != nil { + t.Error(err) + } + if err := checkAttr(sg.Children[3], "hometown"); err != nil { + t.Error(err) + } + child := sg.Children[0] + if len(child.Children) != 1 { + t.Errorf("Expected 1 child of friends. Got: %v", len(child.Children)) + } + if err := checkAttr(child.Children[0], "name"); err != nil { + t.Error(err) + } +} + +func TestParse_error1(t *testing.T) { + query := ` + mutation { + me(uid:0x0a) { + name + } + } + ` + var err error + _, err = Parse(query) + t.Log(err) + if err == nil { + t.Error("Expected error") + } +} + +func TestParse_error2(t *testing.T) { + query := ` + query { + me { + name + } + } + ` + var err error + _, err = Parse(query) + t.Log(err) + if err == nil { + t.Error("Expected error") + } +} + +func TestParse_pass1(t *testing.T) { + query := ` + { + me(uid:0x0a) { + name, + friends(xid:what) { # xid would be ignored. + } + } + } + ` + sg, err := Parse(query) + if err != nil { + t.Error(err) + } + if len(sg.Children) != 2 { + t.Errorf("Expected 2. Got: %v", len(sg.Children)) + } + if err := checkAttr(sg.Children[0], "name"); err != nil { + t.Error(err) + } + if err := checkAttr(sg.Children[1], "friends"); err != nil { + t.Error(err) + } + f := sg.Children[1] + if len(f.Children) != 0 { + t.Errorf("Expected 0. Got: %v", len(sg.Children)) + } +} diff --git a/gql/state.go b/gql/state.go index 01e967ea3c363de553ad74d468b8069b3e60ba90..f5e07c04f44cffa6439607cd637c201891a951a3 100644 --- a/gql/state.go +++ b/gql/state.go @@ -1,3 +1,19 @@ +/* + * Copyright 2015 Manish R Jain <manishrjain@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package gql const (