Fix #26 by adding datafiable-result-set
This makes handling metadata result sets much easier.
This commit is contained in:
parent
b4331146ff
commit
22a3f2bb5f
7 changed files with 53 additions and 27 deletions
|
|
@ -6,7 +6,7 @@ Only accretive/fixative changes will be made from now on.
|
|||
|
||||
The following changes have been committed to the **master** branch and will be in the next release:
|
||||
|
||||
* None.
|
||||
* Fix #26 by exposing `next.jdbc.result-set/datafiable-result-set` so that various `java.sql.DatabaseMetaData` methods that result metadata information in `ResultSet`s can be easily turned into a fully realized result set.
|
||||
|
||||
## Stable Builds
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ The latest versions on Clojars and on cljdoc:
|
|||
|
||||
[](https://clojars.org/seancorfield/next.jdbc) [](https://cljdoc.org/d/seancorfield/next.jdbc/CURRENT)
|
||||
|
||||
This documentation is for the 1.0.0-rc1 release -- [see the CHANGELOG](CHANGELOG.md).
|
||||
This documentation is for the upcoming 1.0.0 release -- [see the CHANGELOG](CHANGELOG.md).
|
||||
|
||||
* [Getting Started](/doc/getting-started.md)
|
||||
* [Migrating from `clojure.java.jdbc`](/doc/migration-from-clojure-java-jdbc.md)
|
||||
|
|
|
|||
|
|
@ -45,4 +45,6 @@ When that is called (`nav` on a row, column name, and column value), if a `:sche
|
|||
|
||||
The protocol `next.jdbc.result-set/DatafiableRow` has a default implementation of `datafiable-row` for `clojure.lang.IObj` that just adds the metadata to support `datafy`. There is also an implementation baked into the result set handling behind `plan` so that you can call `datafiable-row` directly during reduction and get a fully-realized row that can be `datafy`'d (and then `nav`igated).
|
||||
|
||||
In addition, you can call `next.jdbc.result-set/datafiable-result-set` on any `ResultSet` object and get a fully realized, datafiable result set created using any of the result set builders.
|
||||
|
||||
[<: All The Options](/doc/all-the-options.md) | [Migration from `clojure.java.jdbc` :>](/doc/migration-from-clojure-java-jdbc.md)
|
||||
|
|
|
|||
|
|
@ -67,6 +67,19 @@ If you are using `:result-set-fn` and/or `:row-fn`, you will need to change to e
|
|||
|
||||
Note: this means that result sets are never exposed lazily in `next.jdbc` -- in `clojure.java.jdbc` you had to be careful that your `:result-set-fn` was eager, but in `next.jdbc` you either reduce the result set eagerly (via `plan`) or you get a fully-realized result set data structure back (from `execute!` and `execute-one!`). As with `clojure.java.jdbc` however, you can still stream result sets from the database and process them via reduction (was `reducible-query`, now `plan`). Remember that you can terminate a reduction early by using the `reduced` function to wrap the final value you produce.
|
||||
|
||||
### Processing Database Metadata
|
||||
|
||||
There are no metadata-specific functions in `next.jdbc` but those in `clojure.java.jdbc` are only a very thin layer over the raw Java calls. Here's how metadata can be handled in `next.jdbc`:
|
||||
|
||||
```clojure
|
||||
(with-open [con (p/get-connection ds opts)]
|
||||
(-> (.getMetaData con) ; produces java.sql.DatabaseMetaData
|
||||
(.getTables nil nil nil (into-array ["TABLE" "VIEW"]))
|
||||
(rs/datafiable-result-set ds opts)))
|
||||
```
|
||||
|
||||
Several methods on `DatabaseMetaData` return a `ResultSet` object. All of those can be handled similarly.
|
||||
|
||||
## Further Minor differences
|
||||
|
||||
These are mostly drawn from [Issue #5](https://github.com/seancorfield/next-jdbc/issues/5) although most of the bullets in that issue are described in more detail above.
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ The options hash map for any `next.jdbc` function can contain a `:builder-fn` ke
|
|||
|
||||
The options hash map passed to the builder function will contain a `:next.jdbc/sql-params` key, whose value is the SQL + parameters vector passed into the top-level `next.jdbc` functions (`plan`, `execute!`, and `execute-one!`).
|
||||
|
||||
There is also a convenience function, `datafiable-result-set`, that accepts a `ResultSet` object (and a connectable and an options hash map) and returns a fully realized result set, per the `:builder-fn` option (or `as-maps` if that option is omitted).
|
||||
|
||||
## `next.jdbc.optional`
|
||||
|
||||
This namespace contains variants of the six `as-maps`-style builders above that omit keys from the row hash maps if the corresponding column is `NULL`. This is in keeping with Clojure's views of "optionality" -- that optional elements should simply be omitted -- and is provided as an "opt-in" style of rows and result sets.
|
||||
|
|
|
|||
|
|
@ -354,6 +354,22 @@
|
|||
(with-meta this
|
||||
{`core-p/datafy (navize-row connectable opts)})))
|
||||
|
||||
(defn datafiable-result-set
|
||||
"Given a ResultSet, a connectable, and an options hash map, return a fully
|
||||
realized, datafiable result set per the `:builder-fn` option passed in.
|
||||
If no `:builder-fn` option is provided, `as-maps` is used as the default.
|
||||
|
||||
This can be used to process regular result sets or metadata result sets."
|
||||
[^java.sql.ResultSet rs connectable opts]
|
||||
(let [builder-fn (get opts :builder-fn as-maps)
|
||||
builder (builder-fn rs opts)]
|
||||
(loop [rs' (->rs builder) more? (.next rs)]
|
||||
(if more?
|
||||
(recur (with-row builder rs'
|
||||
(datafiable-row (row-builder builder) connectable opts))
|
||||
(.next rs))
|
||||
(rs! builder rs')))))
|
||||
|
||||
(defn- stmt->result-set
|
||||
"Given a `PreparedStatement` and options, execute it and return a `ResultSet`
|
||||
if possible."
|
||||
|
|
@ -413,14 +429,7 @@
|
|||
(rest sql-params)
|
||||
opts)]
|
||||
(if-let [rs (stmt->result-set stmt opts)]
|
||||
(let [builder-fn (get opts :builder-fn as-maps)
|
||||
builder (builder-fn rs opts)]
|
||||
(loop [rs' (->rs builder) more? (.next rs)]
|
||||
(if more?
|
||||
(recur (with-row builder rs'
|
||||
(datafiable-row (row-builder builder) this opts))
|
||||
(.next rs))
|
||||
(rs! builder rs'))))
|
||||
(datafiable-result-set rs this opts)
|
||||
[{:next.jdbc/update-count (.getUpdateCount stmt)}])))
|
||||
|
||||
javax.sql.DataSource
|
||||
|
|
@ -452,14 +461,7 @@
|
|||
(rest sql-params)
|
||||
opts)]
|
||||
(if-let [rs (stmt->result-set stmt opts)]
|
||||
(let [builder-fn (get opts :builder-fn as-maps)
|
||||
builder (builder-fn rs opts)]
|
||||
(loop [rs' (->rs builder) more? (.next rs)]
|
||||
(if more?
|
||||
(recur (with-row builder rs'
|
||||
(datafiable-row (row-builder builder) this opts))
|
||||
(.next rs))
|
||||
(rs! builder rs'))))
|
||||
(datafiable-result-set rs this opts)
|
||||
[{:next.jdbc/update-count (.getUpdateCount stmt)}]))))
|
||||
|
||||
java.sql.PreparedStatement
|
||||
|
|
@ -480,15 +482,7 @@
|
|||
{:next.jdbc/update-count (.getUpdateCount this)}))
|
||||
(-execute-all [this _ opts]
|
||||
(if-let [rs (stmt->result-set this opts)]
|
||||
(let [builder-fn (get opts :builder-fn as-maps)
|
||||
builder (builder-fn rs opts)]
|
||||
(loop [rs' (->rs builder) more? (.next rs)]
|
||||
(if more?
|
||||
(recur (with-row builder rs'
|
||||
(datafiable-row (row-builder builder)
|
||||
(.getConnection this) opts))
|
||||
(.next rs))
|
||||
(rs! builder rs'))))
|
||||
(datafiable-result-set rs (.getConnection this) opts)
|
||||
[{:next.jdbc/update-count (.getUpdateCount this)}]))
|
||||
|
||||
Object
|
||||
|
|
|
|||
|
|
@ -191,3 +191,18 @@
|
|||
(is (every? #(instance? Fruit %) rs))
|
||||
(is (= 1 (count rs)))
|
||||
(is (= 1 (:id (first rs))))))
|
||||
|
||||
(deftest metadata-result-set
|
||||
(let [metadata (with-open [con (p/get-connection (ds) {})]
|
||||
(-> (.getMetaData con)
|
||||
(.getTables nil nil nil (into-array ["TABLE" "VIEW"]))
|
||||
(rs/datafiable-result-set (ds) {})))]
|
||||
(is (vector? metadata))
|
||||
(is (map? (first metadata)))
|
||||
;; we should find :something/table_name with a value of "fruit"
|
||||
;; may be upper/lower-case, could have any qualifier
|
||||
(is (some (fn [row]
|
||||
(some #(and (= "table_name" (-> % key name str/lower-case))
|
||||
(= "fruit" (-> % val name str/lower-case)))
|
||||
row))
|
||||
metadata))))
|
||||
|
|
|
|||
Loading…
Reference in a new issue