Alpha 9; fixes #14; improves protocol docstrings
* Move documentation from `ns` into `defprotocol` and the method declarations. * Indicate which protocols may be extended via metadata (`SettableParameter` and `Sourceable`).
This commit is contained in:
parent
a8897765fa
commit
2c018654d3
7 changed files with 95 additions and 81 deletions
|
|
@ -1,3 +1,4 @@
|
||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
2019-04-21 -- 1.0.0-alpha8 -- Initial publicly announced release.
|
* 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.
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,12 @@ It is designed to work with Clojure 1.10 or later, supports `datafy`/`nav`, and
|
||||||
You can add `next.jdbc` to your project with either:
|
You can add `next.jdbc` to your project with either:
|
||||||
|
|
||||||
```clojure
|
```clojure
|
||||||
{seancorfield/next.jdbc {:mvn/version "1.0.0-alpha8"}}
|
{seancorfield/next.jdbc {:mvn/version "1.0.0-alpha9"}}
|
||||||
```
|
```
|
||||||
for `deps.edn` or:
|
for `deps.edn` or:
|
||||||
|
|
||||||
```clojure
|
```clojure
|
||||||
[seancorfield/next.jdbc "1.0.0-alpha8"]
|
[seancorfield/next.jdbc "1.0.0-alpha9"]
|
||||||
```
|
```
|
||||||
for `project.clj` or `build.boot`.
|
for `project.clj` or `build.boot`.
|
||||||
|
|
||||||
|
|
@ -29,7 +29,7 @@ For the examples in this documentation, we will use a local H2 database on disk,
|
||||||
```clojure
|
```clojure
|
||||||
;; deps.edn
|
;; deps.edn
|
||||||
{:deps {org.clojure/clojure {:mvn/version "1.10.0"}
|
{:deps {org.clojure/clojure {:mvn/version "1.10.0"}
|
||||||
seancorfield/next.jdbc {:mvn/version "1.0.0-alpha8"}
|
seancorfield/next.jdbc {:mvn/version "1.0.0-alpha9"}
|
||||||
com.h2database/h2 {:mvn/version "1.4.197"}}}
|
com.h2database/h2 {:mvn/version "1.4.197"}}}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ This page attempts to list all of the differences between [clojure.java.jdbc](ht
|
||||||
|
|
||||||
## Conceptually
|
## Conceptually
|
||||||
|
|
||||||
`clojure.java.jdbc` focuses heavily on a `db-spec` hash map to describe the various ways of interacting with the database and grew from very imperative origins that expose a lot of the JDBC API (multiple type of SQL execution, some operations returned hash maps, others update counts as integers, etc).
|
`clojure.java.jdbc` focuses heavily on a `db-spec` hash map to describe the various ways of interacting with the database and grew from very imperative origins that expose a lot of the JDBC API (multiple types of SQL execution, some operations returned hash maps, others update counts as integers, etc).
|
||||||
|
|
||||||
`next.jdbc` focuses on using protocols and native Java JDBC types where possible (for performance and simplicity) and strives to present a more modern Clojure API with namespace-qualified keywords in hash maps, reducible SQL operations as part of the primary API, and a streamlined set of SQL execution primitives. Execution always returns a hash map (for one result) or a vector of hash maps (for multiple results) -- even update counts are returned as if they were result sets.
|
`next.jdbc` focuses on using protocols and native Java JDBC types where possible (for performance and simplicity) and strives to present a more modern Clojure API with namespace-qualified keywords in hash maps, reducible SQL operations as part of the primary API, and a streamlined set of SQL execution primitives. Execution always returns a hash map (for one result) or a vector of hash maps (for multiple results) -- even update counts are returned as if they were result sets.
|
||||||
|
|
||||||
|
|
|
||||||
2
pom.xml
2
pom.xml
|
|
@ -3,7 +3,7 @@
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>seancorfield</groupId>
|
<groupId>seancorfield</groupId>
|
||||||
<artifactId>next.jdbc</artifactId>
|
<artifactId>next.jdbc</artifactId>
|
||||||
<version>1.0.0-alpha8</version>
|
<version>1.0.0-alpha9</version>
|
||||||
<name>next.jdbc</name>
|
<name>next.jdbc</name>
|
||||||
|
|
||||||
<description>The next generation of clojure.java.jdbc: a new low-level Clojure wrapper for JDBC-based access to databases.</description>
|
<description>The next generation of clojure.java.jdbc: a new low-level Clojure wrapper for JDBC-based access to databases.</description>
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,9 @@
|
||||||
(defprotocol SettableParameter :extend-via-metadata true
|
(defprotocol SettableParameter :extend-via-metadata true
|
||||||
"Protocol for setting SQL parameters in statement objects, which
|
"Protocol for setting SQL parameters in statement objects, which
|
||||||
can convert from Clojure values. The default implementation just
|
can convert from Clojure values. The default implementation just
|
||||||
calls `.setObject` on the parameter value. It can be extended to use other
|
calls `.setObject` on the parameter value. It can be extended to
|
||||||
methods of `PreparedStatement` to convert and set parameter values."
|
use other methods of `PreparedStatement` to convert and set parameter
|
||||||
|
values. Extension via metadata is supported."
|
||||||
(set-parameter [val stmt ix]
|
(set-parameter [val stmt ix]
|
||||||
"Convert a Clojure value into a SQL value and store it as the ix'th
|
"Convert a Clojure value into a SQL value and store it as the ix'th
|
||||||
parameter in the given SQL statement object."))
|
parameter in the given SQL statement object."))
|
||||||
|
|
|
||||||
|
|
@ -3,59 +3,61 @@
|
||||||
(ns next.jdbc.protocols
|
(ns next.jdbc.protocols
|
||||||
"This is the extensible core of the next generation java.jdbc library.
|
"This is the extensible core of the next generation java.jdbc library.
|
||||||
|
|
||||||
`Sourceable` protocol:
|
`Sourceable` -- for producing `javax.sql.DataSource` objects,
|
||||||
`get-datasource` -- turn something into a `javax.sql.DataSource`; implementations
|
`Connectable` -- for producing new `java.sql.Connection` objects,
|
||||||
are provided for strings, hash maps (`db-spec` structures), and also a
|
`Executable` -- for executing SQL operations,
|
||||||
`DataSource` (which just returns itself).
|
`Preparable` -- for producing new `java.sql.PreparedStatement` objects,
|
||||||
|
`Transactable` -- for executing SQL operations transactionally.")
|
||||||
`Connectable` protocol:
|
|
||||||
`get-connection` -- create a new JDBC connection that should be closed when you
|
|
||||||
are finished with it; implementations are provided for `DataSource`,
|
|
||||||
`PreparedStatement`, and `Object`, on the assumption that an `Object`
|
|
||||||
can possibly be turned into a `DataSource`.
|
|
||||||
|
|
||||||
`Executable` protocol:
|
|
||||||
`-execute` -- given SQL and parameters, produce a 'reducible' that, when
|
|
||||||
reduced, executes the SQL and produces a `ResultSet` that can be processed;
|
|
||||||
implementations are provided for `Connection`, `DataSource`,
|
|
||||||
`PreparedStatement`, and `Object` (on the assumption that an `Object` can be
|
|
||||||
turned into a `DataSource` and therefore used to get a `Connection`).
|
|
||||||
|
|
||||||
`-execute-one` -- given SQL and parameters, executes the SQL and produces
|
|
||||||
the first row of the `ResultSet` as a datafiable hash map (by default);
|
|
||||||
implementations are provided for `Connection`, `DataSource`,
|
|
||||||
`PreparedStatement`, and `Object` (on the assumption that an `Object` can be
|
|
||||||
turned into a `DataSource` and therefore used to get a `Connection`).
|
|
||||||
|
|
||||||
`-execute-all` -- given SQL and parameters, executes the SQL and produces
|
|
||||||
either a vector of datafiable hash maps from the `ResultSet` (default)
|
|
||||||
or a vector of column names followed by vectors of row values;
|
|
||||||
implementations are provided for `Connection`, `DataSource`,
|
|
||||||
`PreparedStatement`, and `Object` (on the assumption that an `Object` can be
|
|
||||||
turned into a `DataSource` and therefore used to get a `Connection`).
|
|
||||||
|
|
||||||
`Preparable` protocol:
|
|
||||||
`prepare` -- given SQL and parameters, produce a `PreparedStatement` that can
|
|
||||||
be executed (by -execute above); implementation is provided for
|
|
||||||
`Connection` only.
|
|
||||||
|
|
||||||
`Transactable` protocol:
|
|
||||||
`-transact` -- given a function (presumably containing SQL operations),
|
|
||||||
run the function inside a SQL transaction; implementations are provided
|
|
||||||
for `Connection`, `DataSource`, and `Object` (on the assumption that an
|
|
||||||
`Object` can be turned into a `DataSource`).")
|
|
||||||
|
|
||||||
(set! *warn-on-reflection* true)
|
(set! *warn-on-reflection* true)
|
||||||
|
|
||||||
(defprotocol Sourceable :extend-via-metadata true
|
(defprotocol Sourceable :extend-via-metadata true
|
||||||
(get-datasource ^javax.sql.DataSource [this]))
|
"Protocol for producing a `javax.sql.DataSource`.
|
||||||
|
|
||||||
|
Implementations are provided for strings, hash maps (`db-spec` structures),
|
||||||
|
and also a `DataSource` (which just returns itself).
|
||||||
|
|
||||||
|
Extension via metadata is supported."
|
||||||
|
(get-datasource ^javax.sql.DataSource [this]
|
||||||
|
"Produce a `javax.sql.DataSource`."))
|
||||||
|
|
||||||
(defprotocol Connectable
|
(defprotocol Connectable
|
||||||
(get-connection ^java.lang.AutoCloseable [this opts]))
|
"Protocol for producing a new JDBC connection that should be closed when you
|
||||||
|
are finished with it.
|
||||||
|
|
||||||
|
Implementations are provided for `DataSource`, `PreparedStatement`, and
|
||||||
|
`Object`, on the assumption that an `Object` can be turned into a `DataSource`."
|
||||||
|
(get-connection ^java.lang.AutoCloseable [this opts]
|
||||||
|
"Produce a new `java.sql.Connection` for use with `with-open`."))
|
||||||
|
|
||||||
(defprotocol Executable
|
(defprotocol Executable
|
||||||
(-execute ^clojure.lang.IReduceInit [this sql-params opts])
|
"Protocol for executing SQL operations.
|
||||||
(-execute-one [this sql-params opts])
|
|
||||||
(-execute-all [this sql-params opts]))
|
Implementations are provided for `Connection`, `DataSource`,
|
||||||
|
`PreparedStatement`, and `Object`, on the assumption that an `Object` can be
|
||||||
|
turned into a `DataSource` and therefore used to get a `Connection`."
|
||||||
|
(-execute ^clojure.lang.IReduceInit [this sql-params opts]
|
||||||
|
"Produce a 'reducible' that, when reduced, executes the SQL and
|
||||||
|
processes the rows of the `ResultSet` directly.")
|
||||||
|
(-execute-one [this sql-params opts]
|
||||||
|
"Executes the SQL and produces the first row of the `ResultSet`
|
||||||
|
as a fully-realized, datafiable hash map (by default).")
|
||||||
|
(-execute-all [this sql-params opts]
|
||||||
|
"Executes the SQL and produces (by default) a vector of
|
||||||
|
fully-realized, datafiable hash maps from the `ResultSet`."))
|
||||||
|
|
||||||
(defprotocol Preparable
|
(defprotocol Preparable
|
||||||
(prepare ^java.sql.PreparedStatement [this sql-params opts]))
|
"Protocol for producing a new `java.sql.PreparedStatement` that should
|
||||||
|
be closed after use. Can be used by `Executable` functions.
|
||||||
|
|
||||||
|
Implementation is provided for `Connection` only."
|
||||||
|
(prepare ^java.sql.PreparedStatement [this sql-params opts]
|
||||||
|
"Produce a new `java.sql.PreparedStatement` for use with `with-open`."))
|
||||||
|
|
||||||
(defprotocol Transactable
|
(defprotocol Transactable
|
||||||
(-transact [this body-fn opts]))
|
"Protocol for running SQL operations in a transaction.
|
||||||
|
|
||||||
|
Implementations are provided for `Connection`, `DataSource`, and `Object`
|
||||||
|
(on the assumption that an `Object` can be turned into a `DataSource`)."
|
||||||
|
(-transact [this body-fn opts]
|
||||||
|
"Run the `body-fn` inside a transaction."))
|
||||||
|
|
|
||||||
|
|
@ -76,30 +76,30 @@
|
||||||
(read-column-by-index [_1 _2 _3] nil))
|
(read-column-by-index [_1 _2 _3] nil))
|
||||||
|
|
||||||
(defprotocol RowBuilder
|
(defprotocol RowBuilder
|
||||||
"Protocol for building rows in various representations:
|
"Protocol for building rows in various representations.
|
||||||
`->row` -- called once per row to create the basis of each row
|
|
||||||
`column-count` -- return the number of columns in each row
|
|
||||||
`with-column` -- called with the row and the index of the column to be added;
|
|
||||||
this is expected to read the column value from the `ResultSet`!
|
|
||||||
`row!` -- called once per row to finalize each row once it is complete
|
|
||||||
|
|
||||||
The default implementation for building hash maps: `MapResultSetBuilder`"
|
The default implementation for building hash maps: `MapResultSetBuilder`"
|
||||||
(->row [_])
|
(->row [_]
|
||||||
(column-count [_])
|
"Called once per row to create the basis of each row.")
|
||||||
(with-column [_ row i])
|
(column-count [_]
|
||||||
(row! [_ row]))
|
"Return the number of columns in each row.")
|
||||||
|
(with-column [_ row i]
|
||||||
|
"Called with the row and the index of the column to be added;
|
||||||
|
this is expected to read the column value from the `ResultSet`!")
|
||||||
|
(row! [_ row]
|
||||||
|
"Called once per row to finalize each row once it is complete."))
|
||||||
|
|
||||||
(defprotocol ResultSetBuilder
|
(defprotocol ResultSetBuilder
|
||||||
"Protocol for building result sets in various representations:
|
"Protocol for building result sets in various representations.
|
||||||
`->rs` -- called to create the basis of the result set
|
|
||||||
`with-row` -- called with the result set and the row to be added
|
|
||||||
`rs!` -- called to finalize the result set once it is complete
|
|
||||||
|
|
||||||
Default implementations for building vectors of hash maps and vectors
|
Default implementations for building vectors of hash maps and vectors of
|
||||||
of column names and row values: `MapResultSetBuilder` & `ArrayResultSetBuilder`"
|
column names and row values: `MapResultSetBuilder` & `ArrayResultSetBuilder`"
|
||||||
(->rs [_])
|
(->rs [_]
|
||||||
(with-row [_ rs row])
|
"Called to create the basis of the result set.")
|
||||||
(rs! [_ rs]))
|
(with-row [_ rs row]
|
||||||
|
"Called with the result set and the row to be added.")
|
||||||
|
(rs! [_ rs]
|
||||||
|
"Called to finalize the result set once it is complete."))
|
||||||
|
|
||||||
(defrecord MapResultSetBuilder [^ResultSet rs rsmeta cols]
|
(defrecord MapResultSetBuilder [^ResultSet rs rsmeta cols]
|
||||||
RowBuilder
|
RowBuilder
|
||||||
|
|
@ -199,9 +199,17 @@
|
||||||
(declare navize-row)
|
(declare navize-row)
|
||||||
|
|
||||||
(defprotocol DatafiableRow
|
(defprotocol DatafiableRow
|
||||||
"Given a connectable object, return a function that knows how to turn a row
|
"Protocol for making rows datafiable and therefore navigable.
|
||||||
into a datafiable object that can be `nav`igated."
|
|
||||||
(datafiable-row [this connectable opts]))
|
The default implementation just adds metadata so that `datafy` can be
|
||||||
|
called on the row, which will produce something that `nav` can be called
|
||||||
|
on, to lazily navigate through foreign key relationships into other tables.
|
||||||
|
|
||||||
|
If `datafiable-row` is called when reducing the result set produced by
|
||||||
|
`next.jdbc/reducible!`, the row is fully-realized from the `ResultSet`
|
||||||
|
first."
|
||||||
|
(datafiable-row [this connectable opts]
|
||||||
|
"Produce a datafiable representation of a row from a `ResultSet`."))
|
||||||
|
|
||||||
(defn- row-builder
|
(defn- row-builder
|
||||||
"Given a `RowBuilder` -- a row materialization strategy -- produce a fully
|
"Given a `RowBuilder` -- a row materialization strategy -- produce a fully
|
||||||
|
|
@ -396,9 +404,11 @@
|
||||||
(reduce-stmt this f init (assoc opts :return-keys true)))))
|
(reduce-stmt this f init (assoc opts :return-keys true)))))
|
||||||
(-execute-one [this _ opts]
|
(-execute-one [this _ opts]
|
||||||
(if-let [rs (stmt->result-set this (assoc opts :return-keys true))]
|
(if-let [rs (stmt->result-set this (assoc opts :return-keys true))]
|
||||||
(when (.next rs)
|
(let [gen-fn (get opts :gen-fn as-maps)
|
||||||
(datafiable-row (row-builder (as-maps rs opts))
|
gen (gen-fn rs opts)]
|
||||||
(.getConnection this) opts))
|
(when (.next rs)
|
||||||
|
(datafiable-row (row-builder gen)
|
||||||
|
(.getConnection this) opts)))
|
||||||
{:next.jdbc/update-count (.getUpdateCount this)}))
|
{:next.jdbc/update-count (.getUpdateCount this)}))
|
||||||
(-execute-all [this _ opts]
|
(-execute-all [this _ opts]
|
||||||
(if-let [rs (stmt->result-set this opts)]
|
(if-let [rs (stmt->result-set this opts)]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue