honeysql

slipset 2023-12-15T12:54:06.775609Z

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) 2023-12-15T12:56:50.901459Z

👋 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 ☝️

nbardiuk 2023-12-15T13:16:45.690889Z

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) 2023-12-15T13:19:19.332349Z

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.

isak 2023-12-15T15:44:15.416909Z

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.

seancorfield 2023-12-15T16:16:29.965509Z

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
seancorfield 2023-12-15T16:20:22.579989Z

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]

Jakub Holý (HolyJak) 2023-12-18T22:40:52.184439Z

thank you!