next-jdbc/src/next/jdbc.clj

199 lines
8.4 KiB
Clojure
Raw Normal View History

2019-01-08 07:03:20 +00:00
;; copyright (c) 2018-2019 Sean Corfield, all rights reserved
2019-01-08 04:38:58 +00:00
2019-01-08 07:03:20 +00:00
(ns next.jdbc
2019-04-01 06:17:12 +00:00
"The public API of the next generation java.jdbc library.
2019-04-21 23:13:52 +00:00
The basic building blocks are the `java.sql`/`javax.sql` classes:
* `DataSource` -- something to get connections from,
* `Connection` -- an active connection to the database,
* `PreparedStatement` -- SQL and parameters combined, from a connection,
2019-04-18 20:19:59 +00:00
and the following functions and a macro:
* `plan` -- given a connectable and SQL + parameters or a statement,
2019-04-01 06:17:12 +00:00
return a reducible that, when reduced will execute the SQL and consume
2019-04-21 23:13:52 +00:00
the `ResultSet` produced,
* `execute!` -- given a connectable and SQL + parameters or a statement,
execute the SQL, consume the `ResultSet` produced, and return a vector
2019-04-18 20:19:59 +00:00
of hash maps representing the rows (@1); this can be datafied to allow
navigation of foreign keys into other tables (either by convention or
via a schema definition),
2019-04-21 23:13:52 +00:00
* `execute-one!` -- given a connectable and SQL + parameters or a statement,
execute the SQL, consume the first row of the `ResultSet` produced, and
2019-04-18 20:19:59 +00:00
return a hash map representing that row; this can be datafied to allow
2019-04-01 06:17:12 +00:00
navigation of foreign keys into other tables (either by convention or
2019-04-18 20:19:59 +00:00
via a schema definition),
2019-04-21 23:13:52 +00:00
* `prepare` -- given a `Connection` and SQL + parameters, construct a new
`PreparedStatement`; in general this should be used with `with-open`,
* `transact` -- the functional implementation of `with-transaction`,
* `with-transaction` -- execute a series of SQL operations within a transaction.
2019-04-01 06:17:12 +00:00
2019-04-18 20:19:59 +00:00
@1 result sets are built, by default, as vectors of hash maps, containing
qualified keywords as column names, but the row builder and result set
builder machinery is open and alternatives are provided to produce
unqualified keywords as column names, and to produce a vector the
2019-04-21 23:13:52 +00:00
column names followed by vectors of column values for each row, and
lower-case variants of each.
The following options are supported wherever a `PreparedStatement` is created:
* `:concurrency` -- `:read-only`, `:updatable`,
* `:cursors` -- `:close`, `:hold`
* `:fetch-size` -- the fetch size value,
* `:max-rows` -- the maximum number of rows to return,
* `:result-type` -- `:forward-only`, `:scroll-insensitive`, `:scroll-sensitive`,
* `:return-keys` -- either `true` or a vector of key names to return,
* `:timeout` -- the query timeout."
2019-03-31 23:54:34 +00:00
(:require [next.jdbc.connection] ; used to extend protocols
[next.jdbc.prepare] ; used to extend protocols
2019-03-31 23:54:34 +00:00
[next.jdbc.protocols :as p]
[next.jdbc.result-set] ; used to extend protocols
2019-04-01 01:22:04 +00:00
[next.jdbc.transaction])) ; used to extend protocols
2019-01-08 07:03:20 +00:00
(set! *warn-on-reflection* true)
2019-04-01 06:17:12 +00:00
(defn get-datasource
2019-04-21 23:13:52 +00:00
"Given some sort of specification of a database, return a `DataSource`.
2019-04-02 04:31:38 +00:00
A specification can be a JDBC URL string (which is passed to the JDBC
driver as-is), or a hash map. For the hash map, these keys are required:
2019-04-21 23:13:52 +00:00
* `:dbtype` -- a string indicating the type of the database
* `:dbname` -- a string indicating the name of the database to be used
2019-04-02 04:31:38 +00:00
The following optional keys are commonly used:
2019-04-21 23:13:52 +00:00
* `:user` -- the username to authenticate with
* `:password` -- the password to authenticate with
* `:host` -- the hostname or IP address of the database (default: `127.0.0.1`)
* `:port` -- the port for the database connection (the default is database-
2019-04-02 04:31:38 +00:00
specific -- see below)
2019-04-21 23:13:52 +00:00
* `:classname` -- if you need to override the default for the `:dbtype`
2019-04-02 04:31:38 +00:00
(or you want to use a database that next.jdbc does not know about!)
Any additional options provided will be passed to the JDBC driver's
2019-04-21 23:13:52 +00:00
`.getConnection` call as a `java.util.Properties` structure.
2019-04-02 04:31:38 +00:00
Database types supported, and their defaults:
2019-04-21 23:13:52 +00:00
* `derby` -- `org.apache.derby.jdbc.EmbeddedDriver` -- also pass `:create true`
2019-04-02 04:31:38 +00:00
if you want the database to be automatically created
2019-04-21 23:13:52 +00:00
* `h2` -- `org.h2.Driver` -- for an on-disk database
* `h2:mem` -- `org.h2.Driver` -- for an in-memory database
* `hsqldb`, `hsql` -- `org.hsqldb.jdbcDriver`
* `jtds:sqlserver`, `jtds` -- `net.sourceforge.jtds.jdbc.Driver` -- `1433`
* `mysql` -- `com.mysql.cj.jdbc.Driver`, `com.mysql.jdbc.Driver` -- `3306`
* `oracle:oci` -- `oracle.jdbc.OracleDriver` -- `1521`
* `oracle:thin`, `oracle` -- `oracle.jdbc.OracleDriver` -- `1521`
* `oracle:sid` -- `oracle.jdbc.OracleDriver` -- `1521` -- uses the legacy `:`
separator for the database name but otherwise behaves like `oracle:thin`
* `postgresql`, `postgres` -- `org.postgresql.Driver` -- `5432`
* `pgsql` -- `com.impossibl.postgres.jdbc.PGDriver` -- no default port
* `redshift` -- `com.amazon.redshift.jdbc.Driver` -- no default port
* `sqlite` -- `org.sqlite.JDBC`
* `sqlserver`, `mssql` -- `com.microsoft.sqlserver.jdbc.SQLServerDriver` -- `1433`"
2019-04-01 06:17:12 +00:00
[spec]
(p/get-datasource spec))
2019-04-01 06:17:12 +00:00
(defn get-connection
2019-04-21 23:13:52 +00:00
"Given some sort of specification of a database, return a new `Connection`.
2019-01-10 07:30:46 +00:00
2019-04-21 23:13:52 +00:00
In general, this should be used via `with-open`:
2019-04-01 06:17:12 +00:00
2019-04-21 23:13:52 +00:00
```clojure
2019-04-01 06:17:12 +00:00
(with-open [con (get-connection spec opts)]
2019-04-02 04:31:38 +00:00
(run-some-ops con))
2019-04-21 23:13:52 +00:00
```
2019-04-02 04:31:38 +00:00
2019-04-21 23:13:52 +00:00
If you call `get-connection` on a `DataSource`, it just calls `.getConnection`
and applies the `:auto-commit` and/or `:read-only` options, if provided.
2019-04-02 04:31:38 +00:00
2019-04-21 23:13:52 +00:00
If you call `get-connection` on anything else, it will call `get-datasource`
first to try to get a `DataSource`, and then call `get-connection` on that."
([spec]
(p/get-connection spec {}))
([spec opts]
(p/get-connection spec opts)))
2019-04-01 06:17:12 +00:00
(defn prepare
2019-04-02 04:31:38 +00:00
"Given a connection to a database, and a vector containing SQL and any
2019-04-21 23:13:52 +00:00
parameters it needs, return a new `PreparedStatement`.
2019-04-01 06:17:12 +00:00
2019-04-21 23:13:52 +00:00
In general, this should be used via `with-open`:
2019-04-01 06:17:12 +00:00
2019-04-21 23:13:52 +00:00
```clojure
2019-04-01 06:17:12 +00:00
(with-open [stmt (prepare spec sql-params opts)]
2019-04-02 04:31:38 +00:00
(run-some-ops stmt))
2019-04-21 23:13:52 +00:00
```
2019-04-02 04:31:38 +00:00
See the list of options above (in the namespace docstring) for what can
be passed to prepare."
([connection sql-params]
(p/prepare connection sql-params {}))
([connection sql-params opts]
(p/prepare connection sql-params opts)))
2019-01-08 07:03:20 +00:00
(defn plan
2019-03-31 03:36:53 +00:00
"General SQL execution function.
2019-04-02 04:31:38 +00:00
Returns a reducible that, when reduced, runs the SQL and yields the result.
2019-04-21 23:13:52 +00:00
Can be called on a `PreparedStatement`, a `Connection`, or something that can
produce a `Connection` via a `DataSource`."
([stmt]
(p/-execute stmt [] {}))
([connectable sql-params]
(p/-execute connectable sql-params
{:next.jdbc/sql-params sql-params}))
([connectable sql-params opts]
(p/-execute connectable sql-params
(assoc opts :next.jdbc/sql-params sql-params))))
2019-03-31 06:13:01 +00:00
(defn execute!
2019-04-01 06:17:12 +00:00
"General SQL execution function.
2019-04-21 23:13:52 +00:00
Returns a fully-realized result set.
2019-04-02 04:31:38 +00:00
2019-04-21 23:13:52 +00:00
Can be called on a `PreparedStatement`, a `Connection`, or something that can
produce a `Connection` via a `DataSource`."
2019-03-31 23:54:34 +00:00
([stmt]
(p/-execute-all stmt [] {}))
2019-03-31 23:54:34 +00:00
([connectable sql-params]
(p/-execute-all connectable sql-params
{:next.jdbc/sql-params sql-params}))
2019-03-31 06:13:01 +00:00
([connectable sql-params opts]
(p/-execute-all connectable sql-params
(assoc opts :next.jdbc/sql-params sql-params))))
2019-03-31 06:13:01 +00:00
(defn execute-one!
2019-04-01 06:17:12 +00:00
"General SQL execution function that returns just the first row of a result.
2019-04-21 23:13:52 +00:00
Can be called on a `PreparedStatement`, a `Connection`, or something that can
produce a `Connection` via a `DataSource`."
2019-03-31 23:54:34 +00:00
([stmt]
(p/-execute-one stmt [] {}))
2019-03-31 23:54:34 +00:00
([connectable sql-params]
(p/-execute-one connectable sql-params
{:next.jdbc/sql-params sql-params}))
2019-03-31 06:13:01 +00:00
([connectable sql-params opts]
(p/-execute-one connectable sql-params
(assoc opts :next.jdbc/sql-params sql-params))))
2019-03-31 23:54:34 +00:00
(defn transact
2019-04-21 23:13:52 +00:00
"Given a connectable object and a function (taking a `Connection`),
execute the function on a new connection in a transactional manner.
2019-04-18 20:19:59 +00:00
See `with-transaction` for supported options."
([connectable f]
(p/-transact connectable f {}))
2019-04-18 20:19:59 +00:00
([connectable f opts]
(p/-transact connectable f opts)))
2019-03-31 23:54:34 +00:00
(defmacro with-transaction
2019-04-21 23:13:52 +00:00
"Given a connectable object, gets a new connection and binds it to `sym`,
then executes the `body` in that context, committing any changes if the body
2019-04-01 06:17:12 +00:00
completes successfully, otherwise rolling back any changes made.
The options map supports:
2019-04-21 23:13:52 +00:00
* `:isolation` -- `:none`, `:read-committed`, `:read-uncommitted`,
`:repeatable-read`, `:serializable`,
* `:read-only` -- `true` / `false`,
* `:rollback-only` -- `true` / `false`."
2019-03-31 23:54:34 +00:00
[[sym connectable opts] & body]
`(transact ~connectable (^{:once true} fn* [~sym] ~@body) ~opts))