我正在尝试根据我传递给函数的列和值映射生成 korma 查询条件。
我发现当一张空地图传递给 korma 时,其中:
(select "things"
(where conditions))
生成带有空 WHERE 的查询,从而导致 SQL 错误:
SELECT * FROM things WHERE () LIMIT 10
但是,使用此表单:
(select "things"
(if-not (empty? conditions)
(where conditions)))
导致错误:"传递到:core$where 的参数数 (1) 错误"
在 korma 中是否有处理动态子句的惯用方法?
更新
以下工作,但非常笨拙(注意奇怪的必要 if 格式)
(defn do-select []
(-> (select* "things")
(fields :id :data)
(limit 10)))
(defn add-constraints [query conditions]
(if (empty? conditions)
query
(where query (conditions-to-clause-map conditions))))
(select (do-select)
(add-constraints conditions)
(where (is_owner? owner)))
我认为是否可以在不查看 korma 并尝试调用一些私有 API 的情况下生成动态查询,但这是一个坏主意。第二个代码的问题在于select
和where
是宏。选择的作用是:
(defmacro select
[ent & body]
`(let [query# (-> (select* ~ent)
~@body)]
(exec query#)))
如您所见,它将select*
返回值线程化到下一个表单,如果您引入导致此线程中断的 if
子句,并且where
只获得一个值(这是您的映射)而不是 select* 和映射的获取值,因此错误说参数数量错误。
到目前为止,似乎eval
一些动态代码生成是您的朋友。像这样:
(eval `(select "things"
~(if (empty? conditions)
`identity
`(where conditions))))
我还没有尝试过,但我希望它能给你带来想法。
起初有点奇怪,但牢记"代码即数据"的口头禅,我创建了一个"my-where"函数,该函数要么传递无条件的原始查询,要么插入真正的 korma where 子句作为结果。
像这样:
(defn my-where [query conditions]
(if-not (nil? conditions)
(-> query (where conditions))
query))
然后你可以使用:
(select "things"
(my-where conditions))
希望这有帮助,
格雷格
你可能已经找到了解决这个问题的方法,但我会插话。就我个人而言,我最终使用了 cond-> 宏,如果您使用的是 Clojure 1.6+,则可以使用该宏。
您可以在此处找到有关新线程宏的信息。
生成的代码如下所示:
(let [query (->(select* "things")
(fields :id :data)
(limit 10))]
(-> (cond-> query
conditions (where conditions)
more-conditions (where more-conditions))
(exec)))