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
|
||||
|
||||
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:
|
||||
|
||||
```clojure
|
||||
{seancorfield/next.jdbc {:mvn/version "1.0.0-alpha8"}}
|
||||
{seancorfield/next.jdbc {:mvn/version "1.0.0-alpha9"}}
|
||||
```
|
||||
for `deps.edn` or:
|
||||
|
||||
```clojure
|
||||
[seancorfield/next.jdbc "1.0.0-alpha8"]
|
||||
[seancorfield/next.jdbc "1.0.0-alpha9"]
|
||||
```
|
||||
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
|
||||
;; deps.edn
|
||||
{: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"}}}
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ This page attempts to list all of the differences between [clojure.java.jdbc](ht
|
|||
|
||||
## 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.
|
||||
|
||||
|
|
|
|||
2
pom.xml
2
pom.xml
|
|
@ -3,7 +3,7 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>seancorfield</groupId>
|
||||
<artifactId>next.jdbc</artifactId>
|
||||
<version>1.0.0-alpha8</version>
|
||||
<version>1.0.0-alpha9</version>
|
||||
<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>
|
||||
|
|
|
|||
|
|
@ -20,8 +20,9 @@
|
|||
(defprotocol SettableParameter :extend-via-metadata true
|
||||
"Protocol for setting SQL parameters in statement objects, which
|
||||
can convert from Clojure values. The default implementation just
|
||||
calls `.setObject` on the parameter value. It can be extended to use other
|
||||
methods of `PreparedStatement` to convert and set parameter values."
|
||||
calls `.setObject` on the parameter value. It can be extended to
|
||||
use other methods of `PreparedStatement` to convert and set parameter
|
||||
values. Extension via metadata is supported."
|
||||
(set-parameter [val stmt ix]
|
||||
"Convert a Clojure value into a SQL value and store it as the ix'th
|
||||
parameter in the given SQL statement object."))
|
||||
|
|
|
|||
|
|
@ -3,59 +3,61 @@
|
|||
(ns next.jdbc.protocols
|
||||
"This is the extensible core of the next generation java.jdbc library.
|
||||
|
||||
`Sourceable` protocol:
|
||||
`get-datasource` -- turn something into a `javax.sql.DataSource`; implementations
|
||||
are provided for strings, hash maps (`db-spec` structures), and also a
|
||||
`DataSource` (which just returns itself).
|
||||
|
||||
`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`).")
|
||||
`Sourceable` -- for producing `javax.sql.DataSource` objects,
|
||||
`Connectable` -- for producing new `java.sql.Connection` objects,
|
||||
`Executable` -- for executing SQL operations,
|
||||
`Preparable` -- for producing new `java.sql.PreparedStatement` objects,
|
||||
`Transactable` -- for executing SQL operations transactionally.")
|
||||
|
||||
(set! *warn-on-reflection* 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
|
||||
(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
|
||||
(-execute ^clojure.lang.IReduceInit [this sql-params opts])
|
||||
(-execute-one [this sql-params opts])
|
||||
(-execute-all [this sql-params opts]))
|
||||
"Protocol for executing SQL operations.
|
||||
|
||||
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
|
||||
(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
|
||||
(-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))
|
||||
|
||||
(defprotocol RowBuilder
|
||||
"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
|
||||
"Protocol for building rows in various representations.
|
||||
|
||||
The default implementation for building hash maps: `MapResultSetBuilder`"
|
||||
(->row [_])
|
||||
(column-count [_])
|
||||
(with-column [_ row i])
|
||||
(row! [_ row]))
|
||||
(->row [_]
|
||||
"Called once per row to create the basis of each row.")
|
||||
(column-count [_]
|
||||
"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
|
||||
"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
|
||||
"Protocol for building result sets in various representations.
|
||||
|
||||
Default implementations for building vectors of hash maps and vectors
|
||||
of column names and row values: `MapResultSetBuilder` & `ArrayResultSetBuilder`"
|
||||
(->rs [_])
|
||||
(with-row [_ rs row])
|
||||
(rs! [_ rs]))
|
||||
Default implementations for building vectors of hash maps and vectors of
|
||||
column names and row values: `MapResultSetBuilder` & `ArrayResultSetBuilder`"
|
||||
(->rs [_]
|
||||
"Called to create the basis of the result set.")
|
||||
(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]
|
||||
RowBuilder
|
||||
|
|
@ -199,9 +199,17 @@
|
|||
(declare navize-row)
|
||||
|
||||
(defprotocol DatafiableRow
|
||||
"Given a connectable object, return a function that knows how to turn a row
|
||||
into a datafiable object that can be `nav`igated."
|
||||
(datafiable-row [this connectable opts]))
|
||||
"Protocol for making rows datafiable and therefore navigable.
|
||||
|
||||
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
|
||||
"Given a `RowBuilder` -- a row materialization strategy -- produce a fully
|
||||
|
|
@ -396,9 +404,11 @@
|
|||
(reduce-stmt this f init (assoc opts :return-keys true)))))
|
||||
(-execute-one [this _ opts]
|
||||
(if-let [rs (stmt->result-set this (assoc opts :return-keys true))]
|
||||
(let [gen-fn (get opts :gen-fn as-maps)
|
||||
gen (gen-fn rs opts)]
|
||||
(when (.next rs)
|
||||
(datafiable-row (row-builder (as-maps rs opts))
|
||||
(.getConnection this) opts))
|
||||
(datafiable-row (row-builder gen)
|
||||
(.getConnection this) opts)))
|
||||
{:next.jdbc/update-count (.getUpdateCount this)}))
|
||||
(-execute-all [this _ opts]
|
||||
(if-let [rs (stmt->result-set this opts)]
|
||||
|
|
|
|||
Loading…
Reference in a new issue