From 3f31e5a61fed065643675c56763bc769f7b0b39f Mon Sep 17 00:00:00 2001 From: Sean Corfield Date: Sun, 12 Mar 2023 17:40:53 -0700 Subject: [PATCH] fix #478 --- CHANGELOG.md | 1 + src/honey/sql.cljc | 23 ++++++++++++++--------- src/honey/sql/helpers.cljc | 11 ++++++++++- test/honey/sql/postgres_test.cljc | 14 ++++++++++++++ 4 files changed, 39 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a46679..e5e07d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changes * 2.4.next in progress + * Fix [#478](https://github.com/seancorfield/honeysql/issues/478) by handling `:do-update-set` correctly in the `upsert` helper and by handling parameters correctly in the `:do-update-set` formatter. * Fix [#476](https://github.com/seancorfield/honeysql/issues/476) by adding support for multiple arguments to `:raw`, essentially restoring 1.x functionality (while still allowing for embedded vectors as expressions, introduced in 2.x). * 2.4.1002 -- 2023-03-03 diff --git a/src/honey/sql.cljc b/src/honey/sql.cljc index 771b05e..02e1989 100644 --- a/src/honey/sql.cljc +++ b/src/honey/sql.cljc @@ -898,16 +898,21 @@ (defn- format-do-update-set [k x] (cond (map? x) (if (or (contains? x :fields) (contains? x 'fields)) - (let [sets (str/join ", " - (map (fn [e] - (let [e (format-entity e {:drop-ns true})] - (str e " = EXCLUDED." e))) - (or (:fields x) - ('fields x)))) + (let [fields (or (:fields x) ('fields x)) + [sets & set-params] + (if (map? fields) + (format-set-exprs k fields) + [(str/join ", " + (map (fn [e] + (let [e (format-entity e {:drop-ns true})] + (str e " = EXCLUDED." e))) + fields))]) where (or (:where x) ('where x)) [sql & params] (when where (format-dsl {:where where}))] - (into [(str (sql-kw k) " " sets - (when sql (str " " sql)))] params)) + (-> [(str (sql-kw k) " " sets + (when sql (str " " sql)))] + (into set-params) + (into params))) (format-set-exprs k x)) (sequential? x) (let [[cols clauses] (split-with (complement map?) x)] @@ -2049,4 +2054,4 @@ (sql/register-fn! :foo foo-formatter) (sql/format {:select [:*], :from [:table], :where [:foo [:+ :a 1]]}) - ,) + ) diff --git a/src/honey/sql/helpers.cljc b/src/honey/sql/helpers.cljc index 9a2b8b1..90c8dca 100644 --- a/src/honey/sql/helpers.cljc +++ b/src/honey/sql/helpers.cljc @@ -1036,7 +1036,16 @@ (assoc :do-nothing do-nothing) do-update-set (assoc :do-update-set (if where - {:fields do-update-set + {:fields + (cond (and (= 1 (count do-update-set)) + (map? (first do-update-set))) + (first do-update-set) + (every? #(and (vector? %) + (= 2 (count %))) + do-update-set) + (into {} do-update-set) + :else + do-update-set) :where where} do-update-set)))))) diff --git a/test/honey/sql/postgres_test.cljc b/test/honey/sql/postgres_test.cljc index 9aad005..c6ff2b8 100644 --- a/test/honey/sql/postgres_test.cljc +++ b/test/honey/sql/postgres_test.cljc @@ -93,6 +93,20 @@ (upsert (-> (on-conflict (on-constraint :distributors_pkey)) do-nothing)) sql/format))) + (is (= ["INSERT INTO foo (id, data) VALUES (?, ?) ON CONFLICT (id) DO UPDATE SET DO UPDATE SET into = ((STATE(?), MODIFIED(NOW()))) WHERE state = ?" 1 42 "enabled" "disabled"] + (sql/format (-> (insert-into :foo) + (values [{:id 1 :data 42}]) + (upsert (-> (on-conflict :id) + (do-update-set [:state "enabled"] + [:modified [:now]]) + (where [:= :state "disabled"]))))))) + (is (= ["INSERT INTO foo (id, data) VALUES (?, ?) ON CONFLICT (id) DO UPDATE SET DO UPDATE SET state = ?, modified = NOW() WHERE state = ?" 1 42 "enabled" "disabled"] + (sql/format (-> (insert-into :foo) + (values [{:id 1 :data 42}]) + (upsert (-> (on-conflict :id) + (do-update-set {:state "enabled" + :modified [:now]}) + (where [:= :state "disabled"]))))))) (is (= ["INSERT INTO distributors (did, dname) VALUES (?, ?), (?, ?) ON CONFLICT (did) DO UPDATE SET dname = EXCLUDED.dname" 10 "Pinp Design" 11 "Foo Bar Works"] (sql/format {:insert-into :distributors :values [{:did 10 :dname "Pinp Design"}