trydatomic

Chapters

Or Clauses

Pattern clauses in :where are implicitly joined with AND: every clause must match. To express OR logic, Datomic Datalog provides or and or-join.

or

or succeeds when at least one of its branches matches. All branches must use the same set of variables. Let's find Pokemon that are Fire or Water type:

Query
[:find ?name :where [?e :pokemon/name ?name] (or [?e :pokemon/type "Fire"] [?e :pokemon/type "Water"])]

Try adding a third branch for "Electric".

or-join

or-join works like or but you declare explicitly which outer variables each branch must bind. This is required when branches introduce different local variables.

Here we find Pokemon that are either Electric-type or have a speed above 100. The second branch introduces ?speed which only exists inside that branch, so plain or would not work:

Query
[:find ?name :where [?e :pokemon/name ?name] (or-join [?e] [?e :pokemon/type "Electric"] (and [?e :stat/speed ?speed] [(> ?speed 100)]))]

The [?e] in or-join declares that ?e is the only variable that must unify with the outer query. ?speed is a local variable that lives only inside its branch.

TRY

Change or-join [?e] above to plain or and run it. Datomic refuses: All clauses in 'or' must use same set of vars. ?speed only exists in the second branch, so the two branches disagree on which variables they share; or-join gets around this by declaring up front which ones actually are shared. Modify the or-join query to find Pokemon that are Ground-type or have attack above 120.

You can now
  • Match rows against any of several alternatives with or.
  • Know why or requires every branch to use the same set of variables.
  • Use or-join to let branches introduce their own local variables, declaring only what's shared with the outer query.