feat: insert hashmaps with sql.insert-multi!

Updates the API of `sql/insert-multi!` to support sequences of hash maps
which will automatically be converted into rows and columns.
This commit is contained in:
Ryan Schmukler 2022-05-20 12:40:32 -05:00
parent 1d0abe2286
commit 0531ae0268
3 changed files with 66 additions and 12 deletions

View file

@ -180,7 +180,10 @@
:opts (s/? ::opts-map)))
(s/fdef sql/insert-multi!
:args (s/and (s/cat :connectable ::connectable
:args
(s/or
:with-rows-and-columns
(s/and (s/cat :connectable ::connectable
:table keyword?
:cols (s/coll-of keyword?
:kind sequential?
@ -189,7 +192,14 @@
:kind sequential?)
:opts (s/? ::opts-map))
#(apply = (count (:cols %))
(map count (:rows %)))))
(map count (:rows %))))
:with-hash-maps
(s/cat :connectable ::connectable
:table keyword?
:hash-maps (s/coll-of map?
:kind sequential?
:min-count 1)
:opts (s/? ::opts-map))))
(s/fdef sql/query
:args (s/cat :connectable ::connectable

View file

@ -50,12 +50,26 @@
multiple rows in the database and attempts to return a vector of maps of
generated keys.
Also supports a sequence of hash maps with keys corresponding to column
names.
Note: this expands to a single SQL statement with placeholders for every
value being inserted -- for large sets of rows, this may exceed the limits
on SQL string size and/or number of parameters for your JDBC driver or your
database!"
([connectable table cols rows]
(insert-multi! connectable table cols rows {}))
{:arglists '([connectable table hash-maps]
[connectable table hash-maps opts]
[connectable table cols rows]
[connectable table cols rows opts])}
([connectable table hash-maps]
(insert-multi! connectable table hash-maps {}))
([connectable table hash-maps-or-cols opts-or-rows]
(if-not (-> hash-maps-or-cols first map?)
(insert-multi! connectable table hash-maps-or-cols opts-or-rows {})
(let [cols (keys (first hash-maps-or-cols))
->row (fn ->row [m]
(map (partial get m) cols))]
(insert-multi! connectable table cols (map ->row hash-maps-or-cols) opts-or-rows))))
([connectable table cols rows opts]
(if (seq rows)
(let [opts (merge (:options connectable) opts)]

View file

@ -152,6 +152,36 @@
(is (= {:next.jdbc/update-count 2}
(sql/delete! (ds) :fruit ["id > ?" 4])))
(is (= 4 (count (sql/query (ds) ["select * from fruit"])))))
(testing "multiple insert/delete with maps"
(is (= (cond (derby?)
[nil] ; WTF Apache Derby?
(mssql?)
[14M]
(sqlite?)
[14]
:else
[12 13 14])
(mapv new-key
(sql/insert-multi! (ds) :fruit
[{:name "Kiwi"
:appearance "green & fuzzy"
:cost 100
:grade 99.9}
{:name "Grape"
:appearance "black"
:cost 10
:grade 50}
{:name "Lemon"
:appearance "yellow"
:cost 20
:grade 9.9}]))))
(is (= 7 (count (sql/query (ds) ["select * from fruit"]))))
(is (= {:next.jdbc/update-count 1}
(sql/delete! (ds) :fruit {:id 12})))
(is (= 6 (count (sql/query (ds) ["select * from fruit"]))))
(is (= {:next.jdbc/update-count 2}
(sql/delete! (ds) :fruit ["id > ?" 10])))
(is (= 4 (count (sql/query (ds) ["select * from fruit"])))))
(testing "empty insert-multi!" ; per #44
(is (= [] (sql/insert-multi! (ds) :fruit
[:name :appearance :cost :grade]