Построение предложения WHEN с выражением clojure в 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.

Я борюсь с использованием выражений clojure hubsql. Я делаю следующее:

-- :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"]

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))))))
~*/
Другие вопросы по тегам