Fork me on GitHub
#honeysql
<
2023-12-15
>
slipset12:12:06

My colleague @holyjak just discovered (for us) unnest (https://blog.jakubholy.net/2023/pg-select-where-match-on-list-of-tuples/) Is there a way to express this in honey?

Jakub Holý (HolyJak)12:12:50

👋 How do I write JOIN UNNEST(?, ?) AS as x(ws,t) with honey? Currently I cheat with [[:unnest "arg1" "arg2"] [[:raw "as x(ws,t)"]]] . I see that also [... [[:x :ws :t]]] works, with the disadvantage that it ends up as AS X(ws, t) , i.e. a capital X. This will also answer Slipset ☝️

nbardiuk13:12:45

unnest and alias syntax look like function call, and honeysql is happy to generate it. Although I don't know if this case is officially supported

(let [id+ver-pairs [['a' 1] ['b' 20] ['c' 1]]
      ids (map first id+ver-pairs)
      versions (map last id+ver-pairs)]
    (->> {:select :*
          :from [[:thing :t]]
          :join [[[:unnest [:array ids] [:array versions]] [[:x :id :version]]]
                 [:and [:= :x.id :w.id] [:= :x.name :w.name]]]}
         (next.jdbc/execute! conn)))

Jakub Holý (HolyJak)13:12:19

Yes, that is what I am mentioning above. The only disadvantage is that it ends up capitalizing the alias, so as X(ws,t) in my case. But since it is unquoted then its case does not matter, and in honey-generated quoted result "x"."t" will work.

isak15:12:15

Cool approach. I've been using I've been using json_to_recordset for that instead (so you just pass json array of objects (e.g., join json_to_recordset(?::json) as b(id int, state int) on a.id = b.id and ...) ). But I assume your way is more efficient.

seancorfield16:12:29

You can use :'x to keep x as lowercase. Example in 🧵 (and maybe in future, can folks use threads for follow-ups/replies please)

👌 1
🙏 1
seancorfield16:12:22

user=> (let [id+ver-pairs [["a" 1] ["b" 20] ["c" 1]]
      ids (map first id+ver-pairs)
      versions (map last id+ver-pairs)]
    (->> {:select :*
          :from [[:thing :t]]
          :join [[[:unnest [:array ids] [:array versions]] [[:'x :id :version]]]
                 [:and [:= :x.id :w.id] [:= :x.name :w.name]]]}
      (sql/format)))
["SELECT * FROM thing AS t INNER JOIN UNNEST(ARRAY[?, ?, ?], ARRAY[?, ?, ?]) AS x(id, version) ON (x.id = w.id) AND (x.name = w.name)" "a" "b" "c" 1 20 1]