Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dgraph/cmd/alpha/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ func mutationHandler(w http.ResponseWriter, r *http.Request) {

case "application/rdf":
// Parse N-Quads.
req, err = dql.ParseMutation(string(body))
req, err = dql.ParseDQL(string(body))
if err != nil {
x.SetStatus(w, x.ErrorInvalidRequest, err.Error())
return
Expand Down
2 changes: 1 addition & 1 deletion dgraph/cmd/alpha/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -934,7 +934,7 @@ func TestContentTypeCharset(t *testing.T) {
require.True(t, err != nil && strings.Contains(err.Error(), "Unsupported charset"))

_, err = mutationWithTs(
mutationInp{body: `{}`, typ: "application/rdf; charset=utf-8", commitNow: true})
mutationInp{body: `{ set {_:a <name> "alice" .}}`, typ: "application/rdf; charset=utf-8", commitNow: true})
require.NoError(t, err)

_, err = mutationWithTs(
Expand Down
50 changes: 50 additions & 0 deletions dql/dql.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: Hypermode Inc. <[email protected]>
* SPDX-License-Identifier: Apache-2.0
*/

package dql

import (
"github.com/dgraph-io/dgo/v240/protos/api"

"github.com/hypermodeinc/dgraph/v24/lex"
)

func ParseDQL(dqlQuery string) (*api.Request, error) {
var lexer lex.Lexer
lexer.Reset(dqlQuery)
lexer.Run(lexTopLevel)
if err := lexer.ValidateResult(); err != nil {
return nil, err
}

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

item := it.Item()
switch item.Typ {
case itemUpsertBlock:
it.Prev()
return parseUpsertBlock(it)

default:
it.Next()
item = it.Item()
if item.Typ == itemMutationOp {
it.Prev()
it.Prev()
mu, err := parseMutationBlock(it)
if err != nil {
return nil, err
}
return &api.Request{Mutations: []*api.Mutation{mu}}, nil
}

it.Prev()
it.Prev()
return &api.Request{Query: dqlQuery}, nil
}
}
95 changes: 95 additions & 0 deletions dql/dql_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* SPDX-FileCopyrightText: © Hypermode Inc. <[email protected]>
* SPDX-License-Identifier: Apache-2.0
*/

package dql

import (
"testing"

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

func TestParseDQL(t *testing.T) {
testCases := []string{
`{ set {_:a <name> "Alice" .}}`,
"schema{}",
`upsert {
query {
ns(func: eq(dgraph.namespace.name, "ns1")) {
q as var
dgraph.namespace.id
}
}

mutation {
delete {
uid(q) * * .
}
}
}`,
`{
q(func: eq(dgraph.namespace.name, "ns1")) {
uid
dgraph.type
dgraph.namespace.id
}
}`,
` query test($a: int) {
q(func: uid(0x1)) {
x as count(uid)
p : math(x + $a)
}
}`,
`{
me(func: uid(1)) {
Upvote {
u as Author
}
count(val(u))
}
}`,
`{
user(func: uid(0x0a)) {
...fragmenta,...fragmentb
friends {
name
}
...fragmentc
hobbies
...fragmentd
}
me(func: uid(0x01)) {
...fragmenta
...fragmentb
}
}
fragment fragmenta {
name
}
fragment fragmentb {
id
}
fragment fragmentc {
name
}
fragment fragmentd {
id
}`,
`{
set {
<name> <is> <something> .
<hometown> <is> <san/francisco> .
}
delete {
<name> <is> <something-else> .
}
}`,
}

for _, tc := range testCases {
_, err := ParseDQL(tc)
require.NoError(t, err)
}
}
2 changes: 1 addition & 1 deletion dql/parser_mutation.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
func ParseMutation(mutation string) (req *api.Request, err error) {
var lexer lex.Lexer
lexer.Reset(mutation)
lexer.Run(lexIdentifyBlock)
lexer.Run(lexTopLevel)
if err := lexer.ValidateResult(); err != nil {
return nil, err
}
Expand Down
6 changes: 3 additions & 3 deletions dql/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1960,7 +1960,7 @@ func TestParseMutationError(t *testing.T) {
`
_, err := ParseMutation(query)
require.Error(t, err)
require.Contains(t, err.Error(), `Invalid block: [mutation]`)
require.Contains(t, err.Error(), `Unexpected token: [mutation]`)
}

func TestParseMutationError2(t *testing.T) {
Expand All @@ -1975,7 +1975,7 @@ func TestParseMutationError2(t *testing.T) {
`
_, err := ParseMutation(query)
require.Error(t, err)
require.Contains(t, err.Error(), `Invalid block: [set]`)
require.Contains(t, err.Error(), `Invalid operation type: set`)
}

func TestParseMutationAndQueryWithComments(t *testing.T) {
Expand Down Expand Up @@ -4809,7 +4809,7 @@ func TestParseMutationTooManyBlocks(t *testing.T) {
}{
set { _:b2 <reg> "b2 content" . }
}`,
errStr: "Unrecognized character in lexText",
errStr: "Unexpected { after the end of the block",
},
{m: `{set { _:a1 <reg> "a1 content" . }} something`,
errStr: "Invalid operation type: something",
Expand Down
69 changes: 31 additions & 38 deletions dql/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,43 +55,6 @@ const (
itemStar
)

// lexIdentifyBlock identifies whether it is an upsert block
// If the block begins with "{" => mutation block
// Else if the block begins with "upsert" => upsert block
func lexIdentifyBlock(l *lex.Lexer) lex.StateFn {
l.Mode = lexIdentifyBlock
for {
switch r := l.Next(); {
case isSpace(r) || lex.IsEndOfLine(r):
l.Ignore()
case isNameBegin(r):
return lexNameBlock
case r == leftCurl:
l.Backup()
return lexInsideMutation
case r == '#':
return lexComment
case r == lex.EOF:
return l.Errorf("Invalid mutation block")
default:
return l.Errorf("Unexpected character while identifying mutation block: %#U", r)
}
}
}

// lexNameBlock lexes the blocks, for now, only upsert block
func lexNameBlock(l *lex.Lexer) lex.StateFn {
// The caller already checked isNameBegin, and absorbed one rune.
l.AcceptRun(isNameSuffix)
switch word := l.Input[l.Start:l.Pos]; word {
case "upsert":
l.Emit(itemUpsertBlock)
return lexUpsertBlock
default:
return l.Errorf("Invalid block: [%s]", word)
}
}

// lexUpsertBlock lexes the upsert block
func lexUpsertBlock(l *lex.Lexer) lex.StateFn {
l.Mode = lexUpsertBlock
Expand Down Expand Up @@ -368,7 +331,7 @@ Loop:
case r == leftCurl:
l.Depth++ // one level down.
l.Emit(itemLeftCurl)
return lexQuery
return lexIdentifyMutationOrQuery
case r == rightCurl:
return l.Errorf("Too many right curl")
case r == lex.EOF:
Expand Down Expand Up @@ -396,6 +359,33 @@ Loop:
return nil
}

func lexIdentifyMutationOrQuery(l *lex.Lexer) lex.StateFn {
l.Mode = lexIdentifyMutationOrQuery
for {
switch r := l.Next(); {
case isSpace(r) || lex.IsEndOfLine(r):
l.Ignore()
case isNameBegin(r):
l.AcceptRun(isNameSuffix)
op := l.Input[l.Start:l.Pos]
// If it is a mutation
if op == "set" || op == "delete" || op == "del" {
Comment thread
mangalaman93 marked this conversation as resolved.
l.Emit(itemMutationOp)
return lexInsideMutation
}
// else it is a query
l.Emit(itemName)
return lexQuery
case r == '#':
return lexComment
case r == lex.EOF:
return l.Errorf("Invalid DQL")
default:
return l.Errorf("Unexpected character while lexing DQL: %#U", r)
}
}
}

// lexQuery lexes the input string and calls other lex functions.
func lexQuery(l *lex.Lexer) lex.StateFn {
l.Mode = lexQuery
Expand Down Expand Up @@ -592,6 +582,9 @@ func lexOperationType(l *lex.Lexer) lex.StateFn {
case "schema":
l.Emit(itemOpType)
return lexInsideSchema
case "upsert":
l.Emit(itemUpsertBlock)
return lexUpsertBlock
default:
return l.Errorf("Invalid operation type: %s", word)
}
Expand Down
Loading