Recurse and query variables

I have some triples representing the AST of a super simple mock program:

mutation {
  set {
   _:a <name> "a" .
   _:b <name> "b" .
   _:c <name> "c" .
   _:d <name> "d" .
   _:e <name> "e" .

   _:a <child> _:b .
   _:b <child> _:c .
   _:c <child> _:d .
   _:d <child> _:e .
   
   _:a <type> "astnode" .
   _:b <type> "astnode" .
   _:c <type> "astnode" .
   _:d <type> "astnode" .
   _:e <type> "astnode" .

   _:a <kind> "file" .
   _:b <kind> "class" .
   _:c <kind> "func" .
   _:d <kind> "if" .
   _:e <kind> "var" .
  }
}

The actual data is a more complex tree, and obviously files can contain multiple classes etc.

I would like to create queries that start at a given point in the tree, and traverse children recursively to find elements of various kinds with various properties.

For instance, can I find all descendants of file of type func?

I tried:

{
  file as f(func: eq(type, "astnode")) {
    @filter(eq(kind, "file"))
    name
  }

  recurse(func: eq(type, "astnode")) {
    @filter(uid(file))
    name
    filechildren as child
  }

  vars(func: uid(filechildren)) {
    @filter(eq(kind: "func"))
    kind
    name
  }
}

But the filechildren variable is only ever set to the uid of the class node. And if I set the filechildren variable like this instead:

filechildren as recurse(func: eq(type, "astnode")) {
    @filter(uid(file))
    name
    child
}

Then the filechildren variable will only take the value of the uid of the file node.

In either case, the second block returns the full set of children, but on sets the first child to the filechildren variable. So it seems that variables are only assigned in the first application of the recursive block.

1 Like

Hey @BlakeMScurr

You are right. In v0.8.2, variables are only assigned in the first application of a recursive block. Though after Aggregate uids stored in a variable over levels for recurse query. · dgraph-io/dgraph@fadfe05 · GitHub which would be part of the next release and is already in master they would be aggregated over different levels. Then you could do something like

{
  recurse(func: uid(file)) {
    funcChildren as child @filter(eq(kind, "func"))
  }

  me(func: uid(funcChildren)) {
    name
  }
}

To get names of all children of the given file which have kind func.

1 Like

Thanks very much @pawan! That looks perfect, I’ll try it now.

Awesome thank you very much! This final query works for me:

{
  file as f(func: eq(type, "astnode")) {
    @filter(eq(kind, "file"))
  }

  recurse(func: uid(file)) {
    funcChildren as child
  }

  me(func: uid(funcChildren)) {
    @filter(eq(kind, "func"))
    name
  }
}

Interestingly, funcChildren as child @filter(eq(kind, "func")) never assigned anything to funcChildren, so I filtered in the next block instead.

That’s a bit strange. Could you please file a bug with steps to reproduce if possible?

Perhaps this is not a bug. If we filter on the child having a particular kind=func in the recurse block, and the immediate child node _:b does not have kind=func, shouldn’t the recurse just not apply again?

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.