Disjoint OR clauses in advanced query

I’ve defined a “task” in logseq as any item with a marker that isn’t DONE that has at least one of the following attributes:

  • It is scheduled or has a deadline
  • It references a page called #task
  • It is the top-level marked block (i.e. no parent has a marker). This is to prevent “inner TODOs” from clogging up my list.

I have three queries that will independently find these 3 types of tasks, but I want to join them into one query, and I need help understanding how to do that (because the or clause or or-join are complaining that clauses aren’t unified).

Here is my attempt at this joined query

{
:title [:h1 "Big Ol' Joined Query"]
:query [
:find (pull ?block [*])
:in $ %
:where
[?block :block/marker ?marker]
[(contains? #{"TODO", "DOING"} ?marker)]
(or

; Case 1: no ancestor contains a marker
(not (ancestor ?block ?ancestor)
[?ancestor :block/marker ?amarker]
[(contains? #{"TODO", "DOING", "DONE", "WAITING", "NOW", "LATER"} ?amarker)]
)

; Case 2: the block references to the #task page
(and
[?block :block/ref-pages ?page]
[?page :block/name "task"]
)

; Case 3: the block is scheduled or has a deadline
[?block :block/scheduled ?day]
[?block :block/deadline ?day]
)
]
:breadcrumb-show? false
:collapsed? false
:inputs
    [[[[ancestor ?b ?ancestor]
				[?b :block/parent ?ancestor]]
				[[ancestor ?b ?ancestor]
				[?child :block/parent ?ancestor]
				(ancestor ?b ?child)]]]
}

However, this query complains that I must use the same sort of free variables in all clauses in the OR clause.

If I try to use or-join, it complains that I’m not unifying all variables in all clauses (e.g. ?ancestor and ?day).

What is the most idiomatic way to check for multiple disjoint conditions like this?

Welcome. Some questions:

  • Is case “scheduled or has a deadline” actually 2 separate cases?
  • How do you write the or-join ?
    • Is it or-join [?block] ?

I didn’t understand or-join, but I tried your or-join [?block] suggestion and that worked!

I hadn’t really understood what the variables block in or-join did, so I was trying to unify too many variables.

For posterity, this is the version of my original query that worked.


:title [:h1 "Big Ol' Joined Query"]
:query [
:find (pull ?block [*])
:in $ %
:where
[?block :block/marker ?marker]
[(contains? #{"TODO", "DOING"} ?marker)]
(or-join [?block] ; <- this is the solution!

; Case 1: no ancestor contains a marker
(not (ancestor ?block ?ancestor)
[?ancestor :block/marker ?amarker]
[(contains? #{"TODO", "DOING", "DONE", "WAITING", "NOW", "LATER"} ?amarker)]
)

; Case 2: the block references to the #task page
(and
[?block :block/ref-pages ?page]
[?page :block/name "task"]
)

; Case 3: the block is scheduled or has a deadline
[?block :block/scheduled ?day]
[?block :block/deadline ?day]
)
]
:breadcrumb-show? false
:collapsed? false
:inputs
    [[[[ancestor ?b ?ancestor]
				[?b :block/parent ?ancestor]]
				[[ancestor ?b ?ancestor]
				[?child :block/parent ?ancestor]
				(ancestor ?b ?child)]]]
}