fix #204 by adding on-connection macro
This commit is contained in:
parent
0cb10285af
commit
03092d023f
4 changed files with 57 additions and 0 deletions
|
|
@ -3,6 +3,7 @@
|
||||||
Only accretive/fixative changes will be made from now on.
|
Only accretive/fixative changes will be made from now on.
|
||||||
|
|
||||||
* 1.2.next in progress
|
* 1.2.next in progress
|
||||||
|
* Address [#204](https://github.com/seancorfield/next-jdbc/issues/204) by adding `next.jdbc/on-connection`.
|
||||||
* Address [#203](https://github.com/seancorfield/next-jdbc/issues/203) by adding a note to the **PostgreSQL Tips & Tricks** section.
|
* Address [#203](https://github.com/seancorfield/next-jdbc/issues/203) by adding a note to the **PostgreSQL Tips & Tricks** section.
|
||||||
* Update `build-clj` to v0.8.0.
|
* Update `build-clj` to v0.8.0.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -577,6 +577,21 @@ JDBC provides several features that let you introspect the database to obtain li
|
||||||
Several methods on `DatabaseMetaData` return a `ResultSet` object, e.g., `.getCatalogs()`, `.getClientInfoProperties()`, `.getSchemas()`.
|
Several methods on `DatabaseMetaData` return a `ResultSet` object, e.g., `.getCatalogs()`, `.getClientInfoProperties()`, `.getSchemas()`.
|
||||||
All of those can be handled in a similar manner to the above. See the [Oracle documentation for `java.sql.DatabaseMetaData`](https://docs.oracle.com/en/java/javase/11/docs/api/java.sql/java/sql/DatabaseMetaData.html) (Java 11) for more details.
|
All of those can be handled in a similar manner to the above. See the [Oracle documentation for `java.sql.DatabaseMetaData`](https://docs.oracle.com/en/java/javase/11/docs/api/java.sql/java/sql/DatabaseMetaData.html) (Java 11) for more details.
|
||||||
|
|
||||||
|
If you are working with a generalized datasource that may be a `Connection`, a `DataSource`,
|
||||||
|
or a wrapped connectable (via something like `with-options` or `with-transaction`), you can
|
||||||
|
write generic, `Connection`-based code using `on-connection` which will reuse a `Connection`
|
||||||
|
if one is passed or create a new one if needed (and automatically close it afterward):
|
||||||
|
|
||||||
|
```clojure
|
||||||
|
(on-connection [con ds]
|
||||||
|
(-> (.getMetaData con) ; produces java.sql.DatabaseMetaData
|
||||||
|
;; return a java.sql.ResultSet describing all tables and views:
|
||||||
|
(.getTables nil nil nil (into-array ["TABLE" "VIEW"]))
|
||||||
|
(rs/datafiable-result-set ds opts)))
|
||||||
|
```
|
||||||
|
|
||||||
|
> Note: to avoid confusion and/or incorrect usage, you cannot pass options to `on-connection` because they would be ignored in some cases (existing `Connection` or a wrapped `Connection`).
|
||||||
|
|
||||||
## Logging
|
## Logging
|
||||||
|
|
||||||
Sometimes it is convenient to have database operations logged automatically. `next.jdbc/with-logging`
|
Sometimes it is convenient to have database operations logged automatically. `next.jdbc/with-logging`
|
||||||
|
|
|
||||||
|
|
@ -339,6 +339,35 @@
|
||||||
(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
|
||||||
|
"Given a connectable object, gets a connection and binds it to `sym`,
|
||||||
|
then executes the `body` in that context.
|
||||||
|
|
||||||
|
This allows you to write generic, `Connection`-based code without
|
||||||
|
needing to know the exact type of an incoming datasource:
|
||||||
|
|
||||||
|
(on-connection [conn datasource]
|
||||||
|
(let [metadata (.getMetadata conn)
|
||||||
|
catalog (.getCatalog conn)]
|
||||||
|
...))
|
||||||
|
|
||||||
|
If passed a `Connection` or a `Connectable` that wraps a `Connection`,
|
||||||
|
then that `Connection` is used as-is.
|
||||||
|
|
||||||
|
Otherwise, creates a new `Connection` object from the connectable,
|
||||||
|
executes the body, and automatically closes it for you."
|
||||||
|
[[sym connectable] & body]
|
||||||
|
(let [con-sym (vary-meta sym assoc :tag 'java.sql.Connection)
|
||||||
|
con-obj connectable]
|
||||||
|
`(cond (instance? java.sql.Connection ~con-obj)
|
||||||
|
((^{:once true} fn* [~con-sym] ~@body) ~con-obj)
|
||||||
|
(and (satisfies? p/Connectable ~con-obj)
|
||||||
|
(instance? java.sql.Connection (:connectable ~con-obj)))
|
||||||
|
((^{:once true} fn* [~con-sym] ~@body) (:connectable ~con-obj))
|
||||||
|
:else
|
||||||
|
(with-open [con# (get-connection ~con-obj)]
|
||||||
|
((^{:once true} fn* [~con-sym] ~@body) con#)))))
|
||||||
|
|
||||||
(defn transact
|
(defn transact
|
||||||
"Given a transactable object and a function (taking a `Connection`),
|
"Given a transactable object and a function (taking a `Connection`),
|
||||||
execute the function over the connection in a transactional manner.
|
execute the function over the connection in a transactional manner.
|
||||||
|
|
|
||||||
|
|
@ -883,3 +883,15 @@ INSERT INTO fruit (name, appearance) VALUES (?,?)
|
||||||
(default-options)))))
|
(default-options)))))
|
||||||
(is (thrown? IllegalArgumentException
|
(is (thrown? IllegalArgumentException
|
||||||
(doall (take 3 (jdbc/plan (ds) ["select * from fruit"]))))))
|
(doall (take 3 (jdbc/plan (ds) ["select * from fruit"]))))))
|
||||||
|
|
||||||
|
(deftest issue-204
|
||||||
|
(testing "against a Connection"
|
||||||
|
(is (seq (with-open [con (jdbc/get-connection (ds))]
|
||||||
|
(jdbc/on-connection [x con] (jdbc/execute! x ["select * from fruit"]))))))
|
||||||
|
(testing "against a wrapped Connection"
|
||||||
|
(is (seq (with-open [con (jdbc/get-connection (ds))]
|
||||||
|
(jdbc/on-connection [x (jdbc/with-options con {})] (jdbc/execute! x ["select * from fruit"]))))))
|
||||||
|
(testing "against a wrapped Datasource"
|
||||||
|
(is (seq (jdbc/on-connection [x (jdbc/with-options (ds) {})] (jdbc/execute! x ["select * from fruit"])))))
|
||||||
|
(testing "against a Datasource"
|
||||||
|
(is (seq (jdbc/on-connection [x (ds)] (jdbc/execute! x ["select * from fruit"]))))))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue