How can I make HoneySQL handle order by as a compound key?

亡梦爱人 提交于 2019-12-06 07:19:32

First you need to look at the format behavior on order-by

(sql/format {:order-by [:c1 :c2]}) 
=> ["ORDER BY c1, c2"]
(sql/format {:order-by [[:c1 :desc] :c2]})
=> ["ORDER BY c1 DESC, c2"]

that is the struct about order-by which will be generated.

If you look at the macro defhelper it will do two things.

  1. defrecord for the spec type
  2. define a function to call the mutimethod

(do (defmethod build-clause :order-by [_ m fields] (assoc m :order-by (collify fields))) (defn order-by [& args__14903__auto__] (let [[m__14904__auto__ args__14903__auto__] (if (plain-map? (first args__14903__auto__)) [(first args__14903__auto__) (rest args__14903__auto__)] [{} args__14903__auto__])] (build-clause :order-by m__14904__auto__ args__14903__auto__))) (alter-meta! #'order-by assoc :arglists '([fields] [m fields])))

The collify is very simple.

 (defn collify [x]
     (if (coll? x) x [x]))

So , we need to look at defn order-by function . When you call (sqlh/merge-order-by {} [:a :b]),

args__14903__auto__ = '({} [:a :b])

The first if will create two var m__14904__auto__ = {} and args__14903__auto__ = (rest args__14903__auto__) = ([:a :b]).

So, I guess the merge-order-by function is wrong.

I solve your problem like this.

(sql/format
  (->
    (sqlh/select :*)
    (sqlh/from :event)
    (sqlh/merge-where [:in :field_id ["1673576", "1945627", "1338971"]])
    (sqlh/merge-where [:in :layer ["fha.abs" "fha.rank" "fha.true-color"]])
    (sqlh/merge-order-by [:field_id :desc] :layer :event_date)
    (sqlh/limit 5)))

Its been over 2 years, but I finally know enough Clojure and have worked with HoneySQL long enough to see what my younger self was missing. It didn't want the compound key as a vector: sqlh/order-by is variadic:

(doc sqlh/order-by)
-------------------------
honeysql.helpers/order-by
([& fields] [m & fields])
  nil

What it really wanted was (sqlh/order-by :field_id :layer [:event_date :desc]). The vector was only needed to make a specific field sort DESC.

So this was what I was trying to do:

(-> (sqlh/select :*)
    (sqlh/from :event)
    (sqlh/merge-where [:in :field_id field-ids])
    (sqlh/merge-where (cond (not-empty layers) [:in :layer layers]))
    (sqlh/merge-where (make-where-for-timestamp
                        :event_date event-date-from event-date-to))
    (sqlh/merge-where (make-where-for-timestamp
                        :updated_at updated-at-from updated-at-to))
    (sqlh/order-by :field_id :layer [:event_date :desc])
    sql/format)
=>
["SELECT * FROM event WHERE ((field_id in (?)) AND (layer in (?, ?, ?))) ORDER BY field_id, layer, event_date DESC"
 "1325629"
 "fha.true-color"
 "fha.abs"
 "fha.rank"]

@savior was correct at https://stackoverflow.com/a/40356529/688355 all along. My Clojure wasn't good enough to understand it.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!