Skip to content

Commit e06d3e4

Browse files
martinmrdna2github
authored andcommitted
Allow querying all lang values of a predicate. (dgraph-io#2910)
This PR introduces the syntax pred@* which returns all the values of a predicate which contain a language tag.
1 parent c3c5d3a commit e06d3e4

5 files changed

Lines changed: 83 additions & 1 deletion

File tree

gql/parser.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1561,6 +1561,10 @@ L:
15611561
function.Attr = val
15621562
attrItemsAgo = 0
15631563
} else if expectLang {
1564+
if val == "*" {
1565+
return nil, x.Errorf(
1566+
"The * symbol cannot be used as a valid language inside functions")
1567+
}
15641568
function.Lang = val
15651569
expectLang = false
15661570
} else if function.Name != uid {
@@ -2130,6 +2134,14 @@ func parseLanguageList(it *lex.ItemIterator) ([]string, error) {
21302134
}
21312135
it.Prev()
21322136

2137+
for _, lang := range langs {
2138+
if lang == string(star) && len(langs) > 1 {
2139+
return nil, x.Errorf(
2140+
"If * is used, no other languages are allowed in the language list. Found %v",
2141+
langs)
2142+
}
2143+
}
2144+
21332145
return langs, nil
21342146
}
21352147

gql/parser_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2567,6 +2567,22 @@ func TestLangs(t *testing.T) {
25672567
require.Equal(t, []string{"en", "ru", "hu"}, gq.Query[0].Children[1].Langs)
25682568
}
25692569

2570+
func TestAllLangs(t *testing.T) {
2571+
query := `
2572+
query {
2573+
me(func: uid(1)) {
2574+
name@*
2575+
}
2576+
}
2577+
`
2578+
2579+
gq, err := Parse(Request{Str: query})
2580+
require.NoError(t, err)
2581+
require.Equal(t, 1, len(gq.Query[0].Children))
2582+
require.Equal(t, "name", gq.Query[0].Children[0].Attr)
2583+
require.Equal(t, []string{"*"}, gq.Query[0].Children[0].Langs)
2584+
}
2585+
25702586
func TestLangsInvalid1(t *testing.T) {
25712587
query := `
25722588
query {
@@ -2665,6 +2681,36 @@ func TestLangsInvalid7(t *testing.T) {
26652681
require.Contains(t, err.Error(), "Expected only one dot(.) while parsing language list.")
26662682
}
26672683

2684+
func TestLangsInvalid8(t *testing.T) {
2685+
query := `
2686+
query {
2687+
me(func: uid(1)) {
2688+
name@*:en
2689+
}
2690+
}
2691+
`
2692+
2693+
_, err := Parse(Request{Str: query})
2694+
require.Error(t, err)
2695+
require.Contains(t, err.Error(),
2696+
"If * is used, no other languages are allowed in the language list")
2697+
}
2698+
2699+
func TestLangsInvalid9(t *testing.T) {
2700+
query := `
2701+
query {
2702+
me(func: eqs(name@*, "Amir")) {
2703+
name@en
2704+
}
2705+
}
2706+
`
2707+
2708+
_, err := Parse(Request{Str: query})
2709+
require.Error(t, err)
2710+
require.Contains(t, err.Error(),
2711+
"The * symbol cannot be used as a valid language inside functions")
2712+
}
2713+
26682714
func TestLangsFilter(t *testing.T) {
26692715
query := `
26702716
query {

gql/state.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ const (
3838
colon = ':'
3939
lsThan = '<'
4040
grThan = '>'
41+
star = '*'
4142
)
4243

4344
// Constants representing type of different graphql lexed items.
@@ -338,7 +339,7 @@ func lexFilterFuncName(l *lex.Lexer) lex.StateFn {
338339
func lexDirectiveOrLangList(l *lex.Lexer) lex.StateFn {
339340
r := l.Next()
340341
// Check first character.
341-
if !isNameBegin(r) && r != period {
342+
if !isNameBegin(r) && r != period && r != star {
342343
return l.Errorf("Unrecognized character in lexDirective: %#U", r)
343344
}
344345
l.Backup()
@@ -543,6 +544,9 @@ func isLangOrDirective(r rune) bool {
543544
if r >= '0' && r <= '9' {
544545
return true
545546
}
547+
if r == '*' {
548+
return true
549+
}
546550
return false
547551
}
548552

query/query.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -991,6 +991,13 @@ func createTaskQuery(sg *SubGraph) (*pb.Query, error) {
991991
}
992992
}
993993
}
994+
995+
// If the lang is set to *, query all the languages.
996+
if len(sg.Params.Langs) == 1 && sg.Params.Langs[0] == "*" {
997+
sg.Params.expandAll = true
998+
sg.Params.Langs = nil
999+
}
1000+
9941001
out := &pb.Query{
9951002
ReadTs: sg.ReadTs,
9961003
Attr: attr,
@@ -1003,6 +1010,7 @@ func createTaskQuery(sg *SubGraph) (*pb.Query, error) {
10031010
FacetsFilter: sg.facetsFilter,
10041011
ExpandAll: sg.Params.expandAll,
10051012
}
1013+
10061014
if sg.SrcUIDs != nil {
10071015
out.UidList = sg.SrcUIDs
10081016
}

query/query0_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,18 @@ func TestQueryNamesInLanguage(t *testing.T) {
123123
js)
124124
}
125125

126+
func TestQueryAllLanguages(t *testing.T) {
127+
query := `{
128+
people(func: eq(name@hi, "अमित")) {
129+
name@*
130+
}
131+
}`
132+
js := processToFastJsonNoErr(t, query)
133+
require.JSONEq(t,
134+
`{"data":{"people": [{"name@en":"Amit", "name@hi":"अमित", "name":""}]}}`,
135+
js)
136+
}
137+
126138
func TestQueryNamesBeforeA(t *testing.T) {
127139
query := `{
128140
people(func: lt(name, "A")) {

0 commit comments

Comments
 (0)