From ba336f2884cbcac4025370bd0687fdc21da269ff Mon Sep 17 00:00:00 2001 From: Sean Corfield Date: Thu, 10 Aug 2023 19:31:17 -0700 Subject: [PATCH] clarify :values clause behavior with columns also add more examples to the RCF at the bottom of honey.sql. --- CHANGELOG.md | 3 +++ doc/clause-reference.md | 33 +++++++++++++++++++++++++++++---- src/honey/sql.cljc | 15 +++++++++++++++ 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a6b595..48e8715 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changes +* 2.4.next in progress + * Attempt to clarify the formatting behavior of the `:values` clause when used to produce column names. + * 2.4.1045 -- 2023-06-25 * Address [#495](https://github.com/seancorfield/honeysql/issues/495) by adding (experimental) `formatf` function -- purely for discussion: may be removed in a subsequent release! * Fix [#494](https://github.com/seancorfield/honeysql/issues/494) by supporting expressions in `:on-conflict` instead of just entities. diff --git a/doc/clause-reference.md b/doc/clause-reference.md index 2d37f38..22f7db4 100644 --- a/doc/clause-reference.md +++ b/doc/clause-reference.md @@ -564,7 +564,8 @@ The third case takes a pair of either a table specifier or a table/column specifier and a SQL query. For the first and second cases, you'll use the `:values` clause -to specify rows of values to insert. +to specify rows of values to insert. See [**values**](#values) below +for more detail on the `:values` clause. `:replace-into` is only supported by MySQL and SQLite but is part of HoneySQL's "core" dialect anyway. It produces a `REPLACE INTO` @@ -1037,16 +1038,40 @@ same as the `:for` clause above. row values or a sequence of sequences, also representing row values. -In the former case, all of the rows are augmented to have +### values with hash maps + +If you provide a sequence of hash maps, the `:values` clause +will generate a `VALUES` clause with the column names preceding +and the row values following. + +```clojure +user=> (sql/format {:values [{:col-a 1 :col-b 2}]}) +["(col_a, col_b) VALUES (?, ?)" 1 2] +``` + +In addition, all of the rows are augmented to have either `NULL` or `DEFAULT` values for any missing keys (columns). By default, `NULL` is used but you can specify a set of columns to get `DEFAULT` values, via the `:values-default-columns` option. You can also be explicit and use `[:default]` as a value to generate `DEFAULT`. -In the latter case -- a sequence of sequences -- -all of the rows are padded to the same length by adding `nil` + +### values with sequences + +If you provide a sequence of sequences, the `:values` clause +will generate a `VALUES` clause with no column names and the +row values following. + +```clojure +user=> (sql/format {:values [[1 2]]}) +["VALUES (?, ?)" 1 2] +``` + +In addition, all of the rows are padded to the same length by adding `nil` values if needed (since `:values` does not know how or if column names are being used in this case). +### values examples + ```clojure user=> (sql/format {:insert-into :table :values [[1 2] [2 3 4 5] [3 4 5]]}) diff --git a/src/honey/sql.cljc b/src/honey/sql.cljc index 1df00ed..1cbfdc1 100644 --- a/src/honey/sql.cljc +++ b/src/honey/sql.cljc @@ -2083,4 +2083,19 @@ (sql/format {:select [:*], :from [:table], :where [:foo [:+ :a 1]]}) (sql/formatf '{select * from table where (foo (+ a 1))}) (sql/formatf '{select * from table where (foo (+ a ?1))} 42) + + (sql/format {:update [:user :u] + :set {:email :u2.email + :first_name :u2.first_name + :last_name :u2.last_name} + :from [[[:values [1 "hollis@weiman.biz" "Hollis" "Connell"] + [2 "robert@duncan.info" "Robert" "Duncan"]] + [[:'u2 :id :email :first_name :last_name]]]] + :where [:= :u.id :u2.id]} + {:inline true}) + + (sql/register-clause! :output :select :values) + (sql/format {:insert-into :foo :output [:inserted.*] :values [{:bar 1}]}) + (sql/format {:insert-into :foo :columns [:bar] :output [:inserted.*] :values [[1]]}) + )