address #256 by adding with-transaction+options
This commit is contained in:
parent
8ad1110fcb
commit
044de70b49
5 changed files with 76 additions and 4 deletions
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
Only accretive/fixative changes will be made from now on.
|
Only accretive/fixative changes will be made from now on.
|
||||||
|
|
||||||
|
* 1.3.next in progress
|
||||||
|
* Address [#256](https://github.com/seancorfield/next-jdbc/issues/256) by adding `with-transaction+options`. Documentation TBD.
|
||||||
|
|
||||||
* 1.3.883 -- 2023-06-25
|
* 1.3.883 -- 2023-06-25
|
||||||
* Address [#254](https://github.com/seancorfield/next-jdbc/issues/254) by adding `next.jdbc/active-tx?` and adding more explanation to [**Transactions**](https://cljdoc.org/d/com.github.seancorfield/next.jdbc/CURRENT/doc/getting-started/transactions) about the conventions behind transactions and the limitations of thread-local tracking of active transactions in `next.jdbc`.
|
* Address [#254](https://github.com/seancorfield/next-jdbc/issues/254) by adding `next.jdbc/active-tx?` and adding more explanation to [**Transactions**](https://cljdoc.org/d/com.github.seancorfield/next.jdbc/CURRENT/doc/getting-started/transactions) about the conventions behind transactions and the limitations of thread-local tracking of active transactions in `next.jdbc`.
|
||||||
* Address [#251](https://github.com/seancorfield/next-jdbc/issues/251) by updating `next.jdbc/with-logging` docstring.
|
* Address [#251](https://github.com/seancorfield/next-jdbc/issues/251) by updating `next.jdbc/with-logging` docstring.
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
{:hooks
|
{:hooks
|
||||||
{:analyze-call
|
{:analyze-call
|
||||||
{next.jdbc/with-transaction
|
{next.jdbc/with-transaction
|
||||||
hooks.com.github.seancorfield.next-jdbc/with-transaction}}
|
hooks.com.github.seancorfield.next-jdbc/with-transaction
|
||||||
|
next.jdbc/with-transaction+options
|
||||||
|
hooks.com.github.seancorfield.next-jdbc/with-transaction+options}}
|
||||||
:lint-as {next.jdbc/on-connection clojure.core/with-open}}
|
:lint-as {next.jdbc/on-connection clojure.core/with-open}}
|
||||||
|
|
@ -16,3 +16,19 @@
|
||||||
opts
|
opts
|
||||||
body))]
|
body))]
|
||||||
{:node new-node})))
|
{:node new-node})))
|
||||||
|
|
||||||
|
(defn with-transaction+options
|
||||||
|
"Expands (with-transaction+options [tx expr opts] body)
|
||||||
|
to (let [tx expr] opts body) per clj-kondo examples."
|
||||||
|
[{:keys [:node]}]
|
||||||
|
(let [[binding-vec & body] (rest (:children node))
|
||||||
|
[sym val opts] (:children binding-vec)]
|
||||||
|
(when-not (and sym val)
|
||||||
|
(throw (ex-info "No sym and val provided" {})))
|
||||||
|
(let [new-node (api/list-node
|
||||||
|
(list*
|
||||||
|
(api/token-node 'let)
|
||||||
|
(api/vector-node [sym val])
|
||||||
|
opts
|
||||||
|
body))]
|
||||||
|
{:node new-node})))
|
||||||
|
|
|
||||||
|
|
@ -389,6 +389,9 @@
|
||||||
Like `with-open`, if `with-transaction` creates a new `Connection` object,
|
Like `with-open`, if `with-transaction` creates a new `Connection` object,
|
||||||
it will automatically close it for you.
|
it will automatically close it for you.
|
||||||
|
|
||||||
|
If you are working with default options via `with-options`, you might want
|
||||||
|
to use `with-transaction+options` instead.
|
||||||
|
|
||||||
The options map supports:
|
The options map supports:
|
||||||
* `:isolation` -- `:none`, `:read-committed`, `:read-uncommitted`,
|
* `:isolation` -- `:none`, `:read-committed`, `:read-uncommitted`,
|
||||||
`:repeatable-read`, `:serializable`,
|
`:repeatable-read`, `:serializable`,
|
||||||
|
|
@ -419,9 +422,45 @@
|
||||||
return plain Java objects, so if you call any of those on this wrapped
|
return plain Java objects, so if you call any of those on this wrapped
|
||||||
object, you'll need to re-wrap the Java object `with-options` again. See
|
object, you'll need to re-wrap the Java object `with-options` again. See
|
||||||
the Datasources, Connections & Transactions section of Getting Started for
|
the Datasources, Connections & Transactions section of Getting Started for
|
||||||
more details, and some examples of use with these functions."
|
more details, and some examples of use with these functions.
|
||||||
|
|
||||||
|
`with-transaction+options` exists to automatically rewrap a `Connection`
|
||||||
|
with the options from a `with-options` wrapper."
|
||||||
[connectable opts]
|
[connectable opts]
|
||||||
(opts/->DefaultOptions connectable opts))
|
(let [c (:connectable connectable)
|
||||||
|
o (:options connectable)]
|
||||||
|
(if (and c o)
|
||||||
|
(opts/->DefaultOptions c (merge o opts))
|
||||||
|
(opts/->DefaultOptions connectable opts))))
|
||||||
|
|
||||||
|
(defmacro with-transaction+options
|
||||||
|
"Given a transactable object, assumed to be wrapped with options, gets a
|
||||||
|
connection, rewraps it with those options, and binds it to `sym`, then
|
||||||
|
executes the `body` in that context, committing any changes if the body
|
||||||
|
completes successfully, otherwise rolling back any changes made.
|
||||||
|
|
||||||
|
Like `with-open`, if `with-transaction+options` creates a new `Connection`
|
||||||
|
object, it will automatically close it for you.
|
||||||
|
|
||||||
|
Note: the bound `sym` will be a **wrapped** connectable and not a plain
|
||||||
|
Java object, so you cannot call JDBC methods directly on it like you can
|
||||||
|
with `with-transaction`.
|
||||||
|
|
||||||
|
The options map supports:
|
||||||
|
* `:isolation` -- `:none`, `:read-committed`, `:read-uncommitted`,
|
||||||
|
`:repeatable-read`, `:serializable`,
|
||||||
|
* `:read-only` -- `true` / `false` (`true` will make the `Connection` readonly),
|
||||||
|
* `:rollback-only` -- `true` / `false` (`true` will make the transaction
|
||||||
|
rollback, even if it would otherwise succeed)."
|
||||||
|
[[sym transactable opts] & body]
|
||||||
|
(let [con (vary-meta sym assoc :tag 'java.sql.Connection)]
|
||||||
|
`(let [tx# ~transactable]
|
||||||
|
(transact tx#
|
||||||
|
(^{:once true} fn*
|
||||||
|
[con#]
|
||||||
|
(let [~con (with-options con# (:options tx# {}))]
|
||||||
|
~@body))
|
||||||
|
~(or opts {})))))
|
||||||
|
|
||||||
(defn with-logging
|
(defn with-logging
|
||||||
"Given a connectable/transactable object and a sql/params logging
|
"Given a connectable/transactable object and a sql/params logging
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,18 @@
|
||||||
ds-opts
|
ds-opts
|
||||||
["select appearance as looks_like from fruit where id = ?" 1]
|
["select appearance as looks_like from fruit where id = ?" 1]
|
||||||
jdbc/snake-kebab-opts))))
|
jdbc/snake-kebab-opts))))
|
||||||
|
(let [ds' (jdbc/with-options ds-opts jdbc/snake-kebab-opts)]
|
||||||
|
(is (= "red" (:fruit/looks-like
|
||||||
|
(jdbc/execute-one!
|
||||||
|
ds'
|
||||||
|
["select appearance as looks_like from fruit where id = ?" 1])))))
|
||||||
|
(jdbc/with-transaction+options [ds' (jdbc/with-options ds-opts jdbc/snake-kebab-opts)]
|
||||||
|
(is (= (merge (default-options) jdbc/snake-kebab-opts)
|
||||||
|
(:options ds')))
|
||||||
|
(is (= "red" (:fruit/looks-like
|
||||||
|
(jdbc/execute-one!
|
||||||
|
ds'
|
||||||
|
["select appearance as looks_like from fruit where id = ?" 1])))))
|
||||||
(is (= "red" (:looks-like
|
(is (= "red" (:looks-like
|
||||||
(jdbc/execute-one!
|
(jdbc/execute-one!
|
||||||
ds-opts
|
ds-opts
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue