在 hugsql 中使用 clojure 表达式构建 WHEN 子句
Building WHEN clause with a clojure expression in hugsql
我有一个包含 status
实体的数据库,我希望能够以多种不同方式获取该实体。因此,我想根据地图的内容构建查询的 WHEN
子句。
比如像这样:
(get-status *db* {:message_id 2 :user_id 1 :status "sent"})
;; or
(get-status *db* {:message_id 2})
;; or
(get-status *db* {:user_id 1})
;; etc.
我正在努力使用 hubsql 的 clojure expressions。我正在执行以下操作:
-- :name get-status
-- :doc fetch the status of a specific message
-- :command :query
-- :return :many
/* :require [clojure.string :as s] */
SELECT
*
FROM
message_status
/*~
(let [params (filter (comp some? val) params)]
(when (not (empty? params))
(str "WHERE "
(s/join ","
(for [[field value] params]
(str field " = " (keyword field)))))))
~*/
但是,这里是 hugsql 准备请求的方式:
=> (get-status-sqlvec {:message_id 2 :user_id 1})
["SELECT\n *\nFROM\n message_status\nWHERE ? = ?,? = ?" 2 2 1 1]
而我想要的是:
=> (get-status-sqlvec {:message_id 2 :user_id 1})
["SELECT\n *\nFROM\n message_status\nWHERE message_id = 2, user_id = 1"]
我终于成功了。上面的代码有两个问题。
首先,我们有
(s/join ","
(for [[field value] params]
(str field " = " (keyword field)))
因为field
是关键字,所以这实际上生成了这样的字符串::foo = :foo, :bar = :bar
。然后关键字被hugsql替换为?
。相反,我们想要的是构建这种字符串 foo = :foo, bar = :bar
,我们可以使用以下代码来完成:
(s/join ", "
(for [[field _] params]
(str (name field) " = " field))))))
第二个问题是 WHEN
子句甚至无效 SQL。上面的代码最终会生成如下请求:
SELECT * FROM message_status WHERE foo = 2, bar = 1
WHERE
子句中的逗号应该是AND
,所以最终(工作)代码是:
-- :name get-status
-- :doc fetch the status of a specific message
-- :command :query
-- :return :many
/* :require [clojure.string :as s] */
SELECT
*
FROM
message_status
/*~
(let [params (filter (comp some? val) params)]
(when (not (empty? params))
(str "WHERE "
(s/join " AND "
(for [[field _] params]
(str (name field) " = " field))))))
~*/
我有一个包含 status
实体的数据库,我希望能够以多种不同方式获取该实体。因此,我想根据地图的内容构建查询的 WHEN
子句。
比如像这样:
(get-status *db* {:message_id 2 :user_id 1 :status "sent"})
;; or
(get-status *db* {:message_id 2})
;; or
(get-status *db* {:user_id 1})
;; etc.
我正在努力使用 hubsql 的 clojure expressions。我正在执行以下操作:
-- :name get-status
-- :doc fetch the status of a specific message
-- :command :query
-- :return :many
/* :require [clojure.string :as s] */
SELECT
*
FROM
message_status
/*~
(let [params (filter (comp some? val) params)]
(when (not (empty? params))
(str "WHERE "
(s/join ","
(for [[field value] params]
(str field " = " (keyword field)))))))
~*/
但是,这里是 hugsql 准备请求的方式:
=> (get-status-sqlvec {:message_id 2 :user_id 1})
["SELECT\n *\nFROM\n message_status\nWHERE ? = ?,? = ?" 2 2 1 1]
而我想要的是:
=> (get-status-sqlvec {:message_id 2 :user_id 1})
["SELECT\n *\nFROM\n message_status\nWHERE message_id = 2, user_id = 1"]
我终于成功了。上面的代码有两个问题。
首先,我们有
(s/join ","
(for [[field value] params]
(str field " = " (keyword field)))
因为field
是关键字,所以这实际上生成了这样的字符串::foo = :foo, :bar = :bar
。然后关键字被hugsql替换为?
。相反,我们想要的是构建这种字符串 foo = :foo, bar = :bar
,我们可以使用以下代码来完成:
(s/join ", "
(for [[field _] params]
(str (name field) " = " field))))))
第二个问题是 WHEN
子句甚至无效 SQL。上面的代码最终会生成如下请求:
SELECT * FROM message_status WHERE foo = 2, bar = 1
WHERE
子句中的逗号应该是AND
,所以最终(工作)代码是:
-- :name get-status
-- :doc fetch the status of a specific message
-- :command :query
-- :return :many
/* :require [clojure.string :as s] */
SELECT
*
FROM
message_status
/*~
(let [params (filter (comp some? val) params)]
(when (not (empty? params))
(str "WHERE "
(s/join " AND "
(for [[field _] params]
(str (name field) " = " field))))))
~*/