Skip to content

Commit

Permalink
Allow the result of count(uid) to be assigned to a var. (#2947)
Browse files Browse the repository at this point in the history
Allow expressions of the form "f as count(uid)".

When resolving the value of such a variable inside a math block it gets
treated as a constant.
  • Loading branch information
martinmr authored Jan 30, 2019
1 parent 553d76d commit 64c681a
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 14 deletions.
4 changes: 1 addition & 3 deletions gql/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -2641,11 +2641,9 @@ func godeep(it *lex.ItemIterator, gq *GraphQuery) error {
goto Fall
}

if varName != "" {
return it.Errorf("Cannot assign variable to count()")
}
count = notSeen
gq.UidCount = true
gq.Var = varName
if alias != "" {
gq.UidCountAlias = alias
}
Expand Down
11 changes: 0 additions & 11 deletions gql/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3663,17 +3663,6 @@ func TestCountAtRootErr(t *testing.T) {
}

func TestCountAtRootErr2(t *testing.T) {
query := `{
me(func: uid( 1)) {
a as count(uid)
}
}`
_, err := Parse(Request{Str: query})
require.Error(t, err)
require.Contains(t, err.Error(), "Cannot assign variable to count()")
}

func TestCountAtRootErr3(t *testing.T) {
query := `{
me(func: uid( 1)) {
count()
Expand Down
19 changes: 19 additions & 0 deletions query/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -1227,6 +1227,14 @@ func (sg *SubGraph) transformVars(doneVars map[string]varValue, path []*SubGraph
if err != nil {
return err
}

// This is the result of setting the result of count(uid) to a variable.
// Treat this value as a constant.
if val, ok := newMap[math.MaxUint64]; ok && len(newMap) == 1 {
mt.Const = val
continue
}

mt.Val = newMap
}
return nil
Expand Down Expand Up @@ -1488,6 +1496,17 @@ func (sg *SubGraph) populateUidValVar(doneVars map[string]varValue, sgPath []*Su
}
doneVars[sg.Params.Var].Vals[uid] = val
}
} else if sg.Params.uidCount {
doneVars[sg.Params.Var] = varValue{
Vals: make(map[uint64]types.Val),
path: sgPath,
}

val := types.Val{
Tid: types.IntID,
Value: int64(len(sg.DestUIDs.Uids)),
}
doneVars[sg.Params.Var].Vals[math.MaxUint64] = val
} else if len(sg.DestUIDs.Uids) != 0 || (sg.Attr == "uid" && sg.SrcUIDs != nil) {
// Uid variable could be defined using uid or a predicate.
uids := sg.DestUIDs
Expand Down
56 changes: 56 additions & 0 deletions query/query0_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1656,6 +1656,62 @@ func TestNestedFuncRoot4(t *testing.T) {
require.JSONEq(t, `{"data": {"me":[{"name":"Rick Grimes"},{"name":"Andrea"}]}}`, js)
}

func TestCountUidToVar(t *testing.T) {
query := `
{
var(func: has(school), first: 3) {
f as count(uid)
}
me(func: uid(1)) {
score: math(f)
}
}
`
js := processToFastJsonNoErr(t, query)
require.JSONEq(t, `{"data": {"me":[{"score": 3}]}}`, js)
}

func TestCountUidToVarMultiple(t *testing.T) {
query := `
{
var(func: has(school), first: 3) {
f as count(uid)
}
var(func: has(follow), first: 4) {
g as count(uid)
}
me(func: uid(1)) {
score: math(f + g)
}
}
`
js := processToFastJsonNoErr(t, query)
require.JSONEq(t, `{"data": {"me":[{"score": 7}]}}`, js)
}

func TestCountUidToVarCombinedWithNormalVar(t *testing.T) {
query := `
{
var(func: has(school), first: 3) {
f as count(uid)
}
var(func: has(follow)) {
g as count(path)
}
me(func: uid(1)) {
score: math(f + g)
}
}
`
js := processToFastJsonNoErr(t, query)
require.JSONEq(t, `{"data": {"me":[{"score": 5}]}}`, js)
}

var maxPendingCh chan uint64

func TestMain(m *testing.M) {
Expand Down

0 comments on commit 64c681a

Please sign in to comment.