Closed seancorfield closed 2 years ago
Having played with a few "solutions" to this, solving execute-batch!
's problem turns out to be not the same as solving the OP's problem (and using a solution to the OP's problem in execute-batch!
actually makes it worse).
In addition, trying to solve the OP's problem leads to code that is less predictable about what happens with options so I'm still a bit stuck on this.
This was my first cut but it's really not very nice:
(defmacro on-connection
"Given a connectable object, binds a `Connection` to `sym`,
then executes the `body` in that context. Only to be used when you
specifically need a raw `Connection` object rather than for calling
`next.jdbc` functions on a connectable!
Like `with-open`, if `on-connection` creates a new `Connection` object,
it will automatically close it for you.
If the connectable is a `Connection`, it is used as-is.
If the connectable is an options-wrapped `Connection`, it is unwrapped
(be aware that you get the 'raw' `Connection` and lose the effect of
the options from the wrapper).
Otherwise, `get-connection` is called on the connectable (and that
newly-obtained `Connection` is closed after the `body` is done)."
[[sym connectable] & body]
(let [con (vary-meta sym assoc :tag 'java.sql.Connection)]
`(let [con# ~connectable]
(cond (instance? java.sql.Connection con#)
((^{:once true} fn* [~con] ~@body) con#)
(opts/wrapped-connection? con#)
((^{:once true} fn* [~con] ~@body) (:connectable con#))
:else
(with-open [new# (get-connection con#)]
((^{:once true} fn* [~con] ~@body) new#))))))
I think this is a bit of a dead-end in terms of usability and maintenance so I'm closing this out for now.
See this example from Slack:
Obviously, we don't want folks to be writing conditional code based on types like this --
execute-batch!
already does something horrible like this:We can fix both of these "bad" things by adding something like a
with-connection
macro that uses an existingConnection
(or options-wrapped connection) or creates a new connection for the body to execute in.