From eb722b502e1d04f9923dc961c1378709da6e465c Mon Sep 17 00:00:00 2001 From: Sean Corfield Date: Fri, 28 Feb 2020 10:54:28 -0800 Subject: [PATCH] Fixes #93 by improving documentation about datafiable-row --- CHANGELOG.md | 2 +- doc/getting-started.md | 14 +++++++++++++- src/next/jdbc.clj | 19 ++++++++++++++++++- src/next/jdbc/result_set.clj | 2 +- 4 files changed, 33 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 705585c..c61bf0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ Only accretive/fixative changes will be made from now on. The following changes have been committed to the **master** branch since the 1.0.13 release: * Add PostgreSQL streaming option information to **Tips & Tricks** (#87). -* Minor documentation fixes (including #85, #92). +* Minor documentation fixes (including #85, #92, #93). * Improve `Unknown dbtype` exception message (to clarify that `:classname` is also missing, #90). * Fix #88 by using 1-arity `keyword` call when table name unavailable (or `:qualifier-fn` returns `nil` or an empty string); also allows `:qualifier-fn` function to be called on empty table name (so `:qualifier-fn (constantly "qual")` will now work much like `clojure.java.jdbc`'s `:qualifier "qual"` worked). * Address #89, #91 by making minor performance tweaks to `next.jdbc.result-set` functions. diff --git a/doc/getting-started.md b/doc/getting-started.md index 7b618ad..b199f60 100644 --- a/doc/getting-started.md +++ b/doc/getting-started.md @@ -143,7 +143,19 @@ user=> (into #{} user=> ``` -Any operation that can perform key-based lookup can be used here without creating hash maps: `get`, `contains?`, `find` (returns a `MapEntry` of whatever key you requested and the corresponding column value), or direct keyword access as shown above. Any operation that would require a Clojure hash map, such as `assoc` or anything that invokes `seq` (`keys`, `vals`), will cause the full row to be expanded into a hash map, such as produced by `execute!` or `execute-one!`. +Any operation that can perform key-based lookup can be used here without creating hash maps: `get`, `contains?`, `find` (returns a `MapEntry` of whatever key you requested and the corresponding column value), or direct keyword access as shown above. Any operation that would require a Clojure hash map, such as `assoc` or anything that invokes `seq` (`keys`, `vals`), will cause the full row to be expanded into a hash map, such as produced by `execute!` or `execute-one!`, which implements `Datafiable` and `Navigable` and supports lazy navigation via foreign keys, explained in [`datafy`, `nav`, and the `:schema` option](/doc/datafy-nav-and-schema.md). + +This means that `select-keys` can be used to create regular Clojure hash map from (a subset of) columns in the row, without realizing the row, and it will not implement `Datafiable` or `Navigable`. + +If you wish to create a Clojure hash map that supports that lazy navigation, you can call `next.jdbc.result-set/datafiable-row`, passing in the current row, a `connectable`, and an options hash map, just as you passed into `plan`: + +```clojure +user=> (into [] + (map #(rs/datafiable-row % ds {})) + (jdbc/plan ds ["select * from address"])) +``` + +This produces a vector of hash maps, just like the result of `execute!`, where each "row" is datafiable and navigable. > Note: since `plan` expects you to process the result set via reduction, you should not use it for DDL or for SQL statements that only produce update counts. diff --git a/src/next/jdbc.clj b/src/next/jdbc.clj index 9d4a9d0..d3b3743 100644 --- a/src/next/jdbc.clj +++ b/src/next/jdbc.clj @@ -176,7 +176,24 @@ Returns a reducible that, when reduced, runs the SQL and yields the result. Can be called on a `PreparedStatement`, a `Connection`, or something that can - produce a `Connection` via a `DataSource`." + produce a `Connection` via a `DataSource`. + + Your reducing function can read columns by name (string or simple keyword) + from each row of the underlying `ResultSet` without realizing the row as + a Clojure hash map. `select-keys` can also be used without realizing the row. + Operations that imply an actual Clojure data structure (such as `assoc`, + `dissoc`, `seq`, `keys`, `vals`, etc) will realize the whole into a hash map + using the supplied `:builder-fn` (or `as-maps` by default). + + If your reducing function needs to produce a hash map without calling a + function that implicitly realizes the row, you can call: + + `(next.jdbc.result-set/datafiable-row row connectable opts)` + + passing in the current row (passed to the reducing function), a `connectable`, + and an `opts` hash map. These can be the same values that you passed to `plan` + (or they can be different, depending on how you want the row to be built, + and how you want any subsequent lazy navigation to be handled)." (^clojure.lang.IReduceInit [stmt] (p/-execute stmt [] {})) diff --git a/src/next/jdbc/result_set.clj b/src/next/jdbc/result_set.clj index 7fa08be..f557964 100644 --- a/src/next/jdbc/result_set.clj +++ b/src/next/jdbc/result_set.clj @@ -366,7 +366,7 @@ If `datafiable-row` is called when reducing the result set produced by `next.jdbc/plan`, the row is fully-realized from the `ResultSet` - first." + first, using the `:builder-fn` (or `as-maps` by default)." (datafiable-row [this connectable opts] "Produce a datafiable representation of a row from a `ResultSet`."))