I need to generate the following:
(clojureql.core/join (clojureql.core/table db :tableA) (clojureql.core/table db :tableA)
(clojureql.core/where (apply and (= :tableA.id :tableB.id)
[(apply or [(clojureql.predicates/in :tableA.id [1 2])
(clojureql.predicates/in :tableA.id [3 4])])])))
But the “apply or” form needs to be “passed” from another function or macro. Here’s what I mean:
(clojureql.core/join (clojureql.core/table db :tableA) (clojureql.core/table db :tableA)
(clojureql.core/where (apply and (= :tableA.id :tableB.id)
[(my-or-f)])))
where this function is:
(defn my-or-f []
(apply or [(clojureql.predicates/in :tableA.id [1 2])
(clojureql.predicates/in :tableA.id [3 4])]))
however this function throws this exception:
#<CompilerException java.lang.Exception: Can't take value of a macro: #'clojure.core/or (NO_SOURCE_FILE:2)>
I’ve also tried using a macro. It compiles but it throws the same exception when I try running the query using this macro
(defmacro my-or-f []
`(apply or [(clojureql.predicates/in :tableA.id [1 2])
(clojureql.predicates/in :tableA.id [3 4])]))
Is there another way that I could use the “apply or”?
Thanks.
The issue is that macros are not functions – they run at compile time and are passed the actual syntax (lists and symbols, primarily), so you can’t apply them at runtime to runtime datastructures. Thus,
(apply or my-list)throws an error. You have a few options:In practice, you probably want
some— it stops as soon as it reaches an element that returns true, whilereducealways traverses the entire list.Note: you will also have the same problem with your
(apply and ...)—(every? identity ...)will do what you want.In this case, however, why do you need to use
applyat all? This should work equally well:One last suggestion – when you
requireclojureql.predicates, if you replaceclojureql.predicateswith[clojurecl.predicates :as qlp], you can useqlpin place ofclojureql.predicatesin the rest of the file, which makes the above (if we also replaceclojureql.corewithqlc):which is much easier to read.
For the purposes of ClojureQL, try
(apply clojureql.predicates/or* ...)and(apply clojureql.predicates/and* ...). clojureql’swherereplaces anyandandorit sees withclojureql.predicates/and*andclojureql.or*, so doing this replacement yourself should work. Bothand*andor*are functions, not macros, so there shouldn’t be any issues.