diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fee900..c124093 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changes * 2.4.next in progress + * Fix [#494](https://github.com/seancorfield/honeysql/issues/494) by supporting expressions in `:on-conflict` instead of just entities. * Address [#493](https://github.com/seancorfield/honeysql/issues/493) by clarifying use of `:values` in CTEs (using `:with`). * Address [#489](https://github.com/seancorfield/honeysql/issues/489) by adding more examples around `:update`. * Update dev/test dependencies. diff --git a/doc/clause-reference.md b/doc/clause-reference.md index 38ed555..2d37f38 100644 --- a/doc/clause-reference.md +++ b/doc/clause-reference.md @@ -1099,10 +1099,11 @@ as if they are separate clauses but they will appear in pairs: `ON ... DO ...`. `:on-conflict` accepts a sequence of zero or more -SQL entities (keywords or symbols), optionally +SQL expressions, optionally followed by a single SQL clause (hash map). It can also accept either a single SQL entity or a single SQL clause. -The SQL entities are column names and the SQL clause can be an +The SQL expressions can be just column names or function calls etc, +and the SQL clause can be an `:on-constraint` clause or a`:where` clause. _[For convenience of use with the `on-conflict` helper, this clause can also accept any of those arguments, wrapped in a sequence; it can also accept an empty sequence, and just produce `ON CONFLICT`, so that it can be combined with other clauses directly]_ diff --git a/src/honey/sql.cljc b/src/honey/sql.cljc index 4642810..5c7e1fb 100644 --- a/src/honey/sql.cljc +++ b/src/honey/sql.cljc @@ -881,23 +881,26 @@ (defn- format-on-conflict [k x] (if (sequential? x) - (let [entities (take-while ident? x) - n (count entities) + (let [exprs (take-while (complement map?) x) + n (count exprs) [clause & more] (drop n x) - _ (when (or (seq more) - (and clause (not (map? clause)))) + _ (when (seq more) (throw (ex-info "unsupported :on-conflict format" {:clause x}))) - [sql & params] (when clause - (format-dsl clause))] - (into [(str (sql-kw k) - (when (pos? n) - (str " (" - (str/join ", " (map #'format-entity entities)) - ")")) - (when sql - (str " " sql)))] - params)) + [sqls expr-params] + (when (seq exprs) + (format-expr-list exprs)) + [sql & clause-params] + (when clause + (format-dsl clause))] + + (-> [(str (sql-kw k) + (when (pos? n) + (str " (" (str/join ", " sqls) ")")) + (when sql + (str " " sql)))] + (into expr-params) + (into clause-params))) (format-on-conflict k [x]))) (defn- format-do-update-set [k x] diff --git a/test/honey/sql_test.cljc b/test/honey/sql_test.cljc index 242d9a4..e86fef1 100644 --- a/test/honey/sql_test.cljc +++ b/test/honey/sql_test.cljc @@ -772,13 +772,13 @@ DO NOTHING INSERT INTO customers (name, email) VALUES ('Microsoft', 'hotline@microsoft.com') -ON CONFLICT (name, email) +ON CONFLICT (name, TRIM(email)) DO NOTHING "] (format {:insert-into :customers :columns [:name :email] :values [[[:inline "Microsoft"], [:inline "hotline@microsoft.com"]]] - :on-conflict [:name :email] + :on-conflict [:name [:trim :email]] :do-nothing true} {:pretty true}))) (is (= ["