From 13ad9178646379fc3cb16f7b28243a1f6320a4df Mon Sep 17 00:00:00 2001 From: Sean Corfield Date: Wed, 24 Apr 2019 10:07:52 -0700 Subject: [PATCH] Fix #15 by passing SQL string to builders Adds internal `:next.jdbc/sql-string` option. --- CHANGELOG.md | 6 ++++++ doc/result-set-builders.md | 8 +++++++- src/next/jdbc.clj | 18 ++++++++++++------ 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dcd5c62..4e1c2fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,3 +2,9 @@ * 2019-04-22 -- 1.0.0-alpha9 -- Fix #14 by respecting `:gen-fn` in `execute-one` for `PreparedStatement`. * 2019-04-21 -- 1.0.0-alpha8 -- Initial publicly announced release. + +## Unreleased Changes + +The following changes have been committed to the **master** branch and will be in the next release: + +* Fix #15 by adding `:next.jdbc/sql-string` to options hash map that is passed down into the builder function. diff --git a/doc/result-set-builders.md b/doc/result-set-builders.md index a677f8b..1b8b0cf 100644 --- a/doc/result-set-builders.md +++ b/doc/result-set-builders.md @@ -24,6 +24,8 @@ This protocol defines four functions and is used whenever `next.jdbc` needs to m * `(with-column builder row i)` -- given the row so far, fetches column `i` from the current row of the `ResultSet`, converts it to a Clojure value, and adds it to the row (for `as-maps` this is a call to `.getObject`, a call to `read-column-by-index` -- see the `ReadableColumn` protocol below, and a call to `assoc!`), * `(row! builder row)` -- completes the row (a `(persistent! row)` call by default). +`execute!` and `execute-one!` call these functions for each row they need to build. `reducible!` _may_ call these functions if the reducing function causes a row to be materialized. + ## ResultSet Protocol This protocol defines three functions and is used whenever `next.jdbc` needs to materialize a result set (multiple rows) from a `ResultSet` as a Clojure data structure: @@ -32,12 +34,16 @@ This protocol defines three functions and is used whenever `next.jdbc` needs to * `(with-row builder rs row)` -- given the result set so far and a new row, returns the updated result set (a `(conj! rs row)` call by default), * `(rs! builder rs)` -- completes the result set (a `(persistent! rs)` call by default). +Only `execute!` expects this protocol to be implemented. `execute-one!` and `reducible!` do not call these functions. + ## Result Set Builder Functions -The `as-*` functions described above are all implemented in terms of these protocols. They are passed the `ResultSet` object and the options hash map (as passed into various `next.jdbc` functions). They return an implementation of the protocols that is then used to build rows and the result set. Note that the `ResultSet` passed in is _mutable_ and is advanced from row to row by the SQL execution function, so each time `->row` is called, the underlying `ResultSet` object points at each new row in turn. By contrast, `->rs` (which is only called by `execute-all!`) is invoked _before_ the `ResultSet` is advanced to the first row. +The `as-*` functions described above are all implemented in terms of these protocols. They are passed the `ResultSet` object and the options hash map (as passed into various `next.jdbc` functions). They return an implementation of the protocols that is then used to build rows and the result set. Note that the `ResultSet` passed in is _mutable_ and is advanced from row to row by the SQL execution function, so each time `->row` is called, the underlying `ResultSet` object points at each new row in turn. By contrast, `->rs` (which is only called by `execute!`) is invoked _before_ the `ResultSet` is advanced to the first row. The options hash map for any `next.jdbc` function can contain a `:gen-fn` key and the value is used at the row/result set builder function. The tests for `next.jdbc.result-set` include a [record-based builder function](https://github.com/seancorfield/next-jdbc/blob/master/test/next/jdbc/result_set_test.clj#L148-L164) as an example of how you can extend this to satisfy your needs. +The options hash map passed to the builder function will contain a `:next.jdbc/sql-string` key, whose value is the SQL string passed into the + # ReadableColumn As mentioned above, when `with-column` is called, the expectation is that the row builder will call `.getObject` on the current state of the `ResultSet` object with the column index and will then call `read-column-by-index`, passing the column value, the `ResultSetMetaData`, and the column index. That function is part of the `ReadableColumn` protocol that you can extend to handle conversion of arbitrary database-specific types to Clojure values. diff --git a/src/next/jdbc.clj b/src/next/jdbc.clj index cecce2f..9a4b133 100644 --- a/src/next/jdbc.clj +++ b/src/next/jdbc.clj @@ -138,9 +138,11 @@ ([stmt] (p/-execute stmt [] {})) ([connectable sql-params] - (p/-execute connectable sql-params {})) + (p/-execute connectable sql-params + {:next.jdbc/sql-string (first sql-params)})) ([connectable sql-params opts] - (p/-execute connectable sql-params opts))) + (p/-execute connectable sql-params + (assoc opts :next.jdbc/sql-string (first sql-params))))) (defn execute! "General SQL execution function. @@ -152,9 +154,11 @@ ([stmt] (p/-execute-all stmt [] {})) ([connectable sql-params] - (p/-execute-all connectable sql-params {})) + (p/-execute-all connectable sql-params + {:next.jdbc/sql-string (first sql-params)})) ([connectable sql-params opts] - (p/-execute-all connectable sql-params opts))) + (p/-execute-all connectable sql-params + (assoc opts :next.jdbc/sql-string (first sql-params))))) (defn execute-one! "General SQL execution function that returns just the first row of a result. @@ -164,9 +168,11 @@ ([stmt] (p/-execute-one stmt [] {})) ([connectable sql-params] - (p/-execute-one connectable sql-params {})) + (p/-execute-one connectable sql-params + {:next.jdbc/sql-string (first sql-params)})) ([connectable sql-params opts] - (p/-execute-one connectable sql-params opts))) + (p/-execute-one connectable sql-params + (assoc opts :next.jdbc/sql-string (first sql-params))))) (defn transact "Given a connectable object and a function (taking a `Connection`),