3

我正在尝试根据传递给函数的列和值的映射生成 korma 查询条件。

我发现当一张空地图被传递到 korma's where 时:

(select "things"
  (where conditions))

生成带有空 WHERE 的查询,这会导致 SQL 错误:

SELECT * FROM things WHERE () LIMIT 10 

但是使用这种形式:

(select "things"
  (if-not (empty? conditions) 
    (where conditions)))

导致错误:“传递给的参数 (1) 数量错误:core$where”

是否有一种惯用的方式来处理 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)))     
4

3 回答 3

3

我不认为如果不查看 korma 的引擎盖并尝试调用一些私有 API 就可以生成动态查询,但这是一个坏主意。你的第二个代码的问题selectwhere宏。select 的作用是:

(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))))

我还没有尝试过,但我希望它能给你这个想法。

于 2012-06-09T14:16:43.967 回答
1

您可能已经找到了解决此问题的方法,但我会插话。就个人而言,我最终使用 cond-> 宏,如果您使用 Clojure 1.6+,则该宏可用。

您可以在此处找到有关新线程宏的信息。

生成的代码如下所示:

(let [query (->(select* "things") 
                 (fields :id :data)
                 (limit 10))]
  (-> (cond-> query
         conditions (where conditions)
         more-conditions (where more-conditions))
      (exec)))
于 2014-03-21T20:07:39.100 回答
1

一开始有点奇怪,但牢记“代码即数据”的口头禅,我创建了一个“my-where”函数,它要么传递无条件的原始查询,要么插入一个真正的 korma where 子句作为结果。

就像是:

(defn my-where [query conditions]
  (if-not (nil? conditions)
    (-> query (where conditions))
    query))

然后你可以使用:

(select "things"
  (my-where conditions))

希望这会有所帮助,
格雷格

于 2012-09-19T21:15:37.543 回答