I have a database with a status entity that I'd like to be able to fetch in many different ways. As a result, I'd like to build the WHEN clause of my query based on the content of a map.
For instance, like this:
(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.
I'm struggling using hubsql's clojure expressions. I am doing the following:
-- :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)))))))
~*/
However, here is how the request is prepared by hugsql:
=> (get-status-sqlvec {:message_id 2 :user_id 1})
["SELECT\n *\nFROM\n message_status\nWHERE ? = ?,? = ?" 2 2 1 1]
Whereas I want something like:
=> (get-status-sqlvec {:message_id 2 :user_id 1})
["SELECT\n *\nFROM\n message_status\nWHERE message_id = 2, user_id = 1"]
I finally managed to get this working. The above code had two issues.
First, we have
Since
fieldis a keyword, this actually generates this kind of string::foo = :foo, :bar = :bar. The keywords are then replaced by?by hugsql. What we want instead is build this kind of stringfoo = :foo, bar = :bar, which we can do with this code:The second problem is that the
WHENclause is not even valid SQL. The above code ends up generating requests such as:The commas in the
WHEREclause should beAND, so the final (working) code is: