address #181 (again!)

Signed-off-by: Sean Corfield <sean@corfield.org>
This commit is contained in:
Sean Corfield 2025-02-13 17:41:27 -08:00
parent e6d1abf3ec
commit 9ed335dc8d
No known key found for this signature in database
6 changed files with 82 additions and 29 deletions

View file

@ -4,6 +4,7 @@ Only accretive/fixative changes will be made from now on.
* 1.3.next in progress * 1.3.next in progress
* Address [#295](https://github.com/seancorfield/next-jdbc/issues/295) by providing a way to tell `next.jdbc` that certain options should be passed "as-is" in the `Properties` object when creating a `Connection`. * Address [#295](https://github.com/seancorfield/next-jdbc/issues/295) by providing a way to tell `next.jdbc` that certain options should be passed "as-is" in the `Properties` object when creating a `Connection`.
* Fix [#181](https://github.com/seancorfield/next-jdbc/issues/181) (again!) by adding `Wrapped` protocol as a way for `DefaultOptions` and `SQLLogging` to consistently expose the underlying connectable, even when nested.
* 1.3.994 -- 2025-01-28 * 1.3.994 -- 2025-01-28
* Fix [#293](https://github.com/seancorfield/next-jdbc/issues/293) by no longer `locking` on the `Connection` retrieved from a `DataSource`. * Fix [#293](https://github.com/seancorfield/next-jdbc/issues/293) by no longer `locking` on the `Connection` retrieved from a `DataSource`.

View file

@ -1,4 +1,4 @@
;; copyright (c) 2018-2024 Sean Corfield, all rights reserved ;; copyright (c) 2018-2025 Sean Corfield, all rights reserved
(ns next.jdbc (ns next.jdbc
"The public API of the next generation java.jdbc library. "The public API of the next generation java.jdbc library.
@ -336,13 +336,14 @@
result)))) result))))
params))) params)))
([connectable sql param-groups opts] ([connectable sql param-groups opts]
(if (or (instance? java.sql.Connection connectable) (let [conn (p/unwrap connectable)]
(and (satisfies? p/Connectable connectable) (if (instance? java.sql.Connection conn)
(instance? java.sql.Connection (:connectable connectable)))) (with-open [ps (prepare conn [sql] (if-let [opts' (:options connectable)]
(with-open [ps (prepare connectable [sql] opts)] (merge opts' opts)
opts))]
(execute-batch! ps param-groups opts)) (execute-batch! ps param-groups opts))
(with-open [con (get-connection connectable)] (with-open [con (get-connection connectable)]
(execute-batch! con sql param-groups opts))))) (execute-batch! con sql param-groups opts))))))
(defmacro on-connection (defmacro on-connection
"Given a connectable object, gets a connection and binds it to `sym`, "Given a connectable object, gets a connection and binds it to `sym`,
@ -365,13 +366,10 @@
executes the body, and automatically closes it for you." executes the body, and automatically closes it for you."
[[sym connectable] & body] [[sym connectable] & body]
(let [con-sym (vary-meta sym assoc :tag 'java.sql.Connection)] (let [con-sym (vary-meta sym assoc :tag 'java.sql.Connection)]
`(let [con-obj# ~connectable] `(let [con-obj# ~connectable
(cond (instance? java.sql.Connection con-obj#) bare-con# (p/unwrap con-obj#)]
((^{:once true} fn* [~con-sym] ~@body) con-obj#) (if (instance? java.sql.Connection bare-con#)
(and (satisfies? p/Connectable con-obj#) ((^{:once true} fn* [~con-sym] ~@body) bare-con#)
(instance? java.sql.Connection (:connectable con-obj#)))
((^{:once true} fn* [~con-sym] ~@body) (:connectable con-obj#))
:else
(with-open [con# (get-connection con-obj#)] (with-open [con# (get-connection con-obj#)]
((^{:once true} fn* [~con-sym] ~@body) con#)))))) ((^{:once true} fn* [~con-sym] ~@body) con#))))))
@ -403,12 +401,8 @@
with `on-connection`." with `on-connection`."
[[sym connectable] & body] [[sym connectable] & body]
`(let [con-obj# ~connectable] `(let [con-obj# ~connectable]
(cond (instance? java.sql.Connection con-obj#) (if (instance? java.sql.Connection (p/unwrap con-obj#))
((^{:once true} fn* [~sym] ~@body) con-obj#) ((^{:once true} fn* [~sym] ~@body) con-obj#)
(and (satisfies? p/Connectable con-obj#)
(instance? java.sql.Connection (:connectable con-obj#)))
((^{:once true} fn* [~sym] ~@body) con-obj#)
:else
(with-open [con# (get-connection con-obj#)] (with-open [con# (get-connection con-obj#)]
((^{:once true} fn* [~sym] ~@body) ((^{:once true} fn* [~sym] ~@body)
(with-options con# (:options con-obj# {}))))))) (with-options con# (:options con-obj# {})))))))

View file

@ -1,4 +1,4 @@
;; copyright (c) 2020-2024 Sean Corfield, all rights reserved ;; copyright (c) 2020-2025 Sean Corfield, all rights reserved
(ns ^:no-doc next.jdbc.default-options (ns ^:no-doc next.jdbc.default-options
"Implementation of default options logic." "Implementation of default options logic."
@ -8,6 +8,10 @@
(defrecord DefaultOptions [connectable options]) (defrecord DefaultOptions [connectable options])
(extend-protocol p/Wrapped
DefaultOptions
(unwrap [this] (p/unwrap (:connectable this))))
(extend-protocol p/Sourceable (extend-protocol p/Sourceable
DefaultOptions DefaultOptions
(get-datasource [this] (get-datasource [this]

View file

@ -1,4 +1,4 @@
;; copyright (c) 2018-2024 Sean Corfield, all rights reserved ;; copyright (c) 2018-2025 Sean Corfield, all rights reserved
(ns next.jdbc.protocols (ns next.jdbc.protocols
"This is the extensible core of the next generation java.jdbc library. "This is the extensible core of the next generation java.jdbc library.
@ -63,3 +63,15 @@
:extend-via-metadata true :extend-via-metadata true
(-transact [this body-fn opts] (-transact [this body-fn opts]
"Run the `body-fn` inside a transaction.")) "Run the `body-fn` inside a transaction."))
(defprotocol Wrapped
"Protocol for (un)wrapping a `next.jdbc` connectable.
Implementations are provided for `Object` (identity) and `DefaultOptions`
and SQLLogging."
(unwrap [this]
"Unwrap the connectable to get the underlying connectable."))
(extend-protocol Wrapped
Object
(unwrap [this] this))

View file

@ -1,4 +1,4 @@
;; copyright (c) 2021-2024 Sean Corfield, all rights reserved ;; copyright (c) 2021-2025 Sean Corfield, all rights reserved
(ns ^:no-doc next.jdbc.sql-logging (ns ^:no-doc next.jdbc.sql-logging
"Implementation of sql-logging logic." "Implementation of sql-logging logic."
@ -8,6 +8,10 @@
(defrecord SQLLogging [connectable sql-logger result-logger options]) (defrecord SQLLogging [connectable sql-logger result-logger options])
(extend-protocol p/Wrapped
SQLLogging
(unwrap [this] (p/unwrap (:connectable this))))
(extend-protocol p/Sourceable (extend-protocol p/Sourceable
SQLLogging SQLLogging
(get-datasource [this] (get-datasource [this]

View file

@ -749,6 +749,44 @@ INSERT INTO fruit (name, appearance) VALUES (?,?)
(conj result (count (jdbc/execute! (ds) ["select * from fruit"])))) (conj result (count (jdbc/execute! (ds) ["select * from fruit"]))))
(finally (finally
(jdbc/execute-one! (ds) [(str "delete from fruit where " (index) " > 4")]))))) (jdbc/execute-one! (ds) [(str "delete from fruit where " (index) " > 4")])))))
(is (= [1 1 1 1 1 1 1 1 1 13]
(try
(let [result (jdbc/execute-batch! (jdbc/with-options
(jdbc/with-logging (ds) println println)
{:ignore "me"})
"INSERT INTO fruit (name, appearance) VALUES (?,?)"
[["fruit1" "one"]
["fruit2" "two"]
["fruit3" "three"]
["fruit4" "four"]
["fruit5" "five"]
["fruit6" "six"]
["fruit7" "seven"]
["fruit8" "eight"]
["fruit9" "nine"]]
{})]
(conj result (count (jdbc/execute! (ds) ["select * from fruit"]))))
(finally
(jdbc/execute-one! (ds) [(str "delete from fruit where " (index) " > 4")])))))
(is (= [1 1 1 1 1 1 1 1 1 13]
(try
(let [result (jdbc/execute-batch! (jdbc/with-logging
(jdbc/with-options (ds) {:ignore "me"})
println println)
"INSERT INTO fruit (name, appearance) VALUES (?,?)"
[["fruit1" "one"]
["fruit2" "two"]
["fruit3" "three"]
["fruit4" "four"]
["fruit5" "five"]
["fruit6" "six"]
["fruit7" "seven"]
["fruit8" "eight"]
["fruit9" "nine"]]
{})]
(conj result (count (jdbc/execute! (ds) ["select * from fruit"]))))
(finally
(jdbc/execute-one! (ds) [(str "delete from fruit where " (index) " > 4")])))))
(is (= 4 (count (jdbc/execute! (ds) ["select * from fruit"]))))) (is (= 4 (count (jdbc/execute! (ds) ["select * from fruit"])))))
(testing "small batch insert" (testing "small batch insert"
(is (= [1 1 1 1 1 1 1 1 1 13] (is (= [1 1 1 1 1 1 1 1 1 13]