撰写clojure honeysql where子句

时间:2013-09-15 21:09:11

标签: sql map clojure

起初我对clojure很新。 所以,我正在尝试使用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"]

我有函数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

我认为问题出在build-clause函数中,它返回

[:or ([:= :name "foo"] [:= :name "bar"])]

我想要这个:

[:or [:= :name "foo"] [:= :name :bar]]

我应该如何以正确的方式重写build-clause?列表展开了吗?

2 个答案:

答案 0 :(得分:7)

你是对的,map函数是插入一个列表作为第二个元素,而不是按你的意图插入。

试试这个:

(defn build-clause2 [names]
  (into [:or] (map #(vector := :name %) names)))

或者:

(defn build-clause2 [names]
  (apply conj [:or] (map #(vector := :name %) names)))

或者:

(defn build-clause2 [names]
  (reduce conj [:or] (map #(vector := :name %) names)))

所有这些都会达到相同的效果,所以在这种情况下更多的是品味。

此外,build-clausehoneysql.helpers命名空间中的多方法。当您honeysql.helpers :refer :all时,您可以创建名称冲突。

答案 1 :(得分:7)

还有merge-where可以用来合并字段。它也接受null,因此可以将它捆绑起来:

(->
  (select :*)
  (from :test)
  (merge-where (if (> id 0) [:= :id id]))
  (merge-where (if-not (nil? src) [:= :src src]))
  sql/format)

我只是觉得我会指出这一点,因为我花了一点时间才弄明白。