Skip to content

Commit

Permalink
Add parser and lexer for mutation using txn block
Browse files Browse the repository at this point in the history
  • Loading branch information
mangalaman93 committed May 21, 2019
1 parent 6be440b commit d936cba
Show file tree
Hide file tree
Showing 6 changed files with 288 additions and 32 deletions.
78 changes: 78 additions & 0 deletions gql/parse_txn_block_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package gql

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestMutationTxnBlock1(t *testing.T) {
query := `
query {
me(func: eq(age, 34)) {
uid
friend {
uid
age
}
}
}
`
_, err := ParseMutation(query)
require.Error(t, err)
require.Contains(t, err.Error(), "Invalid block: [query]")
}

func TestMutationTxnBlock2(t *testing.T) {
query := `
txn {
query {
me(func: eq(age, 34)) {
uid
friend {
uid
age
}
}
}
}
}
`
_, err := ParseMutation(query)
require.Error(t, err)
require.Contains(t, err.Error(), "Too many right curl")
}

// Is this okay?
// - Doesn't contain mutation op inside txn block
// - uid and age are in the same line
func TestMutationTxnBlock3(t *testing.T) {
query := `txn{query{me(func:eq(age,34)){uidfriend{uid age}}}}}`
_, err := ParseMutation(query)
require.Error(t, err)
require.Contains(t, err.Error(), "Too many right curl")
}

func TestMutationTxnBlock4(t *testing.T) {
query := `
txn {
mutation {
set {
"_:user1" <age> "45" .
}
}
query {
me(func: eq(age, 34)) {
uid
friend {
uid
age
}
}
}
}
`
_, err := ParseMutation(query)
require.Nil(t, err)
}
13 changes: 9 additions & 4 deletions gql/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -457,20 +457,25 @@ type Result struct {
Schema *pb.SchemaRequest
}

// Parse initializes and runs the lexer. It also constructs the GraphQuery subgraph
// from the lexed items.
// Parse initializes and runs the lexer and parser.
func Parse(r Request) (res Result, rerr error) {
query := r.Str
vmap := convertToVarMap(r.Variables)

lexer := lex.NewLexer(query)
lexer.Run(lexTopLevel)
if err := lexer.ValidateResult(); err != nil {
return res, err
}

return ParseQuery(lexer.NewIterator(), r.Variables)
}

// ParseQuery parses the given query.
// It also constructs the GraphQuery subgraph from the lexed items.
func ParseQuery(it *lex.ItemIterator, vars map[string]string) (res Result, rerr error) {
vmap := convertToVarMap(vars)

var qu *GraphQuery
it := lexer.NewIterator()
fmap := make(fragmentMap)
for it.Next() {
item := it.Item()
Expand Down
81 changes: 75 additions & 6 deletions gql/parser_mutation.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,91 @@
package gql

import (
"errors"
"fmt"

"github.com/dgraph-io/dgo/protos/api"
"github.com/dgraph-io/dgraph/lex"
"github.com/dgraph-io/dgraph/x"
)

// ParseMutation parses a block into a mutation. Returns an object with a mutation or
// a txn block with mutation, otherwise returns nil with an error.
func ParseMutation(mutation string) (*api.Mutation, error) {
lexer := lex.NewLexer(mutation)
lexer.Run(lexInsideMutation)
it := lexer.NewIterator()
var mu api.Mutation
lexer.Run(lexIdentifyBlock)
if err := lexer.ValidateResult(); err != nil {
return nil, err
}

it := lexer.NewIterator()
if !it.Next() {
return nil, errors.New("Invalid mutation")
return nil, x.Errorf("Invalid mutation")
}

item := it.Item()
switch item.Typ {
case itemMutationTxnBlock:
return ParseTxnBlock(it)
case itemLeftCurl:
return ParseMutationBlock(it)
default:
return nil, x.Errorf("Unexpected token: [%s]", item.Val)
}
}

// ParseTxnBlock parses the txn block
func ParseTxnBlock(it *lex.ItemIterator) (*api.Mutation, error) {
var mu *api.Mutation
var res Result

// ==>txn<=== {...}
item := it.Item()
if item.Typ != itemMutationTxnBlock {
return nil, x.Errorf("Expected txn block. Got [%s]", item.Val)
}

// txn ===>{<=== ....}
it.Next()
item = it.Item()
if item.Typ != itemLeftCurl {
return nil, x.Errorf("Expected { at the start of block. Got: [%s]", item.Val)
}

for it.Next() {
item = it.Item()
switch item.Typ {
// txn {... ===>}<===
case itemRightCurl:
// TODO
fmt.Printf("ready to return, but don't know what to do with res: %+v\n", res)
return mu, nil
// txn { ===>mutation<=== {...} query{...}}
// txn { mutation{...} ===>query<==={...}}
case itemMutationTxnBlockOp:
var err error
if item.Val == "query" {
if res, err = ParseQuery(it, nil); err != nil {
return nil, err
}
} else if item.Val == "mutation" {
if mu, err = ParseMutationBlock(it); err != nil {
return nil, err
}
} else {
return nil, x.Errorf("should not reach here")
}
default:
return nil, x.Errorf("unexpected token in txn block [%s]", item.Val)
}
}

return nil, x.Errorf("Invalid txn block")
}

// ParseMutationBlock parses the mutation block
func ParseMutationBlock(it *lex.ItemIterator) (*api.Mutation, error) {
var mu api.Mutation

item := it.Item()
if item.Typ != itemLeftCurl {
return nil, x.Errorf("Expected { at the start of block. Got: [%s]", item.Val)
Expand Down Expand Up @@ -73,7 +142,7 @@ func parseMutationOp(it *lex.ItemIterator, op string, mu *api.Mutation) error {
}
parse = true
}
if item.Typ == itemMutationContent {
if item.Typ == itemMutationOpContent {
if !parse {
return x.Errorf("Mutation syntax invalid.")
}
Expand Down
4 changes: 2 additions & 2 deletions gql/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1641,7 +1641,7 @@ func TestParseMutationError(t *testing.T) {
`
_, err := ParseMutation(query)
require.Error(t, err)
require.Equal(t, `Expected { at the start of block. Got: [mutation]`, err.Error())
require.Contains(t, err.Error(), `Invalid block: [mutation]`)
}

func TestParseMutationError2(t *testing.T) {
Expand All @@ -1656,7 +1656,7 @@ func TestParseMutationError2(t *testing.T) {
`
_, err := ParseMutation(query)
require.Error(t, err)
require.Equal(t, `Expected { at the start of block. Got: [set]`, err.Error())
require.Contains(t, err.Error(), `Invalid block: [set]`)
}

func TestParseMutationAndQueryWithComments(t *testing.T) {
Expand Down
Loading

0 comments on commit d936cba

Please sign in to comment.