at first i'm really new to clojure. So, I'm trying to dynamically compose query with honeysql:
(:use [honeysql.core :as sql]
[honeysql.helpers :refer :all])
(sql/format {:select [:*] :from [:test]
:where [:or [:= :name "foo"]
[:= :name "bar"]]})
;; ["SELECT * FROM test WHERE (name = ? OR name = ?)" "foo" "bar"]
and i have function build-clause:
(defn build-clause [names]
[:or (map #(vector := :name %) names)])
(sql/format {:select [:*]
:from [:test]
:where (build-clause ["foo" "bar"])})
;; ClassCastException clojure.lang.PersistentVector cannot be cast to clojure.lang.Named
i thinks the problem is in build-clause function which returns
[:or ([:= :name "foo"] [:= :name "bar"])]
and i'd like to this one:
[:or [:= :name "foo"] [:= :name :bar]]
how should i rewrite build-clause in right way please? kind of list unroll?
You are correct, the map function is inserting a list as the second element, instead of inserting as you intended.
Try this:
(defn build-clause2 [names]
(into [:or] (map #(vector := :name %) names)))
Or:
(defn build-clause2 [names]
(apply conj [:or] (map #(vector := :name %) names)))
Or:
(defn build-clause2 [names]
(reduce conj [:or] (map #(vector := :name %) names)))
All of these will achieve the same result, so it is more a matter of taste in this case.
Also, build-clause
is a multi-method in the honeysql.helpers
namespace. When you honeysql.helpers :refer :all
you can create a name conflict.
There's also merge-where
which can be used to, well, merge where fields. It also accepts null, so that it's possible to bundle it up like this:
(->
(select :*)
(from :test)
(merge-where (if (> id 0) [:= :id id]))
(merge-where (if-not (nil? src) [:= :src src]))
sql/format)
I just thought I'd point that out, because it took a little too long for me to figure that out.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With