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.