Query a Graph

Use this guide once you are comfortable asserting Edge(...) facts.

Step 1. Load Facts in the Same Program

select source, target
from liquid.query($$
  Edge("a", "path", "b").
  Edge("b", "path", "c").
  Edge("c", "path", "d").
  Edge(source, "path", target)?
$$) as t(source text, target text)
order by 1, 2;

Step 2. Add Query-Local Rules

select target
from liquid.query($$
  Edge("a", "path", "b").
  Edge("b", "path", "c").
  Edge("c", "path", "d").

  Reach(x, y) :- Edge(x, "path", y).
  Reach(x, z) :- Reach(x, y), Reach(y, z).

  Reach("a", target)?
$$) as t(target text)
order by 1;

Step 3. Reverse the Query Direction

select source
from liquid.query($$
  Edge("a", "path", "b").
  Edge("b", "path", "c").
  Edge("c", "path", "d").

  Reach(x, y) :- Edge(x, "path", y).
  Reach(x, z) :- Reach(x, y), Reach(y, z).

  Reach(source, "d")?
$$) as t(source text)
order by 1;

Step 4. Combine Multiple Predicates

select person, skill
from liquid.query($$
  Edge("alice", "works_on", "project:search").
  Edge("alice", "uses", "postgres").
  Edge("bob", "works_on", "project:search").
  Edge("bob", "uses", "typescript").

  TeamSkill(person, skill) :-
    Edge(person, "works_on", "project:search"),
    Edge(person, "uses", skill).

  TeamSkill(person, skill)?
$$) as t(person text, skill text)
order by 1, 2;

Step 5. Watch for Scope Rules

  • top-level assertions run before the query
  • rules are local to one liquid.query(...) call
  • only one terminal query is allowed

Useful Patterns

  • reachability and ancestry
  • dependency traversal
  • workflow state transitions
  • ontology subclass closure

Next