address #423 by adding support for default

needs documentation
This commit is contained in:
Sean Corfield 2022-09-01 22:54:00 -07:00
parent 737699c11a
commit 3073d28525
3 changed files with 84 additions and 49 deletions

View file

@ -2,6 +2,7 @@
* 2.3.next in progress * 2.3.next in progress
* Address [#425](https://github.com/seancorfield/honeysql/issues/425) by clarifying that `INTERVAL` as special syntax may be MySQL-specific and PostgreSQL uses difference syntax (because `INTERVAL` is a data type there). * Address [#425](https://github.com/seancorfield/honeysql/issues/425) by clarifying that `INTERVAL` as special syntax may be MySQL-specific and PostgreSQL uses difference syntax (because `INTERVAL` is a data type there).
* Address [#423](https://github.com/seancorfield/honeysql/issues/423) by supporting `DEFAULT` values and `DEFAULT` rows in `VALUES` clause -- NEEDS DOCUMENTATION!
* **WIP** Address [#422](https://github.com/seancorfield/honeysql/issues/422) by auto-quoting unusual entity names when `:quoted` (and `:dialect`) are not specified, making HoneySQL more secure by default. * **WIP** Address [#422](https://github.com/seancorfield/honeysql/issues/422) by auto-quoting unusual entity names when `:quoted` (and `:dialect`) are not specified, making HoneySQL more secure by default.
* Address [#419](https://github.com/seancorfield/honeysql/issues/419) by adding `honey.sql.protocols` and `InlineValue` with a `sqlize` function. * Address [#419](https://github.com/seancorfield/honeysql/issues/419) by adding `honey.sql.protocols` and `InlineValue` with a `sqlize` function.
* Address [#413](https://github.com/seancorfield/honeysql/issues/413) by flagging a lack of `WHERE` clause for `DELETE`, `DELETE FROM`, and `UPDATE` when `:checking :basic` (or `:checking :strict`). * Address [#413](https://github.com/seancorfield/honeysql/issues/413) by flagging a lack of `WHERE` clause for `DELETE`, `DELETE FROM`, and `UPDATE` when `:checking :basic` (or `:checking :strict`).

View file

@ -699,23 +699,38 @@
(str " " (sql-kw nowait))))))])) (str " " (sql-kw nowait))))))]))
(defn- format-values [k xs] (defn- format-values [k xs]
(cond (sequential? (first xs)) (let [first-xs (when (sequential? xs) (first (drop-while ident? xs)))]
(cond (contains? #{:default 'default} xs)
[(str (sql-kw xs) " " (sql-kw k))]
(empty? xs)
[(str (sql-kw k) " ()")]
(sequential? first-xs)
;; [[1 2 3] [4 5 6]] ;; [[1 2 3] [4 5 6]]
(let [n-1 (map count xs) (let [n-1 (map count (filter sequential? xs))
;; issue #291: ensure all value sequences are the same length ;; issue #291: ensure all value sequences are the same length
xs' (if (apply = n-1) xs' (if (apply = n-1)
xs xs
(let [n-n (apply max n-1)] (let [n-n (when (seq n-1) (apply max n-1))]
(map (fn [x] (take n-n (concat x (repeat nil)))) xs))) (map (fn [x]
(if (sequential? x)
(take n-n (concat x (repeat nil)))
x))
xs)))
[sqls params] [sqls params]
(reduce (fn [[sql params] [sqls' params']] (reduce (fn [[sql params] [sqls' params']]
[(conj sql (str "(" (str/join ", " sqls') ")")) [(conj sql
(if (sequential? sqls')
(str "(" (str/join ", " sqls') ")")
sqls'))
(into params params')]) (into params params')])
[[] []] [[] []]
(map #'format-expr-list xs'))] (map #(if (sequential? %)
(format-expr-list %)
[(sql-kw %)])
xs'))]
(into [(str (sql-kw k) " " (str/join ", " sqls))] params)) (into [(str (sql-kw k) " " (str/join ", " sqls))] params))
(map? (first xs)) (map? first-xs)
;; [{:a 1 :b 2 :c 3}] ;; [{:a 1 :b 2 :c 3}]
(let [cols-1 (keys (first xs)) (let [cols-1 (keys (first xs))
;; issue #291: check for all keys in all maps but still ;; issue #291: check for all keys in all maps but still
@ -751,7 +766,7 @@
:else :else
(throw (ex-info ":values expects sequences or maps" (throw (ex-info ":values expects sequences or maps"
{:first (first xs)})))) {:first (first xs)})))))
(comment (comment
(into #{} (mapcat keys) [{:a 1 :b 2} {:b 3 :c 4}]) (into #{} (mapcat keys) [{:a 1 :b 2} {:b 3 :c 4}])

View file

@ -737,6 +737,25 @@ ORDER BY id = ? DESC
:values [{:name name :values [{:name name
:enabled enabled}]}))))) :enabled enabled}]})))))
(deftest issue-425-default-values-test
(testing "default values"
(is (= ["INSERT INTO table (a, b, c) DEFAULT VALUES"]
(format {:insert-into [:table [:a :b :c]] :values :default}))))
(testing "values with default row"
(is (= ["INSERT INTO table (a, b, c) VALUES (1, 2, 3), DEFAULT, (4, 5, 6)"]
(format {:insert-into [:table [:a :b :c]]
:values [[1 2 3] :default [4 5 6]]}
{:inline true}))))
(testing "values with default column"
(is (= ["INSERT INTO table (a, b, c) VALUES (1, DEFAULT, 3), DEFAULT"]
(format {:insert-into [:table [:a :b :c]]
:values [[1 [:default] 3] :default]}
{:inline true}))))
(testing "empty values"
(is (= ["INSERT INTO table (a, b, c) VALUES ()"]
(format {:insert-into [:table [:a :b :c]]
:values []})))))
(deftest issue-316-test (deftest issue-316-test
;; this is a pretty naive test -- there are other tricks to perform injection ;; this is a pretty naive test -- there are other tricks to perform injection
;; that are not detected by HoneySQL and you should generally use :quoted true ;; that are not detected by HoneySQL and you should generally use :quoted true