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, whilereduce
always 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
apply
at all? This should work equally well:One last suggestion - when you
require
clojureql.predicates, if you replaceclojureql.predicates
with[clojurecl.predicates :as qlp]
, you can useqlp
in place ofclojureql.predicates
in the rest of the file, which makes the above (if we also replaceclojureql.core
withqlc
):which is much easier to read.
For the purposes of ClojureQL, try
(apply clojureql.predicates/or* ...)
and(apply clojureql.predicates/and* ...)
. clojureql'swhere
replaces anyand
andor
it 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.