Skip to content

Commit 7a6dad8

Browse files
committed
Add support for parsing functions in RDF
Following are now possible (useful in upsert API) * uid(v) <predicate> "object" . * <0x01> <predicate> uid(foo) . For now, we only support uid function. In future, we can add support for more functions, starting with `val`.
1 parent 1532807 commit 7a6dad8

File tree

3 files changed

+103
-29
lines changed

3 files changed

+103
-29
lines changed

Diff for: chunker/rdf/parse.go

+32-9
Original file line numberDiff line numberDiff line change
@@ -77,17 +77,17 @@ L:
7777
case itemSubject:
7878
rnq.Subject = strings.Trim(item.Val, " ")
7979

80-
case itemVarKeyword:
81-
it.Next()
82-
if item = it.Item(); item.Typ != itemLeftRound {
83-
return rnq, errors.Errorf("Expected '(', found: %s", item.Val)
84-
}
85-
it.Next()
86-
if item = it.Item(); item.Typ != itemVarName {
87-
return rnq, errors.Errorf("Expected variable name, found: %s", item.Val)
80+
case itemSubjectFunc:
81+
var err error
82+
if rnq.Subject, err = parseFunction(it); err != nil {
83+
return rnq, err
8884
}
8985

90-
it.Next() // parse ')'
86+
case itemObjectFunc:
87+
var err error
88+
if rnq.ObjectId, err = parseFunction(it); err != nil {
89+
return rnq, err
90+
}
9191

9292
case itemPredicate:
9393
// Here we split predicate and lang directive (ex: "name@en"), if needed.
@@ -202,6 +202,29 @@ L:
202202
return rnq, nil
203203
}
204204

205+
func parseFunction(it *lex.ItemIterator) (string, error) {
206+
item := it.Item()
207+
s := item.Val
208+
209+
it.Next()
210+
if item = it.Item(); item.Typ != itemLeftRound {
211+
return "", errors.Errorf("Expected '(', found: %s", item.Val)
212+
}
213+
214+
it.Next()
215+
if item = it.Item(); item.Typ != itemVarName {
216+
return "", errors.Errorf("Expected variable name, found: %s", item.Val)
217+
}
218+
s += "(" + item.Val + ")"
219+
220+
it.Next()
221+
if item = it.Item(); item.Typ != itemRightRound {
222+
return "", errors.Errorf("Expected ')', found: %s", item.Val)
223+
}
224+
225+
return s, nil
226+
}
227+
205228
func parseFacets(it *lex.ItemIterator, rnq *api.NQuad) error {
206229
if !it.Next() {
207230
return errors.Errorf("Unexpected end of facets.")

Diff for: chunker/rdf/parse_test.go

+45
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,51 @@ var testNQuads = []struct {
895895
input: `<alice> <age> "13"^^<xs:double> (salary=NaN) .`,
896896
expectedErr: true,
897897
},
898+
{
899+
input: `uid(v) <lives> "\x02 wonderland" .`,
900+
nq: api.NQuad{
901+
Subject: "uid(v)",
902+
Predicate: "lives",
903+
ObjectValue: &api.Value{Val: &api.Value_DefaultVal{DefaultVal: "\x02 wonderland"}},
904+
},
905+
expectedErr: false,
906+
},
907+
{
908+
input: `uid ( v ) <lives> "vrinadavan" .`,
909+
nq: api.NQuad{
910+
Subject: "uid(v)",
911+
Predicate: "lives",
912+
ObjectValue: &api.Value{Val: &api.Value_DefaultVal{DefaultVal: "vrinadavan"}},
913+
},
914+
expectedErr: false,
915+
},
916+
{
917+
input: `uid ( val ) <lives> "vrinadavan" .`,
918+
nq: api.NQuad{
919+
Subject: "uid(val)",
920+
Predicate: "lives",
921+
ObjectValue: &api.Value{Val: &api.Value_DefaultVal{DefaultVal: "vrinadavan"}},
922+
},
923+
expectedErr: false,
924+
},
925+
{
926+
input: `uid ( val ) <lives> uid(g) .`,
927+
nq: api.NQuad{
928+
Subject: "uid(val)",
929+
Predicate: "lives",
930+
ObjectId: "uid(g)",
931+
},
932+
expectedErr: false,
933+
},
934+
{
935+
input: `uid ( val ) <lives> uid ( g ) .`,
936+
nq: api.NQuad{
937+
Subject: "uid(val)",
938+
Predicate: "lives",
939+
ObjectId: "uid(g)",
940+
},
941+
expectedErr: false,
942+
},
898943
}
899944

900945
func TestLex(t *testing.T) {

Diff for: chunker/rdf/state.go

+26-20
Original file line numberDiff line numberDiff line change
@@ -26,23 +26,24 @@ import (
2626

2727
// The constants represent different types of lexed Items possible for an rdf N-Quad.
2828
const (
29-
itemText lex.ItemType = 5 + iota // plain text
30-
itemSubject // subject, 6
31-
itemPredicate // predicate, 7
32-
itemObject // object, 8
33-
itemLabel // label, 9
34-
itemLiteral // literal, 10
35-
itemLanguage // language, 11
36-
itemObjectType // object type, 12
37-
itemValidEnd // end with dot, 13
38-
itemComment // comment, 14
39-
itemComma // comma, 15
40-
itemEqual // equal, 16
41-
itemLeftRound // '(', 17
42-
itemRightRound // ')', 18
43-
itemStar // *, 19
44-
itemVarKeyword // var, 20
45-
itemVarName // 21
29+
itemText lex.ItemType = 5 + iota // plain text
30+
itemSubject // subject, 6
31+
itemPredicate // predicate, 7
32+
itemObject // object, 8
33+
itemLabel // label, 9
34+
itemLiteral // literal, 10
35+
itemLanguage // language, 11
36+
itemObjectType // object type, 12
37+
itemValidEnd // end with dot, 13
38+
itemComment // comment, 14
39+
itemComma // comma, 15
40+
itemEqual // equal, 16
41+
itemLeftRound // '(', 17
42+
itemRightRound // ')', 18
43+
itemStar // *, 19
44+
itemSubjectFunc // uid, 20
45+
itemObjectFunc // uid, 21
46+
itemVarName // 22
4647
)
4748

4849
// These constants keep a track of the depth while parsing an rdf N-Quad.
@@ -138,6 +139,7 @@ func lexText(l *lex.Lexer) lex.StateFn {
138139
l.Depth = atSubject
139140
}
140141

142+
// TODO(Aman): add support for more functions here.
141143
case r == 'u':
142144
if l.Depth != atSubject && l.Depth != atObject {
143145
return l.Errorf("Unexpected char 'u'")
@@ -423,19 +425,23 @@ func lexComment(l *lex.Lexer) lex.StateFn {
423425
func lexVariable(l *lex.Lexer) lex.StateFn {
424426
var r rune
425427

428+
// TODO(Aman): add support for more functions here.
426429
for _, c := range "uid" {
427430
if r = l.Next(); r != c {
428431
return l.Errorf("Unexpected char '%c' when parsing var keyword", r)
429432
}
430433
}
431-
l.Emit(itemVarKeyword)
434+
if l.Depth == atObject {
435+
l.Emit(itemObjectFunc)
436+
} else if l.Depth == atSubject {
437+
l.Emit(itemSubjectFunc)
438+
}
432439
l.IgnoreRun(isSpace)
433440

434441
if r = l.Next(); r != '(' {
435442
return l.Errorf("Expected '(' after var keyword, found: '%c'", r)
436443
}
437444
l.Emit(itemLeftRound)
438-
439445
l.IgnoreRun(isSpace)
440446

441447
for {
@@ -448,11 +454,11 @@ func lexVariable(l *lex.Lexer) lex.StateFn {
448454
break
449455
}
450456
if isSpace(r) {
457+
l.Backup()
451458
break
452459
}
453460
}
454461
l.Emit(itemVarName)
455-
456462
l.IgnoreRun(isSpace)
457463

458464
if r = l.Next(); r != ')' {

0 commit comments

Comments
 (0)